Code reformat.

This commit is contained in:
2019-11-25 00:54:38 +00:00
parent a5c650440d
commit d864bfab6c
116 changed files with 16544 additions and 19331 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -66,8 +66,8 @@ namespace DiscImageChef.Decoders.ATA
public ushort LbaLow;
public ushort LbaMid;
public ushort LbaHigh;
public byte DeviceHead;
public byte Command;
public byte DeviceHead;
public byte Command;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
@@ -97,12 +97,12 @@ namespace DiscImageChef.Decoders.ATA
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct AtaErrorRegistersLba48
{
public byte Status;
public byte Error;
public byte Status;
public byte Error;
public ushort SectorCount;
public ushort LbaLow;
public ushort LbaMid;
public ushort LbaHigh;
public byte DeviceHead;
public byte DeviceHead;
}
}

View File

@@ -38,44 +38,45 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.Bluray
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class BCA
{
#region Public structures
public struct BurstCuttingArea
{
/// <summary>Bytes 0 to 1 Always 66</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Byte 4 to 67 BCA data</summary>
public byte[] BCA;
}
#endregion Public structures
#region Public methods
public static BurstCuttingArea? Decode(byte[] BCAResponse)
{
if(BCAResponse == null) return null;
if(BCAResponse == null)
return null;
if(BCAResponse.Length != 68)
{
DicConsole.DebugWriteLine("BD BCA decoder", "Found incorrect Blu-ray BCA size ({0} bytes)",
BCAResponse.Length);
return null;
}
BurstCuttingArea decoded = new BurstCuttingArea
var decoded = new BurstCuttingArea
{
DataLength = BigEndianBitConverter.ToUInt16(BCAResponse, 0),
Reserved1 = BCAResponse[2],
Reserved2 = BCAResponse[3],
BCA = new byte[64]
DataLength = BigEndianBitConverter.ToUInt16(BCAResponse, 0), Reserved1 = BCAResponse[2],
Reserved2 = BCAResponse[3], BCA = new byte[64]
};
Array.Copy(BCAResponse, 4, decoded.BCA, 0, 64);
@@ -85,16 +86,20 @@ namespace DiscImageChef.Decoders.Bluray
public static string Prettify(BurstCuttingArea? BCAResponse)
{
if(BCAResponse == null) return null;
if(BCAResponse == null)
return null;
BurstCuttingArea response = BCAResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
sb.AppendFormat("Blu-ray Burst Cutting Area in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.BCA, 80));
@@ -104,31 +109,5 @@ namespace DiscImageChef.Decoders.Bluray
public static string Prettify(byte[] BCAResponse) => Prettify(Decode(BCAResponse));
#endregion Public methods
#region Public structures
public struct BurstCuttingArea
{
/// <summary>
/// Bytes 0 to 1
/// Always 66
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Byte 4 to 67
/// BCA data
/// </summary>
public byte[] BCA;
}
#endregion Public structures
}
}

View File

@@ -38,53 +38,72 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.Bluray
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "UnassignedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global"),
SuppressMessage("ReSharper", "UnassignedField.Global")]
public static class Cartridge
{
#region Public structures
public struct CartridgeStatus
{
/// <summary>Bytes 0 to 1 Always 6</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Byte 4, bit 7 Medium is inserted in a cartridge</summary>
public bool Cartridge;
/// <summary>Byte 4, bit 6 Medium taken out / put in a cartridge</summary>
public bool OUT;
/// <summary>Byte 4, bits 5 to 3 Reserved</summary>
public byte Reserved3;
/// <summary>Byte 4, bit 2 Cartridge sets write protection</summary>
public bool CWP;
/// <summary>Byte 4, bits 1 to 0 Reserved</summary>
public byte Reserved4;
/// <summary>Byte 5 Reserved</summary>
public byte Reserved5;
/// <summary>Byte 6 Reserved</summary>
public byte Reserved6;
/// <summary>Byte 7 Reserved</summary>
public byte Reserved7;
}
#endregion Public structures
#region Public methods
public static CartridgeStatus? Decode(byte[] CSResponse)
{
if(CSResponse == null) return null;
if(CSResponse == null)
return null;
if(CSResponse.Length != 8)
{
DicConsole.DebugWriteLine("BD Cartridge Status decoder",
"Found incorrect Blu-ray Cartridge Status size ({0} bytes)",
CSResponse.Length);
return null;
}
CartridgeStatus decoded = new CartridgeStatus
var decoded = new CartridgeStatus
{
DataLength = BigEndianBitConverter.ToUInt16(CSResponse, 0),
Reserved1 = CSResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(CSResponse, 0), Reserved1 = CSResponse[2],
Reserved2 = CSResponse[3],
Cartridge = Convert.ToBoolean(CSResponse[4] & 0x80),
OUT = Convert.ToBoolean(CSResponse[4] & 0x40),
Reserved3 = (byte)((CSResponse[4] & 0x38) >> 3),
CWP = Convert.ToBoolean(CSResponse[4] & 0x04),
Reserved4 = (byte)(CSResponse[4] & 0x03),
Reserved5 = CSResponse[5],
Reserved6 = CSResponse[6],
Reserved7 = CSResponse[7]
OUT =
Convert.ToBoolean(CSResponse[4] & 0x40),
Reserved3 = (byte)((CSResponse[4] & 0x38) >> 3),
CWP =
Convert.ToBoolean(CSResponse[4] & 0x04),
Reserved4 = (byte)(CSResponse[4] & 0x03),
Reserved5 = CSResponse[5],
Reserved6 =
CSResponse[6],
Reserved7 = CSResponse[7]
};
return decoded;
@@ -92,36 +111,57 @@ namespace DiscImageChef.Decoders.Bluray
public static string Prettify(CartridgeStatus? CSResponse)
{
if(CSResponse == null) return null;
if(CSResponse == null)
return null;
CartridgeStatus response = CSResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0) sb.AppendFormat("Reserved3 = 0x{0:X8}", response.Reserved3).AppendLine();
if(response.Reserved4 != 0) sb.AppendFormat("Reserved4 = 0x{0:X8}", response.Reserved4).AppendLine();
if(response.Reserved5 != 0) sb.AppendFormat("Reserved5 = 0x{0:X8}", response.Reserved5).AppendLine();
if(response.Reserved6 != 0) sb.AppendFormat("Reserved6 = 0x{0:X8}", response.Reserved6).AppendLine();
if(response.Reserved7 != 0) sb.AppendFormat("Reserved7 = 0x{0:X8}", response.Reserved7).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0)
sb.AppendFormat("Reserved3 = 0x{0:X8}", response.Reserved3).AppendLine();
if(response.Reserved4 != 0)
sb.AppendFormat("Reserved4 = 0x{0:X8}", response.Reserved4).AppendLine();
if(response.Reserved5 != 0)
sb.AppendFormat("Reserved5 = 0x{0:X8}", response.Reserved5).AppendLine();
if(response.Reserved6 != 0)
sb.AppendFormat("Reserved6 = 0x{0:X8}", response.Reserved6).AppendLine();
if(response.Reserved7 != 0)
sb.AppendFormat("Reserved7 = 0x{0:X8}", response.Reserved7).AppendLine();
#endif
if(response.Cartridge)
{
sb.AppendLine("Media is inserted in a cartridge");
if(response.OUT) sb.AppendLine("Media has been taken out, or inserted in, the cartridge");
if(response.CWP) sb.AppendLine("Media is write protected");
if(response.OUT)
sb.AppendLine("Media has been taken out, or inserted in, the cartridge");
if(response.CWP)
sb.AppendLine("Media is write protected");
}
else
{
sb.AppendLine("Media is not in a cartridge");
#if DEBUG
if(response.OUT) sb.AppendLine("Media has out bit marked, shouldn't");
if(response.CWP) sb.AppendLine("Media has write protection bit marked, shouldn't");
#endif
#if DEBUG
if(response.OUT)
sb.AppendLine("Media has out bit marked, shouldn't");
if(response.CWP)
sb.AppendLine("Media has write protection bit marked, shouldn't");
#endif
}
return sb.ToString();
@@ -129,66 +169,5 @@ namespace DiscImageChef.Decoders.Bluray
public static string Prettify(byte[] CSResponse) => Prettify(Decode(CSResponse));
#endregion Public methods
#region Public structures
public struct CartridgeStatus
{
/// <summary>
/// Bytes 0 to 1
/// Always 6
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Byte 4, bit 7
/// Medium is inserted in a cartridge
/// </summary>
public bool Cartridge;
/// <summary>
/// Byte 4, bit 6
/// Medium taken out / put in a cartridge
/// </summary>
public bool OUT;
/// <summary>
/// Byte 4, bits 5 to 3
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Byte 4, bit 2
/// Cartridge sets write protection
/// </summary>
public bool CWP;
/// <summary>
/// Byte 4, bits 1 to 0
/// Reserved
/// </summary>
public byte Reserved4;
/// <summary>
/// Byte 5
/// Reserved
/// </summary>
public byte Reserved5;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
public byte Reserved6;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
public byte Reserved7;
}
#endregion Public structures
}
}

View File

@@ -38,42 +38,84 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.Bluray
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class DDS
{
#region Private constants
/// <summary>
/// Disc Definition Structure Identifier "DS"
/// </summary>
/// <summary>Disc Definition Structure Identifier "DS"</summary>
const ushort DDSIdentifier = 0x4453;
#endregion Private constants
#region Public structures
public struct DiscDefinitionStructure
{
/// <summary>Bytes 0 to 1 Data Length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 5 "DS"</summary>
public ushort Signature;
/// <summary>Byte 6 DDS format</summary>
public byte Format;
/// <summary>Byte 7 Reserved</summary>
public byte Reserved3;
/// <summary>Bytes 8 to 11 DDS update count</summary>
public uint UpdateCount;
/// <summary>Bytes 12 to 19 Reserved</summary>
public ulong Reserved4;
/// <summary>Bytes 20 to 23 First PSN of Drive Area</summary>
public uint DriveAreaPSN;
/// <summary>Bytes 24 to 27 Reserved</summary>
public uint Reserved5;
/// <summary>Bytes 28 to 31 First PSN of Defect List</summary>
public uint DefectListPSN;
/// <summary>Bytes 32 to 35 Reserved</summary>
public uint Reserved6;
/// <summary>Bytes 36 to 39 PSN of LSN 0 of user data area</summary>
public uint PSNofLSNZero;
/// <summary>Bytes 40 to 43 Last LSN of user data area</summary>
public uint LastUserAreaLSN;
/// <summary>Bytes 44 to 47 ISA0 size</summary>
public uint ISA0;
/// <summary>Bytes 48 to 51 OSA size</summary>
public uint OSA;
/// <summary>Bytes 52 to 55 ISA1 size</summary>
public uint ISA1;
/// <summary>Byte 56 Spare Area full flags</summary>
public byte SpareAreaFullFlags;
/// <summary>Byte 57 Reserved</summary>
public byte Reserved7;
/// <summary>Byte 58 Disc type specific field</summary>
public byte DiscTypeSpecificField1;
/// <summary>Byte 59 Reserved</summary>
public byte Reserved8;
/// <summary>Byte 60 to 63 Disc type specific field</summary>
public uint DiscTypeSpecificField2;
/// <summary>Byte 64 to 67 Reserved</summary>
public uint Reserved9;
/// <summary>Bytes 68 to 99 Status bits of INFO1/2 and PAC1/2 on L0 and L1</summary>
public byte[] StatusBits;
/// <summary>Bytes 100 to end Disc type specific data</summary>
public byte[] DiscTypeSpecificData;
}
#endregion Public structures
#region Public methods
public static DiscDefinitionStructure? Decode(byte[] DDSResponse)
{
if(DDSResponse == null) return null;
if(DDSResponse == null)
return null;
DiscDefinitionStructure decoded = new DiscDefinitionStructure
var decoded = new DiscDefinitionStructure
{
DataLength = BigEndianBitConverter.ToUInt16(DDSResponse, 0),
Reserved1 = DDSResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(DDSResponse, 0), Reserved1 = DDSResponse[2],
Reserved2 = DDSResponse[3],
Signature = BigEndianBitConverter.ToUInt16(DDSResponse, 4)
};
@@ -82,6 +124,7 @@ namespace DiscImageChef.Decoders.Bluray
{
DicConsole.DebugWriteLine("BD DDS decoder", "Found incorrect DDS signature (0x{0:X4})",
decoded.Signature);
return null;
}
@@ -114,11 +157,12 @@ namespace DiscImageChef.Decoders.Bluray
public static string Prettify(DiscDefinitionStructure? DDSResponse)
{
if(DDSResponse == null) return null;
if(DDSResponse == null)
return null;
DiscDefinitionStructure response = DDSResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendFormat("DDS Format: 0x{0:X2}", response.Format).AppendLine();
sb.AppendFormat("DDS has ben updated {0} times", response.UpdateCount).AppendLine();
@@ -137,153 +181,39 @@ namespace DiscImageChef.Decoders.Bluray
sb.AppendFormat("Blu-ray DDS Disc Type Specific Data in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.DiscTypeSpecificData, 80));
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0) sb.AppendFormat("Reserved3 = 0x{0:X2}", response.Reserved3).AppendLine();
if(response.Reserved4 != 0) sb.AppendFormat("Reserved4 = 0x{0:X16}", response.Reserved4).AppendLine();
if(response.Reserved5 != 0) sb.AppendFormat("Reserved5 = 0x{0:X8}", response.Reserved5).AppendLine();
if(response.Reserved6 != 0) sb.AppendFormat("Reserved6 = 0x{0:X8}", response.Reserved6).AppendLine();
if(response.Reserved7 != 0) sb.AppendFormat("Reserved7 = 0x{0:X2}", response.Reserved7).AppendLine();
if(response.Reserved8 != 0) sb.AppendFormat("Reserved8 = 0x{0:X2}", response.Reserved8).AppendLine();
if(response.Reserved9 != 0) sb.AppendFormat("Reserved9 = 0x{0:X8}", response.Reserved9).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0)
sb.AppendFormat("Reserved3 = 0x{0:X2}", response.Reserved3).AppendLine();
if(response.Reserved4 != 0)
sb.AppendFormat("Reserved4 = 0x{0:X16}", response.Reserved4).AppendLine();
if(response.Reserved5 != 0)
sb.AppendFormat("Reserved5 = 0x{0:X8}", response.Reserved5).AppendLine();
if(response.Reserved6 != 0)
sb.AppendFormat("Reserved6 = 0x{0:X8}", response.Reserved6).AppendLine();
if(response.Reserved7 != 0)
sb.AppendFormat("Reserved7 = 0x{0:X2}", response.Reserved7).AppendLine();
if(response.Reserved8 != 0)
sb.AppendFormat("Reserved8 = 0x{0:X2}", response.Reserved8).AppendLine();
if(response.Reserved9 != 0)
sb.AppendFormat("Reserved9 = 0x{0:X8}", response.Reserved9).AppendLine();
#endif
return sb.ToString();
}
public static string Prettify(byte[] DDSResponse) => Prettify(Decode(DDSResponse));
#endregion Public methods
#region Public structures
public struct DiscDefinitionStructure
{
/// <summary>
/// Bytes 0 to 1
/// Data Length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 5
/// "DS"
/// </summary>
public ushort Signature;
/// <summary>
/// Byte 6
/// DDS format
/// </summary>
public byte Format;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Bytes 8 to 11
/// DDS update count
/// </summary>
public uint UpdateCount;
/// <summary>
/// Bytes 12 to 19
/// Reserved
/// </summary>
public ulong Reserved4;
/// <summary>
/// Bytes 20 to 23
/// First PSN of Drive Area
/// </summary>
public uint DriveAreaPSN;
/// <summary>
/// Bytes 24 to 27
/// Reserved
/// </summary>
public uint Reserved5;
/// <summary>
/// Bytes 28 to 31
/// First PSN of Defect List
/// </summary>
public uint DefectListPSN;
/// <summary>
/// Bytes 32 to 35
/// Reserved
/// </summary>
public uint Reserved6;
/// <summary>
/// Bytes 36 to 39
/// PSN of LSN 0 of user data area
/// </summary>
public uint PSNofLSNZero;
/// <summary>
/// Bytes 40 to 43
/// Last LSN of user data area
/// </summary>
public uint LastUserAreaLSN;
/// <summary>
/// Bytes 44 to 47
/// ISA0 size
/// </summary>
public uint ISA0;
/// <summary>
/// Bytes 48 to 51
/// OSA size
/// </summary>
public uint OSA;
/// <summary>
/// Bytes 52 to 55
/// ISA1 size
/// </summary>
public uint ISA1;
/// <summary>
/// Byte 56
/// Spare Area full flags
/// </summary>
public byte SpareAreaFullFlags;
/// <summary>
/// Byte 57
/// Reserved
/// </summary>
public byte Reserved7;
/// <summary>
/// Byte 58
/// Disc type specific field
/// </summary>
public byte DiscTypeSpecificField1;
/// <summary>
/// Byte 59
/// Reserved
/// </summary>
public byte Reserved8;
/// <summary>
/// Byte 60 to 63
/// Disc type specific field
/// </summary>
public uint DiscTypeSpecificField2;
/// <summary>
/// Byte 64 to 67
/// Reserved
/// </summary>
public uint Reserved9;
/// <summary>
/// Bytes 68 to 99
/// Status bits of INFO1/2 and PAC1/2 on L0 and L1
/// </summary>
public byte[] StatusBits;
/// <summary>
/// Bytes 100 to end
/// Disc type specific data
/// </summary>
public byte[] DiscTypeSpecificData;
}
#endregion Public structures
}
}

View File

@@ -39,54 +39,64 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.Bluray
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class DI
{
public enum BluSize : byte
{
/// <summary>120mm</summary>
OneTwenty = 0, /// <summary>80mm</summary>
Eighty = 1
}
public enum ChannelLength : byte
{
/// <summary>74.5nm channel or 25Gb/layer</summary>
Seventy = 1, /// <summary>69.0nm channel or 27Gb/layer</summary>
Sixty = 2
}
public enum HybridLayer : byte
{
/// <summary>No hybrid layer</summary>
None = 0, /// <summary>-ROM layer</summary>
ReadOnly = 1, /// <summary>-R layer</summary>
Recordable = 2, /// <summary>-RW layer</summary>
Rewritable = 3
}
#region Private constants
const string DiscTypeBDROM = "BDO";
const string DiscTypeBDRE = "BDW";
const string DiscTypeBDR = "BDR";
/// <summary>
/// Disc Information Unit Identifier "DI"
/// </summary>
/// <summary>Disc Information Unit Identifier "DI"</summary>
const ushort DIUIdentifier = 0x4449;
#endregion Private constants
#region Public methods
public static DiscInformation? Decode(byte[] DIResponse)
{
if(DIResponse == null) return null;
if(DIResponse == null)
return null;
if(DIResponse.Length != 4100)
{
DicConsole.DebugWriteLine("BD Disc Information decoder",
"Found incorrect Blu-ray Disc Information size ({0} bytes)",
DIResponse.Length);
return null;
}
DiscInformation decoded = new DiscInformation
var decoded = new DiscInformation
{
DataLength = BigEndianBitConverter.ToUInt16(DIResponse, 0),
Reserved1 = DIResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(DIResponse, 0), Reserved1 = DIResponse[2],
Reserved2 = DIResponse[3]
};
@@ -95,14 +105,16 @@ namespace DiscImageChef.Decoders.Bluray
while(true)
{
if(offset >= 4100) break;
if(offset >= 4100)
break;
DiscInformationUnits unit = new DiscInformationUnits
var unit = new DiscInformationUnits
{
Signature = BigEndianBitConverter.ToUInt16(DIResponse, 0 + offset)
};
if(unit.Signature != DIUIdentifier) break;
if(unit.Signature != DIUIdentifier)
break;
unit.Format = DIResponse[2 + offset];
unit.UnitsPerBlock = (byte)((DIResponse[3 + offset] & 0xF8) >> 3);
@@ -125,19 +137,24 @@ namespace DiscImageChef.Decoders.Bluray
unit.RecordedPolarity = DIResponse[14 + offset];
unit.Bca = (byte)(DIResponse[16 + offset] & 0x0F);
unit.MaxTransfer = DIResponse[17 + offset];
unit.LastPsn = (uint)((DIResponse[20 + offset] << 24) + (DIResponse[21 + offset] << 16) +
(DIResponse[22 + offset] << 8) + DIResponse[23 + offset]);
// TODO: In -R/-RE how does this relate to layer size???
unit.FirstAun = (uint)((DIResponse[24 + offset] << 24) + (DIResponse[25 + offset] << 16) +
(DIResponse[26 + offset] << 8) + DIResponse[27 + offset]);
unit.LastAun = (uint)((DIResponse[28 + offset] << 24) + (DIResponse[29 + offset] << 16) +
(DIResponse[30 + offset] << 8) + DIResponse[31 + offset]);
switch(Encoding.ASCII.GetString(unit.DiscTypeIdentifier))
{
case DiscTypeBDROM:
{
unit.FormatDependentContents = new byte[32];
Array.Copy(DIResponse, 32 + offset, unit.FormatDependentContents, 0, 32);
break;
}
@@ -154,6 +171,7 @@ namespace DiscImageChef.Decoders.Bluray
unit.ProductRevisionNumber = DIResponse[111 + offset];
offset += 14;
break;
}
@@ -162,6 +180,7 @@ namespace DiscImageChef.Decoders.Bluray
DicConsole.DebugWriteLine("BD Disc Information decoder",
"Found unknown disc type identifier \"{0}\"",
Encoding.ASCII.GetString(unit.DiscTypeIdentifier));
break;
}
}
@@ -171,21 +190,25 @@ namespace DiscImageChef.Decoders.Bluray
offset += unit.Length;
}
if(units.Count <= 0) return decoded;
if(units.Count <= 0)
return decoded;
decoded.Units = new DiscInformationUnits[units.Count];
for(int i = 0; i < units.Count; i++) decoded.Units[i] = units[i];
for(int i = 0; i < units.Count; i++)
decoded.Units[i] = units[i];
return decoded;
}
public static string Prettify(DiscInformation? DIResponse)
{
if(DIResponse == null) return null;
if(DIResponse == null)
return null;
DiscInformation response = DIResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
foreach(DiscInformationUnits unit in response.Units)
{
@@ -193,41 +216,53 @@ namespace DiscImageChef.Decoders.Bluray
sb.AppendFormat("DI Unit Format: 0x{0:X2}", unit.Format).AppendLine();
sb.AppendFormat("There are {0} per block", unit.UnitsPerBlock).AppendLine();
sb.AppendFormat("This DI refers to layer {0}", unit.Layer).AppendLine();
if(Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDRE)
sb.AppendFormat("Legacy value: 0x{0:X2}", unit.Legacy).AppendLine();
sb.AppendLine(unit.Continuation ? "This DI continues previous unit" : "This DI starts a new unit");
sb.AppendFormat("DI Unit is {0} bytes", unit.Length).AppendLine();
sb.AppendFormat("Disc type identifier: \"{0}\"", Encoding.ASCII.GetString(unit.DiscTypeIdentifier))
.AppendLine();
sb.AppendFormat("Disc type identifier: \"{0}\"", Encoding.ASCII.GetString(unit.DiscTypeIdentifier)).
AppendLine();
switch(unit.DiscSize)
{
case BluSize.OneTwenty:
sb.AppendLine("Disc size: 120mm");
break;
case BluSize.Eighty:
sb.AppendLine("Disc size: 80mm");
break;
default:
sb.AppendFormat("Disc size: Unknown code {0}", (byte)unit.DiscSize).AppendLine();
break;
}
sb.AppendFormat("Disc class: {0}", unit.DiscClass).AppendLine();
sb.AppendFormat("Disc version: {0}", unit.DiscVersion).AppendLine();
sb.AppendFormat("This disc has {0} layers", unit.Layers).AppendLine();
switch(unit.DvdLayer)
{
case HybridLayer.None:
sb.AppendLine("This disc does not contain a DVD layer.");
break;
case HybridLayer.ReadOnly:
sb.AppendLine("This disc contains a DVD-ROM layer.");
break;
case HybridLayer.Recordable:
sb.AppendLine("This disc contains a DVD-R layer.");
break;
case HybridLayer.Rewritable:
sb.AppendLine("This disc contains a DVD-RW layer.");
break;
}
@@ -235,15 +270,19 @@ namespace DiscImageChef.Decoders.Bluray
{
case HybridLayer.None:
sb.AppendLine("This disc does not contain a CD layer.");
break;
case HybridLayer.ReadOnly:
sb.AppendLine("This disc contains a CD-ROM layer.");
break;
case HybridLayer.Recordable:
sb.AppendLine("This disc contains a CD-R layer.");
break;
case HybridLayer.Rewritable:
sb.AppendLine("This disc contains a CD-RW layer.");
break;
}
@@ -251,13 +290,16 @@ namespace DiscImageChef.Decoders.Bluray
{
case ChannelLength.Seventy:
sb.AppendLine("Disc uses a 74.5nm channel giving 25 Gb per layer.");
break;
case ChannelLength.Sixty:
sb.AppendLine("Disc uses a 69.0nm channel giving 27 Gb per layer.");
break;
default:
sb.AppendFormat("Disc uses unknown channel length with code {0}", (byte)unit.ChannelLength)
.AppendLine();
sb.AppendFormat("Disc uses unknown channel length with code {0}", (byte)unit.ChannelLength).
AppendLine();
break;
}
@@ -265,12 +307,15 @@ namespace DiscImageChef.Decoders.Bluray
{
case 0:
sb.AppendLine("Disc uses positive polarity.");
break;
case 1:
sb.AppendLine("Disc uses negative polarity.");
break;
default:
sb.AppendFormat("Disc uses unknown polarity with code {0}", unit.Polarity).AppendLine();
break;
}
@@ -279,13 +324,16 @@ namespace DiscImageChef.Decoders.Bluray
{
case 0:
sb.AppendLine("Recorded marks have a lower reflectivity than unrecorded ones (HTL disc).");
break;
case 1:
sb.AppendLine("Recorded marks have a higher reflectivity than unrecorded ones (LTH disc).");
break;
default:
sb.AppendFormat("Disc uses unknown recorded reflectivity polarity with code {0}",
unit.RecordedPolarity).AppendLine();
break;
}
@@ -293,31 +341,39 @@ namespace DiscImageChef.Decoders.Bluray
{
case 0:
sb.AppendLine("Disc doesn't have a BCA.");
break;
case 1:
sb.AppendLine("Disc has a BCA.");
break;
default:
sb.AppendFormat("Disc uses unknown BCA code {0}", unit.Bca).AppendLine();
break;
}
if(unit.MaxTransfer > 0)
sb.AppendFormat("Disc has a maximum transfer rate of {0} Mbit/sec.", unit.MaxTransfer).AppendLine();
else sb.AppendLine("Disc does not specify a maximum transfer rate.");
else
sb.AppendLine("Disc does not specify a maximum transfer rate.");
sb.AppendFormat("Last user data PSN for disc: {0}", unit.LastPsn).AppendLine();
sb.AppendFormat("First address unit number of data zone in this layer: {0}", unit.FirstAun)
.AppendLine();
sb.AppendFormat("First address unit number of data zone in this layer: {0}", unit.FirstAun).
AppendLine();
sb.AppendFormat("Last address unit number of data zone in this layer: {0}", unit.LastAun).AppendLine();
if(Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDR ||
Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDRE)
{
sb.AppendFormat("Disc manufacturer ID: \"{0}\"", Encoding.ASCII.GetString(unit.ManufacturerID))
.AppendLine();
sb.AppendFormat("Disc media type ID: \"{0}\"", Encoding.ASCII.GetString(unit.MediaTypeID))
.AppendLine();
sb.AppendFormat("Disc manufacturer ID: \"{0}\"", Encoding.ASCII.GetString(unit.ManufacturerID)).
AppendLine();
sb.AppendFormat("Disc media type ID: \"{0}\"", Encoding.ASCII.GetString(unit.MediaTypeID)).
AppendLine();
sb.AppendFormat("Disc timestamp: 0x{0:X2}", unit.TimeStamp).AppendLine();
sb.AppendFormat("Disc product revison number: {0}", unit.ProductRevisionNumber).AppendLine();
}
@@ -335,219 +391,86 @@ namespace DiscImageChef.Decoders.Bluray
#region Public structures
public struct DiscInformation
{
/// <summary>
/// Bytes 0 to 1
/// Always 4098
/// </summary>
/// <summary>Bytes 0 to 1 Always 4098</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 4 to 4099
/// Disc information units
/// </summary>
/// <summary>Byte 4 to 4099 Disc information units</summary>
public DiscInformationUnits[] Units;
}
public struct DiscInformationUnits
{
/// <summary>
/// Byte 0
/// "DI"
/// </summary>
/// <summary>Byte 0 "DI"</summary>
public ushort Signature;
/// <summary>
/// Byte 2
/// Disc information format
/// </summary>
/// <summary>Byte 2 Disc information format</summary>
public byte Format;
/// <summary>
/// Byte 3, bits 7 to 3
/// Number of DI units per block
/// </summary>
/// <summary>Byte 3, bits 7 to 3 Number of DI units per block</summary>
public byte UnitsPerBlock;
/// <summary>
/// Byte 3, bits 2 to 0
/// Layer this DI refers to
/// </summary>
/// <summary>Byte 3, bits 2 to 0 Layer this DI refers to</summary>
public byte Layer;
/// <summary>
/// Byte 4
/// Reserved for BD-ROM, legacy information for BD-R/-RE
/// </summary>
/// <summary>Byte 4 Reserved for BD-ROM, legacy information for BD-R/-RE</summary>
public byte Legacy;
/// <summary>
/// Byte 5
/// Sequence number for this DI unit
/// </summary>
/// <summary>Byte 5 Sequence number for this DI unit</summary>
public byte Sequence;
/// <summary>
/// Byte 6, bit 7
/// If set this DI is a continuation of the previous one
/// </summary>
/// <summary>Byte 6, bit 7 If set this DI is a continuation of the previous one</summary>
public bool Continuation;
/// <summary>
/// Byte 6, bits 6 to 0
/// Number of bytes used by this DI unit, should be 64 for BD-ROM and 112 for BD-R/-RE
/// </summary>
/// <summary>Byte 6, bits 6 to 0 Number of bytes used by this DI unit, should be 64 for BD-ROM and 112 for BD-R/-RE</summary>
public byte Length;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
/// <summary>Byte 7 Reserved</summary>
public byte Reserved;
/// <summary>
/// Bytes 8 to 10
/// Disc type identifier
/// </summary>
/// <summary>Bytes 8 to 10 Disc type identifier</summary>
public byte[] DiscTypeIdentifier;
/// <summary>
/// Byte 11, bits 7 to 6
/// Disc size
/// </summary>
/// <summary>Byte 11, bits 7 to 6 Disc size</summary>
public BluSize DiscSize;
/// <summary>
/// Byte 11, bits 5 to 4
/// Disc class
/// </summary>
/// <summary>Byte 11, bits 5 to 4 Disc class</summary>
public byte DiscClass;
/// <summary>
/// Byte 11, bits 3 to 0
/// Disc version
/// </summary>
/// <summary>Byte 11, bits 3 to 0 Disc version</summary>
public byte DiscVersion;
/// <summary>
/// Byte 12, bits 7 to 4
/// Layers in this disc
/// </summary>
/// <summary>Byte 12, bits 7 to 4 Layers in this disc</summary>
public byte Layers;
/// <summary>
/// Byte 12, bits 3 to 0
/// Reserved
/// </summary>
/// <summary>Byte 12, bits 3 to 0 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 13, bits 7 to 6
/// DVD layer
/// </summary>
/// <summary>Byte 13, bits 7 to 6 DVD layer</summary>
public HybridLayer DvdLayer;
/// <summary>
/// Byte 13, bits 5 to 4
/// CD layer
/// </summary>
/// <summary>Byte 13, bits 5 to 4 CD layer</summary>
public HybridLayer CdLayer;
/// <summary>
/// Byte 13, bits 3 to 0
/// Channel length
/// </summary>
/// <summary>Byte 13, bits 3 to 0 Channel length</summary>
public ChannelLength ChannelLength;
/// <summary>
/// Byte 14
/// Polarity
/// </summary>
/// <summary>Byte 14 Polarity</summary>
public byte Polarity;
/// <summary>
/// Byte 15
/// Recorded polarity
/// </summary>
/// <summary>Byte 15 Recorded polarity</summary>
public byte RecordedPolarity;
/// <summary>
/// Byte 16, bits 7 to 4
/// Reserved
/// </summary>
/// <summary>Byte 16, bits 7 to 4 Reserved</summary>
public byte Reserved3;
/// <summary>
/// Byte 16, bits 3 to 0
/// If 0 no BCA, if 1 BCA, rest not defined
/// </summary>
/// <summary>Byte 16, bits 3 to 0 If 0 no BCA, if 1 BCA, rest not defined</summary>
public byte Bca;
/// <summary>
/// Byte 17
/// Maximum transfer speed in megabits/second, 0 if no maximum
/// </summary>
/// <summary>Byte 17 Maximum transfer speed in megabits/second, 0 if no maximum</summary>
public byte MaxTransfer;
/// <summary>
/// Bytes 18 to 19
/// Reserved
/// </summary>
/// <summary>Bytes 18 to 19 Reserved</summary>
public ushort Reserved4;
/// <summary>
/// Bytes 20 to 23
/// Last user data PSN for disc
/// </summary>
/// <summary>Bytes 20 to 23 Last user data PSN for disc</summary>
public uint LastPsn;
/// <summary>
/// Bytes 24 to 27
/// First address unit number of data zone in this layer
/// </summary>
/// <summary>Bytes 24 to 27 First address unit number of data zone in this layer</summary>
public uint FirstAun;
/// <summary>
/// Bytes 28 to 31
/// Last address unit number of data zone in this layer
/// </summary>
/// <summary>Bytes 28 to 31 Last address unit number of data zone in this layer</summary>
public uint LastAun;
/// <summary>
/// Bytes 32 to 63 for BD-ROM, bytes 32 to 99 for BD-R/-RE
/// Format dependent contents, disclosed in private blu-ray specifications
/// Bytes 32 to 63 for BD-ROM, bytes 32 to 99 for BD-R/-RE Format dependent contents, disclosed in private blu-ray
/// specifications
/// </summary>
public byte[] FormatDependentContents;
/// <summary>
/// Bytes 100 to 105, BD-R/-RE only
/// Manufacturer ID
/// </summary>
/// <summary>Bytes 100 to 105, BD-R/-RE only Manufacturer ID</summary>
public byte[] ManufacturerID;
/// <summary>
/// Bytes 106 to 108, BD-R/-RE only
/// Media type ID
/// </summary>
/// <summary>Bytes 106 to 108, BD-R/-RE only Media type ID</summary>
public byte[] MediaTypeID;
/// <summary>
/// Bytes 109 to 110, BD-R/-RE only
/// Timestamp
/// </summary>
/// <summary>Bytes 109 to 110, BD-R/-RE only Timestamp</summary>
public ushort TimeStamp;
/// <summary>
/// Byte 111
/// Product revision number
/// </summary>
/// <summary>Byte 111 Product revision number</summary>
public byte ProductRevisionNumber;
}
#endregion Public structures
public enum BluSize : byte
{
/// <summary>120mm</summary>
OneTwenty = 0,
/// <summary>80mm</summary>
Eighty = 1
}
public enum HybridLayer : byte
{
/// <summary>No hybrid layer</summary>
None = 0,
/// <summary>-ROM layer</summary>
ReadOnly = 1,
/// <summary>-R layer</summary>
Recordable = 2,
/// <summary>-RW layer</summary>
Rewritable = 3
}
public enum ChannelLength : byte
{
/// <summary>74.5nm channel or 25Gb/layer</summary>
Seventy = 1,
/// <summary>69.0nm channel or 27Gb/layer</summary>
Sixty = 2
}
}
}

View File

@@ -37,43 +37,49 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.Bluray
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class Spare
{
#region Public structures
public struct SpareAreaInformation
{
/// <summary>Bytes 0 to 1 Always 14</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 7 Reserved</summary>
public uint Reserved3;
/// <summary>Bytes 8 to 11 Free spare blocks</summary>
public uint FreeSpareBlocks;
/// <summary>Bytes 12 to 15 Allocated spare blocks</summary>
public uint AllocatedSpareBlocks;
}
#endregion Public structures
#region Public methods
public static SpareAreaInformation? Decode(byte[] SAIResponse)
{
if(SAIResponse == null) return null;
if(SAIResponse == null)
return null;
if(SAIResponse.Length != 16)
{
DicConsole.DebugWriteLine("BD Spare Area Information decoder",
"Found incorrect Blu-ray Spare Area Information size ({0} bytes)",
SAIResponse.Length);
return null;
}
SpareAreaInformation decoded = new SpareAreaInformation
var decoded = new SpareAreaInformation
{
DataLength = BigEndianBitConverter.ToUInt16(SAIResponse, 0),
Reserved1 = SAIResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(SAIResponse, 0), Reserved1 = SAIResponse[2],
Reserved2 = SAIResponse[3],
Reserved3 = BigEndianBitConverter.ToUInt32(SAIResponse, 4),
FreeSpareBlocks = BigEndianBitConverter.ToUInt32(SAIResponse, 8),
@@ -85,17 +91,23 @@ namespace DiscImageChef.Decoders.Bluray
public static string Prettify(SpareAreaInformation? SAIResponse)
{
if(SAIResponse == null) return null;
if(SAIResponse == null)
return null;
SpareAreaInformation response = SAIResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0) sb.AppendFormat("Reserved3 = 0x{0:X8}", response.Reserved3).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0)
sb.AppendFormat("Reserved3 = 0x{0:X8}", response.Reserved3).AppendLine();
#endif
sb.AppendFormat("{0} free spare blocks", response.FreeSpareBlocks).AppendLine();
sb.AppendFormat("{0} allocated spare blocks", response.AllocatedSpareBlocks).AppendLine();
@@ -104,41 +116,5 @@ namespace DiscImageChef.Decoders.Bluray
public static string Prettify(byte[] SAIResponse) => Prettify(Decode(SAIResponse));
#endregion Public methods
#region Public structures
public struct SpareAreaInformation
{
/// <summary>
/// Bytes 0 to 1
/// Always 14
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 7
/// Reserved
/// </summary>
public uint Reserved3;
/// <summary>
/// Bytes 8 to 11
/// Free spare blocks
/// </summary>
public uint FreeSpareBlocks;
/// <summary>
/// Bytes 12 to 15
/// Allocated spare blocks
/// </summary>
public uint AllocatedSpareBlocks;
}
#endregion Public structures
}
}

View File

@@ -38,201 +38,28 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.CD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class ATIP
{
public struct CDATIP
{
/// <summary>
/// Bytes 1 to 0
/// Total size of returned session information minus this field
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Byte 4, bits 7 to 4
/// Indicative target writing power
/// </summary>
public byte ITWP;
/// <summary>
/// Byte 4, bit 3
/// Set if DDCD
/// </summary>
public bool DDCD;
/// <summary>
/// Byte 4, bits 2 to 0
/// Reference speed
/// </summary>
public byte ReferenceSpeed;
/// <summary>
/// Byte 5, bit 7
/// Always unset
/// </summary>
public bool AlwaysZero;
/// <summary>
/// Byte 5, bit 6
/// Unrestricted media
/// </summary>
public bool URU;
/// <summary>
/// Byte 5, bits 5 to 0
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Byte 6, bit 7
/// Always set
/// </summary>
public bool AlwaysOne;
/// <summary>
/// Byte 6, bit 6
/// Set if rewritable (CD-RW or DDCD-RW)
/// </summary>
public bool DiscType;
/// <summary>
/// Byte 6, bits 5 to 3
/// Disc subtype
/// </summary>
public byte DiscSubType;
/// <summary>
/// Byte 6, bit 2
/// A1 values are valid
/// </summary>
public bool A1Valid;
/// <summary>
/// Byte 6, bit 1
/// A2 values are valid
/// </summary>
public bool A2Valid;
/// <summary>
/// Byte 6, bit 0
/// A3 values are valid
/// </summary>
public bool A3Valid;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
public byte Reserved4;
/// <summary>
/// Byte 8
/// ATIP Start time of Lead-In (Minute)
/// </summary>
public byte LeadInStartMin;
/// <summary>
/// Byte 9
/// ATIP Start time of Lead-In (Second)
/// </summary>
public byte LeadInStartSec;
/// <summary>
/// Byte 10
/// ATIP Start time of Lead-In (Frame)
/// </summary>
public byte LeadInStartFrame;
/// <summary>
/// Byte 11
/// Reserved
/// </summary>
public byte Reserved5;
/// <summary>
/// Byte 12
/// ATIP Last possible start time of Lead-Out (Minute)
/// </summary>
public byte LeadOutStartMin;
/// <summary>
/// Byte 13
/// ATIP Last possible start time of Lead-Out (Second)
/// </summary>
public byte LeadOutStartSec;
/// <summary>
/// Byte 14
/// ATIP Last possible start time of Lead-Out (Frame)
/// </summary>
public byte LeadOutStartFrame;
/// <summary>
/// Byte 15
/// Reserved
/// </summary>
public byte Reserved6;
/// <summary>
/// Bytes 16 to 18
/// A1 values
/// </summary>
public byte[] A1Values;
/// <summary>
/// Byte 19
/// Reserved
/// </summary>
public byte Reserved7;
/// <summary>
/// Bytes 20 to 22
/// A2 values
/// </summary>
public byte[] A2Values;
/// <summary>
/// Byte 23
/// Reserved
/// </summary>
public byte Reserved8;
/// <summary>
/// Bytes 24 to 26
/// A3 values
/// </summary>
public byte[] A3Values;
/// <summary>
/// Byte 27
/// Reserved
/// </summary>
public byte Reserved9;
/// <summary>
/// Bytes 28 to 30
/// S4 values
/// </summary>
public byte[] S4Values;
/// <summary>
/// Byte 31
/// Reserved
/// </summary>
public byte Reserved10;
}
public static CDATIP? Decode(byte[] CDATIPResponse)
{
if(CDATIPResponse == null) return null;
if(CDATIPResponse == null)
return null;
CDATIP decoded = new CDATIP();
var decoded = new CDATIP();
if(CDATIPResponse.Length != 32 && CDATIPResponse.Length != 28)
if(CDATIPResponse.Length != 32 &&
CDATIPResponse.Length != 28)
{
DicConsole.DebugWriteLine("CD ATIP decoder",
"Expected CD ATIP size (32 bytes) is not received size ({0} bytes), not decoding",
CDATIPResponse.Length);
return null;
}
@@ -275,7 +102,8 @@ namespace DiscImageChef.Decoders.CD
decoded.Reserved8 = CDATIPResponse[23];
decoded.Reserved9 = CDATIPResponse[27];
if(CDATIPResponse.Length < 32) return decoded;
if(CDATIPResponse.Length < 32)
return decoded;
decoded.S4Values = new byte[3];
Array.Copy(CDATIPResponse, 28, decoded.S4Values, 0, 3);
@@ -286,72 +114,89 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(CDATIP? CDATIPResponse)
{
if(CDATIPResponse == null) return null;
if(CDATIPResponse == null)
return null;
CDATIP response = CDATIPResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
if(response.DDCD)
{
sb.AppendFormat("Indicative Target Writing Power: 0x{0:X2}", response.ITWP).AppendLine();
sb.AppendLine(response.DiscType ? "Disc is DDCD-RW" : "Disc is DDCD-R");
switch(response.ReferenceSpeed)
{
case 2:
sb.AppendLine("Reference speed is 4x");
break;
case 3:
sb.AppendLine("Reference speed is 8x");
break;
default:
sb.AppendFormat("Reference speed set is unknown: {0}", response.ReferenceSpeed).AppendLine();
break;
}
sb.AppendFormat("ATIP Start time of Lead-in: 0x{0:X6}",
(response.LeadInStartMin << 16) + (response.LeadInStartSec << 8) +
response.LeadInStartFrame).AppendLine();
sb.AppendFormat("ATIP Last possible start time of Lead-out: 0x{0:X6}",
(response.LeadOutStartMin << 16) + (response.LeadOutStartSec << 8) +
response.LeadOutStartFrame).AppendLine();
sb.AppendFormat("S4 value: 0x{0:X6}",
(response.S4Values[0] << 16) + (response.S4Values[1] << 8) + response.S4Values[2])
.AppendLine();
(response.S4Values[0] << 16) + (response.S4Values[1] << 8) + response.S4Values[2]).
AppendLine();
}
else
{
sb.AppendFormat("Indicative Target Writing Power: 0x{0:X2}", response.ITWP & 0x07).AppendLine();
if(response.DiscType)
{
switch(response.DiscSubType)
{
case 0:
sb.AppendLine("Disc is CD-RW");
break;
case 1:
sb.AppendLine("Disc is High-Speed CD-RW");
break;
case 2:
sb.AppendLine("Disc is Ultra-Speed CD-RW");
break;
case 3:
sb.AppendLine("Disc is Ultra-Speed+ CD-RW");
break;
case 4:
sb.AppendLine("Disc is medium type B, low beta category (B-) CD-RW");
break;
case 5:
sb.AppendLine("Disc is medium type B, high beta category (B+) CD-RW");
break;
case 6:
sb.AppendLine("Disc is medium type C, low beta category (C-) CD-RW");
break;
case 7:
sb.AppendLine("Disc is medium type C, high beta category (C+) CD-RW");
break;
default:
sb.AppendFormat("Unknown CD-RW disc subtype: {0}", response.DiscSubType).AppendLine();
break;
}
@@ -359,44 +204,56 @@ namespace DiscImageChef.Decoders.CD
{
case 1:
sb.AppendLine("Reference speed is 2x");
break;
default:
sb.AppendFormat("Reference speed set is unknown: {0}", response.ReferenceSpeed)
.AppendLine();
sb.AppendFormat("Reference speed set is unknown: {0}", response.ReferenceSpeed).
AppendLine();
break;
}
}
else
{
sb.AppendLine("Disc is CD-R");
switch(response.DiscSubType)
{
case 0:
sb.AppendLine("Disc is normal speed (CLV) CD-R");
break;
case 1:
sb.AppendLine("Disc is high speed (CAV) CD-R");
break;
case 2:
sb.AppendLine("Disc is medium type A, low beta category (A-) CD-R");
break;
case 3:
sb.AppendLine("Disc is medium type A, high beta category (A+) CD-R");
break;
case 4:
sb.AppendLine("Disc is medium type B, low beta category (B-) CD-R");
break;
case 5:
sb.AppendLine("Disc is medium type B, high beta category (B+) CD-R");
break;
case 6:
sb.AppendLine("Disc is medium type C, low beta category (C-) CD-R");
break;
case 7:
sb.AppendLine("Disc is medium type C, high beta category (C+) CD-R");
break;
default:
sb.AppendFormat("Unknown CD-R disc subtype: {0}", response.DiscSubType).AppendLine();
break;
}
}
@@ -405,41 +262,48 @@ namespace DiscImageChef.Decoders.CD
sb.AppendFormat("ATIP Start time of Lead-in: {0}:{1:D2}:{2:D2}", response.LeadInStartMin,
response.LeadInStartSec, response.LeadInStartFrame).AppendLine();
sb.AppendFormat("ATIP Last possible start time of Lead-out: {0}:{1:D2}:{2:D2}",
response.LeadOutStartMin, response.LeadOutStartSec, response.LeadOutStartFrame)
.AppendLine();
response.LeadOutStartMin, response.LeadOutStartSec, response.LeadOutStartFrame).
AppendLine();
if(response.A1Valid)
sb.AppendFormat("A1 value: 0x{0:X6}",
(response.A1Values[0] << 16) + (response.A1Values[1] << 8) + response.A1Values[2])
.AppendLine();
(response.A1Values[0] << 16) + (response.A1Values[1] << 8) + response.A1Values[2]).
AppendLine();
if(response.A2Valid)
sb.AppendFormat("A2 value: 0x{0:X6}",
(response.A2Values[0] << 16) + (response.A2Values[1] << 8) + response.A2Values[2])
.AppendLine();
(response.A2Values[0] << 16) + (response.A2Values[1] << 8) + response.A2Values[2]).
AppendLine();
if(response.A3Valid)
sb.AppendFormat("A3 value: 0x{0:X6}",
(response.A3Values[0] << 16) + (response.A3Values[1] << 8) + response.A3Values[2])
.AppendLine();
(response.A3Values[0] << 16) + (response.A3Values[1] << 8) + response.A3Values[2]).
AppendLine();
if(response.S4Values != null)
sb.AppendFormat("S4 value: 0x{0:X6}",
(response.S4Values[0] << 16) + (response.S4Values[1] << 8) + response.S4Values[2])
.AppendLine();
(response.S4Values[0] << 16) + (response.S4Values[1] << 8) + response.S4Values[2]).
AppendLine();
}
if(response.LeadInStartMin != 97) return sb.ToString();
if(response.LeadInStartMin != 97)
return sb.ToString();
int type = response.LeadInStartFrame % 10;
int frm = response.LeadInStartFrame - type;
if(response.DiscType) sb.AppendLine("Disc uses phase change");
if(response.DiscType)
sb.AppendLine("Disc uses phase change");
else
sb.AppendLine(type < 5
? "Disc uses long strategy type dye (Cyanine, AZO, etc...)"
sb.AppendLine(type < 5 ? "Disc uses long strategy type dye (Cyanine, AZO, etc...)"
: "Disc uses short strategy type dye (Phthalocyanine, etc...)");
string manufacturer = ManufacturerFromATIP(response.LeadInStartSec, frm);
if(manufacturer != "") sb.AppendFormat("Disc manufactured by: {0}", manufacturer).AppendLine();
if(manufacturer != "")
sb.AppendFormat("Disc manufactured by: {0}", manufacturer).AppendLine();
return sb.ToString();
}
@@ -447,6 +311,7 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(byte[] CDATIPResponse)
{
CDATIP? decoded = Decode(CDATIPResponse);
return Prettify(decoded);
}
@@ -457,166 +322,169 @@ namespace DiscImageChef.Decoders.CD
case 15:
switch(frm)
{
case 00: return "TDK Corporation";
case 10: return "Ritek Co.";
case 20: return "Mitsubishi Chemical Corporation";
case 30: return "NAN-YA Plastics Corporation";
case 00: return"TDK Corporation";
case 10: return"Ritek Co.";
case 20: return"Mitsubishi Chemical Corporation";
case 30: return"NAN-YA Plastics Corporation";
}
break;
case 16:
switch(frm)
{
case 20: return "Shenzen SG&Gast Digital Optical Discs";
case 30: return "Grand Advance Technology Ltd.";
case 20: return"Shenzen SG&Gast Digital Optical Discs";
case 30: return"Grand Advance Technology Ltd.";
}
break;
case 17:
if(frm == 00) return "Moser Baer India Limited";
if(frm == 00)
return"Moser Baer India Limited";
break;
case 18:
switch(frm)
{
case 10: return "Wealth Fair Investment Ltd.";
case 60: return "Taroko International Co. Ltd.";
case 10: return"Wealth Fair Investment Ltd.";
case 60: return"Taroko International Co. Ltd.";
}
break;
case 20:
if(frm == 10) return "CDA Datenträger Albrechts GmbH";
if(frm == 10)
return"CDA Datenträger Albrechts GmbH";
break;
case 21:
switch(frm)
{
case 10: return "Grupo Condor S.L.";
case 30: return "Bestdisc Technology Corporation";
case 40: return "Optical Disc Manufacturing Equipment";
case 50: return "Sound Sound Multi-Media Development Ltd.";
case 10: return"Grupo Condor S.L.";
case 30: return"Bestdisc Technology Corporation";
case 40: return"Optical Disc Manufacturing Equipment";
case 50: return"Sound Sound Multi-Media Development Ltd.";
}
break;
case 22:
switch(frm)
{
case 00: return "Woongjin Media Corp.";
case 10: return "Seantram Technology Inc.";
case 20: return "Advanced Digital Media";
case 30: return "EXIMPO";
case 40: return "CIS Technology Inc.";
case 50: return "Hong Kong Digital Technology Co., Ltd.";
case 60: return "Acer Media Technology, Inc.";
case 00: return"Woongjin Media Corp.";
case 10: return"Seantram Technology Inc.";
case 20: return"Advanced Digital Media";
case 30: return"EXIMPO";
case 40: return"CIS Technology Inc.";
case 50: return"Hong Kong Digital Technology Co., Ltd.";
case 60: return"Acer Media Technology, Inc.";
}
break;
case 23:
switch(frm)
{
case 00: return "Matsushita Electric Industrial Co., Ltd.";
case 10: return "Doremi Media Co., Ltd.";
case 20: return "Nacar Media s.r.l.";
case 30: return "Audio Distributors Co., Ltd.";
case 40: return "Victor Company of Japan, Ltd.";
case 50: return "Optrom Inc.";
case 60: return "Customer Pressing Oosterhout";
case 00: return"Matsushita Electric Industrial Co., Ltd.";
case 10: return"Doremi Media Co., Ltd.";
case 20: return"Nacar Media s.r.l.";
case 30: return"Audio Distributors Co., Ltd.";
case 40: return"Victor Company of Japan, Ltd.";
case 50: return"Optrom Inc.";
case 60: return"Customer Pressing Oosterhout";
}
break;
case 24:
switch(frm)
{
case 00: return "Taiyo Yuden Company Ltd.";
case 10: return "SONY Corporation";
case 20: return "Computer Support Italy s.r.l.";
case 30: return "Unitech Japan Inc.";
case 40: return "kdg mediatech AG";
case 50: return "Guann Yinn Co., Ltd.";
case 60: return "Harmonic Hall Optical Disc Ltd.";
case 00: return"Taiyo Yuden Company Ltd.";
case 10: return"SONY Corporation";
case 20: return"Computer Support Italy s.r.l.";
case 30: return"Unitech Japan Inc.";
case 40: return"kdg mediatech AG";
case 50: return"Guann Yinn Co., Ltd.";
case 60: return"Harmonic Hall Optical Disc Ltd.";
}
break;
case 25:
switch(frm)
{
case 00: return "MPO";
case 20: return "Hitachi Maxell, Ltd.";
case 30: return "Infodisc Technology Co. Ltd.";
case 40: return "Vivastar AG";
case 50: return "AMS Technology Inc.";
case 60: return "Xcitec Inc.";
case 00: return"MPO";
case 20: return"Hitachi Maxell, Ltd.";
case 30: return"Infodisc Technology Co. Ltd.";
case 40: return"Vivastar AG";
case 50: return"AMS Technology Inc.";
case 60: return"Xcitec Inc.";
}
break;
case 26:
switch(frm)
{
case 00: return "Fornet International Pte Ltd.";
case 10: return "POSTECH Corporation";
case 20: return "SKC Co., Ltd.";
case 30: return "Optical Disc Corporation";
case 40: return "FUJI Photo Film Co., Ltd.";
case 50: return "Lead Data Inc.";
case 60: return "CMC Magnetics Corporation";
case 00: return"Fornet International Pte Ltd.";
case 10: return"POSTECH Corporation";
case 20: return"SKC Co., Ltd.";
case 30: return"Optical Disc Corporation";
case 40: return"FUJI Photo Film Co., Ltd.";
case 50: return"Lead Data Inc.";
case 60: return"CMC Magnetics Corporation";
}
break;
case 27:
switch(frm)
{
case 00: return "Digital Storage Technology Co., Ltd.";
case 10: return "Plasmon Data systems Ltd.";
case 20: return "Princo Corporation";
case 30: return "Pioneer Video Corporation";
case 40: return "Kodak Japan Ltd.";
case 50: return "Mitsui Chemicals, Inc.";
case 60: return "Ricoh Company Ltd.";
case 00: return"Digital Storage Technology Co., Ltd.";
case 10: return"Plasmon Data systems Ltd.";
case 20: return"Princo Corporation";
case 30: return"Pioneer Video Corporation";
case 40: return"Kodak Japan Ltd.";
case 50: return"Mitsui Chemicals, Inc.";
case 60: return"Ricoh Company Ltd.";
}
break;
case 28:
switch(frm)
{
case 00: return "Opti.Me.S. S.p.A.";
case 10: return "Gigastore Corporation";
case 20: return "Multi Media Masters & Machinary SA";
case 30: return "Auvistar Industry Co., Ltd.";
case 40: return "King Pro Mediatek Inc.";
case 50: return "Delphi Technology Inc.";
case 60: return "Friendly CD-Tek Co.";
case 00: return"Opti.Me.S. S.p.A.";
case 10: return"Gigastore Corporation";
case 20: return"Multi Media Masters & Machinary SA";
case 30: return"Auvistar Industry Co., Ltd.";
case 40: return"King Pro Mediatek Inc.";
case 50: return"Delphi Technology Inc.";
case 60: return"Friendly CD-Tek Co.";
}
break;
case 29:
switch(frm)
{
case 00: return "Taeil Media Co., Ltd.";
case 10: return "Vanguard Disc Inc.";
case 20: return "Unidisc Technology Co., Ltd.";
case 30: return "Hile Optical Disc Technology Corp.";
case 40: return "Viva Magnetics Ltd.";
case 50: return "General Magnetics Ltd.";
case 00: return"Taeil Media Co., Ltd.";
case 10: return"Vanguard Disc Inc.";
case 20: return"Unidisc Technology Co., Ltd.";
case 30: return"Hile Optical Disc Technology Corp.";
case 40: return"Viva Magnetics Ltd.";
case 50: return"General Magnetics Ltd.";
}
break;
case 30:
if(frm == 10) return "CDA Datenträger Albrechts GmbH";
if(frm == 10)
return"CDA Datenträger Albrechts GmbH";
break;
case 31:
switch(frm)
{
case 00: return "Ritek Co.";
case 30: return "Grand Advance Technology Ltd.";
case 00: return"Ritek Co.";
case 30: return"Grand Advance Technology Ltd.";
}
break;
case 32:
switch(frm)
{
case 00: return "TDK Corporation";
case 10: return "Prodisc Technology Inc.";
case 00: return"TDK Corporation";
case 10: return"Prodisc Technology Inc.";
}
break;
@@ -624,96 +492,165 @@ namespace DiscImageChef.Decoders.CD
switch(frm)
{
case 20:
case 22: return "Mitsubishi Chemical Corporation";
case 22: return"Mitsubishi Chemical Corporation";
}
break;
case 42:
if(frm == 20) return "Advanced Digital Media";
if(frm == 20)
return"Advanced Digital Media";
break;
case 45:
switch(frm)
{
case 00: return "Fornet International Pte Ltd.";
case 10: return "Unitech Japan Inc.";
case 20: return "Acer Media Technology, Inc.";
case 40: return "CIS Technology Inc.";
case 50: return "Guann Yinn Co., Ltd.";
case 60: return "Xcitec Inc.";
case 00: return"Fornet International Pte Ltd.";
case 10: return"Unitech Japan Inc.";
case 20: return"Acer Media Technology, Inc.";
case 40: return"CIS Technology Inc.";
case 50: return"Guann Yinn Co., Ltd.";
case 60: return"Xcitec Inc.";
}
break;
case 46:
switch(frm)
{
case 00: return "Taiyo Yuden Company Ltd.";
case 10: return "Hong Kong Digital Technology Co., Ltd.";
case 20: return "Multi Media Masters & Machinary SA";
case 30: return "Computer Support Italy s.r.l.";
case 40: return "FUJI Photo Film Co., Ltd.";
case 50: return "Auvistar Industry Co., Ltd.";
case 60: return "CMC Magnetics Corporation";
case 00: return"Taiyo Yuden Company Ltd.";
case 10: return"Hong Kong Digital Technology Co., Ltd.";
case 20: return"Multi Media Masters & Machinary SA";
case 30: return"Computer Support Italy s.r.l.";
case 40: return"FUJI Photo Film Co., Ltd.";
case 50: return"Auvistar Industry Co., Ltd.";
case 60: return"CMC Magnetics Corporation";
}
break;
case 47:
switch(frm)
{
case 10: return "Hitachi Maxell, Ltd.";
case 20: return "Princo Corporation";
case 40: return "POSTECH Corporation";
case 50: return "Ritek Co.";
case 60: return "Prodisc Technology Inc.";
case 10: return"Hitachi Maxell, Ltd.";
case 20: return"Princo Corporation";
case 40: return"POSTECH Corporation";
case 50: return"Ritek Co.";
case 60: return"Prodisc Technology Inc.";
}
break;
case 48:
switch(frm)
{
case 00: return "Ricoh Company Ltd.";
case 10: return "Kodak Japan Ltd.";
case 20: return "Plasmon Data systems Ltd.";
case 30: return "Pioneer Video Corporation";
case 40: return "Digital Storage Technology Co., Ltd.";
case 50: return "Mitsui Chemicals, Inc.";
case 60: return "Lead Data Inc.";
case 00: return"Ricoh Company Ltd.";
case 10: return"Kodak Japan Ltd.";
case 20: return"Plasmon Data systems Ltd.";
case 30: return"Pioneer Video Corporation";
case 40: return"Digital Storage Technology Co., Ltd.";
case 50: return"Mitsui Chemicals, Inc.";
case 60: return"Lead Data Inc.";
}
break;
case 49:
switch(frm)
{
case 00: return "TDK Corporation";
case 10: return "Gigastore Corporation";
case 20: return "King Pro Mediatek Inc.";
case 30: return "Opti.Me.S. S.p.A.";
case 40: return "Victor Company of Japan, Ltd.";
case 60: return "Matsushita Electric Industrial Co., Ltd.";
case 00: return"TDK Corporation";
case 10: return"Gigastore Corporation";
case 20: return"King Pro Mediatek Inc.";
case 30: return"Opti.Me.S. S.p.A.";
case 40: return"Victor Company of Japan, Ltd.";
case 60: return"Matsushita Electric Industrial Co., Ltd.";
}
break;
case 50:
switch(frm)
{
case 10: return "Vanguard Disc Inc.";
case 20: return "Mitsubishi Chemical Corporation";
case 30: return "CDA Datenträger Albrechts GmbH";
case 10: return"Vanguard Disc Inc.";
case 20: return"Mitsubishi Chemical Corporation";
case 30: return"CDA Datenträger Albrechts GmbH";
}
break;
case 51:
switch(frm)
{
case 10: return "Grand Advance Technology Ltd.";
case 20: return "Infodisc Technology Co. Ltd.";
case 50: return "Hile Optical Disc Technology Corp.";
case 10: return"Grand Advance Technology Ltd.";
case 20: return"Infodisc Technology Co. Ltd.";
case 50: return"Hile Optical Disc Technology Corp.";
}
break;
}
return "";
return"";
}
public struct CDATIP
{
/// <summary>Bytes 1 to 0 Total size of returned session information minus this field</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Byte 4, bits 7 to 4 Indicative target writing power</summary>
public byte ITWP;
/// <summary>Byte 4, bit 3 Set if DDCD</summary>
public bool DDCD;
/// <summary>Byte 4, bits 2 to 0 Reference speed</summary>
public byte ReferenceSpeed;
/// <summary>Byte 5, bit 7 Always unset</summary>
public bool AlwaysZero;
/// <summary>Byte 5, bit 6 Unrestricted media</summary>
public bool URU;
/// <summary>Byte 5, bits 5 to 0 Reserved</summary>
public byte Reserved3;
/// <summary>Byte 6, bit 7 Always set</summary>
public bool AlwaysOne;
/// <summary>Byte 6, bit 6 Set if rewritable (CD-RW or DDCD-RW)</summary>
public bool DiscType;
/// <summary>Byte 6, bits 5 to 3 Disc subtype</summary>
public byte DiscSubType;
/// <summary>Byte 6, bit 2 A1 values are valid</summary>
public bool A1Valid;
/// <summary>Byte 6, bit 1 A2 values are valid</summary>
public bool A2Valid;
/// <summary>Byte 6, bit 0 A3 values are valid</summary>
public bool A3Valid;
/// <summary>Byte 7 Reserved</summary>
public byte Reserved4;
/// <summary>Byte 8 ATIP Start time of Lead-In (Minute)</summary>
public byte LeadInStartMin;
/// <summary>Byte 9 ATIP Start time of Lead-In (Second)</summary>
public byte LeadInStartSec;
/// <summary>Byte 10 ATIP Start time of Lead-In (Frame)</summary>
public byte LeadInStartFrame;
/// <summary>Byte 11 Reserved</summary>
public byte Reserved5;
/// <summary>Byte 12 ATIP Last possible start time of Lead-Out (Minute)</summary>
public byte LeadOutStartMin;
/// <summary>Byte 13 ATIP Last possible start time of Lead-Out (Second)</summary>
public byte LeadOutStartSec;
/// <summary>Byte 14 ATIP Last possible start time of Lead-Out (Frame)</summary>
public byte LeadOutStartFrame;
/// <summary>Byte 15 Reserved</summary>
public byte Reserved6;
/// <summary>Bytes 16 to 18 A1 values</summary>
public byte[] A1Values;
/// <summary>Byte 19 Reserved</summary>
public byte Reserved7;
/// <summary>Bytes 20 to 22 A2 values</summary>
public byte[] A2Values;
/// <summary>Byte 23 Reserved</summary>
public byte Reserved8;
/// <summary>Bytes 24 to 26 A3 values</summary>
public byte[] A3Values;
/// <summary>Byte 27 Reserved</summary>
public byte Reserved9;
/// <summary>Bytes 28 to 30 S4 values</summary>
public byte[] S4Values;
/// <summary>Byte 31 Reserved</summary>
public byte Reserved10;
}
}
}

View File

@@ -38,178 +38,57 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.CD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class CDTextOnLeadIn
{
public enum PackTypeIndicator : byte
{
/// <summary>
/// Title of the track (or album if track == 0)
/// </summary>
Title = 0x80,
/// <summary>
/// Performer
/// </summary>
Performer = 0x81,
/// <summary>
/// Songwriter
/// </summary>
Songwriter = 0x82,
/// <summary>
/// Composer
/// </summary>
Composer = 0x83,
/// <summary>
/// Arranger
/// </summary>
Arranger = 0x84,
/// <summary>
/// Message from the content provider or artist
/// </summary>
Message = 0x85,
/// <summary>
/// Disc identification information
/// </summary>
DiscIdentification = 0x86,
/// <summary>
/// Genre identification
/// </summary>
GenreIdentification = 0x87,
/// <summary>
/// Table of content information
/// </summary>
TOCInformation = 0x88,
/// <summary>
/// Second table of content information
/// </summary>
SecondTOCInformation = 0x89,
/// <summary>
/// Reserved
/// </summary>
Reserved1 = 0x8A,
/// <summary>
/// Reserved
/// </summary>
Reserved2 = 0x8B,
/// <summary>
/// Reserved
/// </summary>
Reserved3 = 0x8C,
/// <summary>
/// Reserved for content provider only
/// </summary>
ReservedForContentProvider = 0x8D,
/// <summary>
/// UPC of album or ISRC of track
/// </summary>
UPCorISRC = 0x8E,
/// <summary>
/// Size information of the block
/// </summary>
/// <summary>Title of the track (or album if track == 0)</summary>
Title = 0x80, /// <summary>Performer</summary>
Performer = 0x81, /// <summary>Songwriter</summary>
Songwriter = 0x82, /// <summary>Composer</summary>
Composer = 0x83, /// <summary>Arranger</summary>
Arranger = 0x84, /// <summary>Message from the content provider or artist</summary>
Message = 0x85, /// <summary>Disc identification information</summary>
DiscIdentification = 0x86, /// <summary>Genre identification</summary>
GenreIdentification = 0x87, /// <summary>Table of content information</summary>
TOCInformation = 0x88, /// <summary>Second table of content information</summary>
SecondTOCInformation = 0x89, /// <summary>Reserved</summary>
Reserved1 = 0x8A, /// <summary>Reserved</summary>
Reserved2 = 0x8B, /// <summary>Reserved</summary>
Reserved3 = 0x8C, /// <summary>Reserved for content provider only</summary>
ReservedForContentProvider = 0x8D, /// <summary>UPC of album or ISRC of track</summary>
UPCorISRC = 0x8E, /// <summary>Size information of the block</summary>
BlockSizeInformation = 0x8F
}
public struct CDText
{
/// <summary>
/// Total size of returned CD-Text information minus this field
/// </summary>
public ushort DataLength;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// CD-Text data packs
/// </summary>
public CDTextPack[] DataPacks;
}
public struct CDTextPack
{
/// <summary>
/// Byte 0
/// Pack ID1 (Pack Type)
/// </summary>
public byte HeaderID1;
/// <summary>
/// Byte 1
/// Pack ID2 (Track number)
/// </summary>
public byte HeaderID2;
/// <summary>
/// Byte 2
/// Pack ID3
/// </summary>
public byte HeaderID3;
/// <summary>
/// Byte 3, bit 7
/// Double Byte Character Code
/// </summary>
public bool DBCC;
/// <summary>
/// Byte 3, bits 6 to 4
/// Block number
/// </summary>
public byte BlockNumber;
/// <summary>
/// Byte 3, bits 3 to 0
/// Character position
/// </summary>
public byte CharacterPosition;
/// <summary>
/// Bytes 4 to 15
/// Text data
/// </summary>
public byte[] TextDataField;
/// <summary>
/// Bytes 16 to 17
/// CRC16
/// </summary>
public ushort CRC;
}
public static CDText? Decode(byte[] CDTextResponse)
{
if(CDTextResponse == null) return null;
if(CDTextResponse == null)
return null;
CDText decoded = new CDText
var decoded = new CDText
{
DataLength = BigEndianBitConverter.ToUInt16(CDTextResponse, 0),
Reserved1 = CDTextResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(CDTextResponse, 0), Reserved1 = CDTextResponse[2],
Reserved2 = CDTextResponse[3]
};
decoded.DataPacks = new CDTextPack[(decoded.DataLength - 2) / 18];
if(decoded.DataLength == 2) return null;
if(decoded.DataLength == 2)
return null;
if(decoded.DataLength + 2 != CDTextResponse.Length)
{
DicConsole.DebugWriteLine("CD-TEXT decoder",
"Expected CD-TEXT size ({0} bytes) is not received size ({1} bytes), not decoding",
decoded.DataLength + 2, CDTextResponse.Length);
return null;
}
@@ -231,23 +110,27 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(CDText? CDTextResponse)
{
if(CDTextResponse == null) return null;
if(CDTextResponse == null)
return null;
CDText response = CDTextResponse.Value;
StringBuilder sb = new StringBuilder();
CDText response = CDTextResponse.Value;
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
foreach(CDTextPack descriptor in response.DataPacks)
if((descriptor.HeaderID1 & 0x80) != 0x80)
{
// Ignore NOPs
if((descriptor.HeaderID1 & 0x80) != 0)
sb.AppendFormat("Incorrect CD-Text pack type {0}, not decoding", descriptor.HeaderID1)
.AppendLine();
sb.AppendFormat("Incorrect CD-Text pack type {0}, not decoding", descriptor.HeaderID1).
AppendLine();
}
else
{
@@ -256,71 +139,98 @@ namespace DiscImageChef.Decoders.CD
case 0x80:
{
sb.Append("CD-Text pack contains title for ");
if(descriptor.HeaderID2 == 0x00) sb.AppendLine("album");
else sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
if(descriptor.HeaderID2 == 0x00)
sb.AppendLine("album");
else
sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
break;
}
case 0x81:
{
sb.Append("CD-Text pack contains performer for ");
if(descriptor.HeaderID2 == 0x00) sb.AppendLine("album");
else sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
if(descriptor.HeaderID2 == 0x00)
sb.AppendLine("album");
else
sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
break;
}
case 0x82:
{
sb.Append("CD-Text pack contains songwriter for ");
if(descriptor.HeaderID2 == 0x00) sb.AppendLine("album");
else sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
if(descriptor.HeaderID2 == 0x00)
sb.AppendLine("album");
else
sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
break;
}
case 0x83:
{
if(descriptor.HeaderID2 == 0x00) sb.AppendLine("album");
else sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
if(descriptor.HeaderID2 == 0x00)
sb.AppendLine("album");
else
sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
break;
}
case 0x84:
{
sb.Append("CD-Text pack contains arranger for ");
if(descriptor.HeaderID2 == 0x00) sb.AppendLine("album");
else sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
if(descriptor.HeaderID2 == 0x00)
sb.AppendLine("album");
else
sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
break;
}
case 0x85:
{
sb.Append("CD-Text pack contains content provider's message for ");
if(descriptor.HeaderID2 == 0x00) sb.AppendLine("album");
else sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
if(descriptor.HeaderID2 == 0x00)
sb.AppendLine("album");
else
sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
break;
}
case 0x86:
{
sb.AppendLine("CD-Text pack contains disc identification information");
break;
}
case 0x87:
{
sb.AppendLine("CD-Text pack contains genre identification information");
break;
}
case 0x88:
{
sb.AppendLine("CD-Text pack contains table of contents information");
break;
}
case 0x89:
{
sb.AppendLine("CD-Text pack contains second table of contents information");
break;
}
@@ -329,25 +239,31 @@ namespace DiscImageChef.Decoders.CD
case 0x8C:
{
sb.AppendLine("CD-Text pack contains reserved data");
break;
}
case 0x8D:
{
sb.AppendLine("CD-Text pack contains data reserved for content provider only");
break;
}
case 0x8E:
{
if(descriptor.HeaderID2 == 0x00) sb.AppendLine("CD-Text pack contains UPC");
else sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
if(descriptor.HeaderID2 == 0x00)
sb.AppendLine("CD-Text pack contains UPC");
else
sb.AppendFormat("track {0}", descriptor.HeaderID2).AppendLine();
break;
}
case 0x8F:
{
sb.AppendLine("CD-Text pack contains size block information");
break;
}
}
@@ -364,20 +280,25 @@ namespace DiscImageChef.Decoders.CD
case 0x87:
case 0x8E:
{
if(descriptor.DBCC) sb.AppendLine("Double Byte Character Code is used");
if(descriptor.DBCC)
sb.AppendLine("Double Byte Character Code is used");
sb.AppendFormat("Block number {0}", descriptor.BlockNumber).AppendLine();
sb.AppendFormat("Character position {0}", descriptor.CharacterPosition).AppendLine();
sb.AppendFormat("Text field: \"{0}\"",
StringHandlers.CToString(descriptor.TextDataField,
Encoding.GetEncoding("iso-8859-1"))).AppendLine();
break;
}
default:
{
sb.AppendFormat("Binary contents: {0}",
PrintHex.ByteArrayToHexArrayString(descriptor.TextDataField, 28))
.AppendLine();
PrintHex.ByteArrayToHexArrayString(descriptor.TextDataField, 28)).
AppendLine();
break;
}
}
@@ -391,7 +312,40 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(byte[] CDTextResponse)
{
CDText? decoded = Decode(CDTextResponse);
return Prettify(decoded);
}
public struct CDText
{
/// <summary>Total size of returned CD-Text information minus this field</summary>
public ushort DataLength;
/// <summary>Reserved</summary>
public byte Reserved1;
/// <summary>Reserved</summary>
public byte Reserved2;
/// <summary>CD-Text data packs</summary>
public CDTextPack[] DataPacks;
}
public struct CDTextPack
{
/// <summary>Byte 0 Pack ID1 (Pack Type)</summary>
public byte HeaderID1;
/// <summary>Byte 1 Pack ID2 (Track number)</summary>
public byte HeaderID2;
/// <summary>Byte 2 Pack ID3</summary>
public byte HeaderID3;
/// <summary>Byte 3, bit 7 Double Byte Character Code</summary>
public bool DBCC;
/// <summary>Byte 3, bits 6 to 4 Block number</summary>
public byte BlockNumber;
/// <summary>Byte 3, bits 3 to 0 Character position</summary>
public byte CharacterPosition;
/// <summary>Bytes 4 to 15 Text data</summary>
public byte[] TextDataField;
/// <summary>Bytes 16 to 17 CRC16</summary>
public ushort CRC;
}
}
}

View File

@@ -37,65 +37,25 @@ namespace DiscImageChef.Decoders.CD
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
public enum TocAdr : byte
{
/// <summary>
/// Q Sub-channel mode information not supplied
/// </summary>
NoInformation = 0x00,
/// <summary>
/// Q Sub-channel encodes current position data
/// </summary>
CurrentPosition = 0x01,
/// <summary>
/// Q Sub-channel encodes the media catalog number
/// </summary>
MediaCatalogNumber = 0x02,
/// <summary>
/// Q Sub-channel encodes the ISRC
/// </summary>
ISRC = 0x03,
/// <summary>
/// Q Sub-channel encodes the start of an audio/data track (if found in TOC)
/// </summary>
TrackPointer = 0x01,
/// <summary>
/// Q Sub-channel encodes the start of a video track (if found in TOC) for CD-V
/// </summary>
/// <summary>Q Sub-channel mode information not supplied</summary>
NoInformation = 0x00, /// <summary>Q Sub-channel encodes current position data</summary>
CurrentPosition = 0x01, /// <summary>Q Sub-channel encodes the media catalog number</summary>
MediaCatalogNumber = 0x02, /// <summary>Q Sub-channel encodes the ISRC</summary>
ISRC = 0x03, /// <summary>Q Sub-channel encodes the start of an audio/data track (if found in TOC)</summary>
TrackPointer = 0x01, /// <summary>Q Sub-channel encodes the start of a video track (if found in TOC) for CD-V</summary>
VideoTrackPointer = 0x04
}
public enum TocControl : byte
{
/// <summary>
/// Stereo audio, no pre-emphasis
/// </summary>
TwoChanNoPreEmph = 0x00,
/// <summary>
/// Stereo audio with pre-emphasis
/// </summary>
TwoChanPreEmph = 0x01,
/// <summary>
/// If mask applied, track can be copied
/// </summary>
CopyPermissionMask = 0x02,
/// <summary>
/// Data track, recorded uninterrumpted
/// </summary>
DataTrack = 0x04,
/// <summary>
/// Data track, recorded incrementally
/// </summary>
DataTrackIncremental = 0x05,
/// <summary>
/// Quadraphonic audio, no pre-emphasis
/// </summary>
FourChanNoPreEmph = 0x08,
/// <summary>
/// Quadraphonic audio with pre-emphasis
/// </summary>
FourChanPreEmph = 0x09,
/// <summary>
/// Reserved mask
/// </summary>
/// <summary>Stereo audio, no pre-emphasis</summary>
TwoChanNoPreEmph = 0x00, /// <summary>Stereo audio with pre-emphasis</summary>
TwoChanPreEmph = 0x01, /// <summary>If mask applied, track can be copied</summary>
CopyPermissionMask = 0x02, /// <summary>Data track, recorded uninterrumpted</summary>
DataTrack = 0x04, /// <summary>Data track, recorded incrementally</summary>
DataTrackIncremental = 0x05, /// <summary>Quadraphonic audio, no pre-emphasis</summary>
FourChanNoPreEmph = 0x08, /// <summary>Quadraphonic audio with pre-emphasis</summary>
FourChanPreEmph = 0x09, /// <summary>Reserved mask</summary>
ReservedMask = 0x0C
}
}

View File

@@ -37,25 +37,13 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.CD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ISO/IEC 61104: Compact disc video system - 12 cm CD-V
/// ISO/IEC 60908: Audio recording - Compact disc digital audio system
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ISO/IEC 61104: Compact
/// disc video system - 12 cm CD-V ISO/IEC 60908: Audio recording - Compact disc digital audio system
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class FullTOC
{
const string StereoNoPre = "Stereo audio track with no pre-emphasis";
@@ -65,98 +53,15 @@ namespace DiscImageChef.Decoders.CD
const string DataUnintrp = "Data track, recorded uninterrupted";
const string DataIncrtly = "Data track, recorded incrementally";
public struct CDFullTOC
{
/// <summary>
/// Total size of returned session information minus this field
/// </summary>
public ushort DataLength;
/// <summary>
/// First complete session number in hex
/// </summary>
public byte FirstCompleteSession;
/// <summary>
/// Last complete session number in hex
/// </summary>
public byte LastCompleteSession;
/// <summary>
/// Track descriptors
/// </summary>
public TrackDataDescriptor[] TrackDescriptors;
}
public struct TrackDataDescriptor
{
/// <summary>
/// Byte 0
/// Session number in hex
/// </summary>
public byte SessionNumber;
/// <summary>
/// Byte 1, bits 7 to 4
/// Type of information in Q subchannel of block where this TOC entry was found
/// </summary>
public byte ADR;
/// <summary>
/// Byte 1, bits 3 to 0
/// Track attributes
/// </summary>
public byte CONTROL;
/// <summary>
/// Byte 2
/// </summary>
public byte TNO;
/// <summary>
/// Byte 3
/// </summary>
public byte POINT;
/// <summary>
/// Byte 4
/// </summary>
public byte Min;
/// <summary>
/// Byte 5
/// </summary>
public byte Sec;
/// <summary>
/// Byte 6
/// </summary>
public byte Frame;
/// <summary>
/// Byte 7, CD only
/// </summary>
public byte Zero;
/// <summary>
/// Byte 7, bits 7 to 4, DDCD only
/// </summary>
public byte HOUR;
/// <summary>
/// Byte 7, bits 3 to 0, DDCD only
/// </summary>
public byte PHOUR;
/// <summary>
/// Byte 8
/// </summary>
public byte PMIN;
/// <summary>
/// Byte 9
/// </summary>
public byte PSEC;
/// <summary>
/// Byte 10
/// </summary>
public byte PFRAME;
}
public static CDFullTOC? Decode(byte[] CDFullTOCResponse)
{
if(CDFullTOCResponse == null) return null;
if(CDFullTOCResponse == null)
return null;
CDFullTOC decoded = new CDFullTOC
var decoded = new CDFullTOC
{
DataLength = BigEndianBitConverter.ToUInt16(CDFullTOCResponse, 0),
FirstCompleteSession = CDFullTOCResponse[2],
LastCompleteSession = CDFullTOCResponse[3]
FirstCompleteSession = CDFullTOCResponse[2], LastCompleteSession = CDFullTOCResponse[3]
};
decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 11];
@@ -166,6 +71,7 @@ namespace DiscImageChef.Decoders.CD
DicConsole.DebugWriteLine("CD full TOC decoder",
"Expected CDFullTOC size ({0} bytes) is not received size ({1} bytes), not decoding",
decoded.DataLength + 2, CDFullTOCResponse.Length);
return null;
}
@@ -192,16 +98,18 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(CDFullTOC? CDFullTOCResponse)
{
if(CDFullTOCResponse == null) return null;
if(CDFullTOCResponse == null)
return null;
CDFullTOC response = CDFullTOCResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
int lastSession = 0;
sb.AppendFormat("First complete session number: {0}", response.FirstCompleteSession).AppendLine();
sb.AppendFormat("Last complete session number: {0}", response.LastCompleteSession).AppendLine();
foreach(TrackDataDescriptor descriptor in response.TrackDescriptors)
if((descriptor.CONTROL & 0x08) == 0x08 ||
descriptor.ADR != 1 && descriptor.ADR != 5 && descriptor.ADR != 4 && descriptor.ADR != 6 ||
@@ -240,31 +148,40 @@ namespace DiscImageChef.Decoders.CD
case 0xA0 when descriptor.ADR == 4:
{
sb.AppendFormat("First video track number: {0}", descriptor.PMIN).AppendLine();
switch(descriptor.PSEC)
{
case 0x10:
sb.AppendLine("CD-V single in NTSC format with digital stereo sound");
break;
case 0x11:
sb.AppendLine("CD-V single in NTSC format with digital bilingual sound");
break;
case 0x12:
sb.AppendLine("CD-V disc in NTSC format with digital stereo sound");
break;
case 0x13:
sb.AppendLine("CD-V disc in NTSC format with digital bilingual sound");
break;
case 0x20:
sb.AppendLine("CD-V single in PAL format with digital stereo sound");
break;
case 0x21:
sb.AppendLine("CD-V single in PAL format with digital bilingual sound");
break;
case 0x22:
sb.AppendLine("CD-V disc in PAL format with digital stereo sound");
break;
case 0x23:
sb.AppendLine("CD-V disc in PAL format with digital bilingual sound");
break;
}
@@ -274,63 +191,80 @@ namespace DiscImageChef.Decoders.CD
case 0xA0 when descriptor.ADR == 1:
{
sb.AppendFormat("First track number: {0} (", descriptor.PMIN);
switch((TocControl)(descriptor.CONTROL & 0x0D))
{
case TocControl.TwoChanNoPreEmph:
sb.Append(StereoNoPre);
break;
case TocControl.TwoChanPreEmph:
sb.Append(StereoPreEm);
break;
case TocControl.FourChanNoPreEmph:
sb.Append(QuadNoPreEm);
break;
case TocControl.FourChanPreEmph:
sb.Append(QuadPreEmph);
break;
case TocControl.DataTrack:
sb.Append(DataUnintrp);
break;
case TocControl.DataTrackIncremental:
sb.Append(DataIncrtly);
break;
}
sb.AppendLine(")");
sb.AppendFormat("Disc type: {0}", descriptor.PSEC).AppendLine();
//sb.AppendFormat("Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, descriptor.Frame, descriptor.HOUR).AppendLine();
break;
}
case 0xA1 when descriptor.ADR == 4:
sb.AppendFormat("Last video track number: {0}", descriptor.PMIN).AppendLine();
break;
case 0xA1 when descriptor.ADR == 1:
{
sb.AppendFormat("Last track number: {0} (", descriptor.PMIN);
switch((TocControl)(descriptor.CONTROL & 0x0D))
{
case TocControl.TwoChanNoPreEmph:
sb.Append(StereoNoPre);
break;
case TocControl.TwoChanPreEmph:
sb.Append(StereoPreEm);
break;
case TocControl.FourChanNoPreEmph:
sb.Append(QuadNoPreEm);
break;
case TocControl.FourChanPreEmph:
sb.Append(QuadPreEmph);
break;
case TocControl.DataTrack:
sb.Append(DataUnintrp);
break;
case TocControl.DataTrackIncremental:
sb.Append(DataIncrtly);
break;
}
sb.AppendLine(")");
//sb.AppendFormat("Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, descriptor.Frame, descriptor.HOUR).AppendLine();
break;
}
@@ -343,8 +277,9 @@ namespace DiscImageChef.Decoders.CD
descriptor.PHOUR).AppendLine();
else
sb.AppendFormat("Lead-out start position: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME)
.AppendLine();
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME).
AppendLine();
//sb.AppendFormat("Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, descriptor.Frame, descriptor.HOUR).AppendLine();
switch((TocControl)(descriptor.CONTROL & 0x0D))
@@ -354,10 +289,12 @@ namespace DiscImageChef.Decoders.CD
case TocControl.FourChanNoPreEmph:
case TocControl.FourChanPreEmph:
sb.AppendLine("Lead-out is audio type");
break;
case TocControl.DataTrack:
case TocControl.DataTrackIncremental:
sb.AppendLine("Lead-out is data type");
break;
}
@@ -366,21 +303,24 @@ namespace DiscImageChef.Decoders.CD
case 0xF0:
{
sb.AppendFormat("Book type: 0x{0:X2}", descriptor.PMIN);
sb.AppendFormat("Material type: 0x{0:X2}", descriptor.PSEC);
sb.AppendFormat("Book type: 0x{0:X2}", descriptor.PMIN);
sb.AppendFormat("Material type: 0x{0:X2}", descriptor.PSEC);
sb.AppendFormat("Moment of inertia: 0x{0:X2}", descriptor.PFRAME);
if(descriptor.PHOUR > 0)
sb.AppendFormat("Absolute time: {3:D2}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min,
descriptor.Sec, descriptor.Frame, descriptor.HOUR).AppendLine();
else
sb.AppendFormat("Absolute time: {0:D2}:{1:D2}:{2:D2}", descriptor.Min,
descriptor.Sec, descriptor.Frame).AppendLine();
break;
}
default:
{
if(descriptor.POINT >= 0x01 && descriptor.POINT <= 0x63)
if(descriptor.POINT >= 0x01 &&
descriptor.POINT <= 0x63)
if(descriptor.ADR == 4)
sb.AppendFormat("Video track {3} starts at: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME,
@@ -391,7 +331,8 @@ namespace DiscImageChef.Decoders.CD
if((TocControl)(descriptor.CONTROL & 0x0D) == TocControl.DataTrack ||
(TocControl)(descriptor.CONTROL & 0x0D) ==
TocControl.DataTrackIncremental) type = "Data";
TocControl.DataTrackIncremental)
type = "Data";
if(descriptor.PHOUR > 0)
sb.AppendFormat("{5} track {3} starts at: {4:D2}:{0:D2}:{1:D2}:{2:D2} (",
@@ -406,21 +347,27 @@ namespace DiscImageChef.Decoders.CD
{
case TocControl.TwoChanNoPreEmph:
sb.Append(StereoNoPre);
break;
case TocControl.TwoChanPreEmph:
sb.Append(StereoPreEm);
break;
case TocControl.FourChanNoPreEmph:
sb.Append(QuadNoPreEm);
break;
case TocControl.FourChanPreEmph:
sb.Append(QuadPreEmph);
break;
case TocControl.DataTrack:
sb.Append(DataUnintrp);
break;
case TocControl.DataTrackIncremental:
sb.Append(DataIncrtly);
break;
}
@@ -457,24 +404,26 @@ namespace DiscImageChef.Decoders.CD
{
if(descriptor.PHOUR > 0)
{
sb
.AppendFormat("Start of next possible program in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Start of next possible program in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
descriptor.Min, descriptor.Sec, descriptor.Frame,
descriptor.HOUR).AppendLine();
sb
.AppendFormat("Maximum start of outermost Lead-out in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Maximum start of outermost Lead-out in the recordable area of the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME,
descriptor.PHOUR).AppendLine();
}
else
{
sb
.AppendFormat("Start of next possible program in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Start of next possible program in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2}",
descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine();
sb
.AppendFormat("Maximum start of outermost Lead-out in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME)
.AppendLine();
sb.
AppendFormat("Maximum start of outermost Lead-out in the recordable area of the disc: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME).
AppendLine();
}
break;
@@ -482,9 +431,11 @@ namespace DiscImageChef.Decoders.CD
case 0xB1:
{
sb.AppendFormat("Number of skip interval pointers: {0}", descriptor.PMIN)
.AppendLine();
sb.AppendFormat("Number of skip interval pointers: {0}", descriptor.PMIN).
AppendLine();
sb.AppendFormat("Number of skip track pointers: {0}", descriptor.PSEC).AppendLine();
break;
}
@@ -499,22 +450,25 @@ namespace DiscImageChef.Decoders.CD
sb.AppendFormat("Skip track {0}", descriptor.PMIN).AppendLine();
sb.AppendFormat("Skip track {0}", descriptor.PSEC).AppendLine();
sb.AppendFormat("Skip track {0}", descriptor.PFRAME).AppendLine();
break;
}
case 0xC0:
{
sb.AppendFormat("Optimum recording power: 0x{0:X2}", descriptor.Min).AppendLine();
if(descriptor.PHOUR > 0)
sb
.AppendFormat("Start time of the first Lead-in area in the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Start time of the first Lead-in area in the disc: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME,
descriptor.PHOUR).AppendLine();
else
sb
.AppendFormat("Start time of the first Lead-in area in the disc: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME)
.AppendLine();
sb.
AppendFormat("Start time of the first Lead-in area in the disc: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME).
AppendLine();
break;
}
@@ -528,6 +482,7 @@ namespace DiscImageChef.Decoders.CD
sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine();
sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine();
sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine();
break;
}
@@ -535,23 +490,25 @@ namespace DiscImageChef.Decoders.CD
{
if(descriptor.PHOUR > 0)
{
sb
.AppendFormat("Start position of outer part lead-in area: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Start position of outer part lead-in area: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME,
descriptor.PHOUR).AppendLine();
sb
.AppendFormat("Stop position of inner part lead-out area: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Stop position of inner part lead-out area: {3:D2}:{0:D2}:{1:D2}:{2:D2}",
descriptor.Min, descriptor.Sec, descriptor.Frame,
descriptor.HOUR).AppendLine();
}
else
{
sb
.AppendFormat("Start position of outer part lead-in area: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME)
.AppendLine();
sb
.AppendFormat("Stop position of inner part lead-out area: {0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Start position of outer part lead-in area: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME).
AppendLine();
sb.
AppendFormat("Stop position of inner part lead-out area: {0:D2}:{1:D2}:{2:D2}",
descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine();
}
@@ -560,14 +517,16 @@ namespace DiscImageChef.Decoders.CD
default:
{
if(descriptor.POINT >= 0x01 && descriptor.POINT <= 0x40)
if(descriptor.POINT >= 0x01 &&
descriptor.POINT <= 0x40)
{
sb
.AppendFormat("Start time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME)
.AppendLine();
sb
.AppendFormat("Ending time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2}",
sb.
AppendFormat("Start time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2}",
descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME).
AppendLine();
sb.
AppendFormat("Ending time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2}",
descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine();
}
else
@@ -597,6 +556,7 @@ namespace DiscImageChef.Decoders.CD
{
uint id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame);
sb.AppendFormat("Disc ID: {0:X6}", id & 0x00FFFFFF).AppendLine();
break;
}
}
@@ -608,7 +568,52 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(byte[] CDFullTOCResponse)
{
CDFullTOC? decoded = Decode(CDFullTOCResponse);
return Prettify(decoded);
}
public struct CDFullTOC
{
/// <summary>Total size of returned session information minus this field</summary>
public ushort DataLength;
/// <summary>First complete session number in hex</summary>
public byte FirstCompleteSession;
/// <summary>Last complete session number in hex</summary>
public byte LastCompleteSession;
/// <summary>Track descriptors</summary>
public TrackDataDescriptor[] TrackDescriptors;
}
public struct TrackDataDescriptor
{
/// <summary>Byte 0 Session number in hex</summary>
public byte SessionNumber;
/// <summary>Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found</summary>
public byte ADR;
/// <summary>Byte 1, bits 3 to 0 Track attributes</summary>
public byte CONTROL;
/// <summary>Byte 2</summary>
public byte TNO;
/// <summary>Byte 3</summary>
public byte POINT;
/// <summary>Byte 4</summary>
public byte Min;
/// <summary>Byte 5</summary>
public byte Sec;
/// <summary>Byte 6</summary>
public byte Frame;
/// <summary>Byte 7, CD only</summary>
public byte Zero;
/// <summary>Byte 7, bits 7 to 4, DDCD only</summary>
public byte HOUR;
/// <summary>Byte 7, bits 3 to 0, DDCD only</summary>
public byte PHOUR;
/// <summary>Byte 8</summary>
public byte PMIN;
/// <summary>Byte 9</summary>
public byte PSEC;
/// <summary>Byte 10</summary>
public byte PFRAME;
}
}
}

254
CD/PMA.cs
View File

@@ -37,112 +37,22 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.CD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class PMA
{
public struct CDPMA
{
/// <summary>
/// Total size of returned session information minus this field
/// </summary>
public ushort DataLength;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Track descriptors
/// </summary>
public CDPMADescriptors[] PMADescriptors;
}
public struct CDPMADescriptors
{
/// <summary>
/// Byte 0
/// Reserved
/// </summary>
public byte Reserved;
/// <summary>
/// Byte 1, bits 7 to 4
/// Type of information in Q subchannel of block where this TOC entry was found
/// </summary>
public byte ADR;
/// <summary>
/// Byte 1, bits 3 to 0
/// Track attributes
/// </summary>
public byte CONTROL;
/// <summary>
/// Byte 2
/// </summary>
public byte TNO;
/// <summary>
/// Byte 3
/// </summary>
public byte POINT;
/// <summary>
/// Byte 4
/// </summary>
public byte Min;
/// <summary>
/// Byte 5
/// </summary>
public byte Sec;
/// <summary>
/// Byte 6
/// </summary>
public byte Frame;
/// <summary>
/// Byte 7, bits 7 to 4
/// </summary>
public byte HOUR;
/// <summary>
/// Byte 7, bits 3 to 0
/// </summary>
public byte PHOUR;
/// <summary>
/// Byte 8
/// </summary>
public byte PMIN;
/// <summary>
/// Byte 9
/// </summary>
public byte PSEC;
/// <summary>
/// Byte 10
/// </summary>
public byte PFRAME;
}
public static CDPMA? Decode(byte[] CDPMAResponse)
{
if(CDPMAResponse == null) return null;
if(CDPMAResponse == null)
return null;
CDPMA decoded = new CDPMA
var decoded = new CDPMA
{
DataLength = BigEndianBitConverter.ToUInt16(CDPMAResponse, 0),
Reserved1 = CDPMAResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(CDPMAResponse, 0), Reserved1 = CDPMAResponse[2],
Reserved2 = CDPMAResponse[3]
};
@@ -153,6 +63,7 @@ namespace DiscImageChef.Decoders.CD
DicConsole.DebugWriteLine("CD PMA decoder",
"Expected CDPMA size ({0} bytes) is not received size ({1} bytes), not decoding",
decoded.DataLength + 2, CDPMAResponse.Length);
return null;
}
@@ -178,22 +89,27 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(CDPMA? CDPMAResponse)
{
if(CDPMAResponse == null) return null;
if(CDPMAResponse == null)
return null;
CDPMA response = CDPMAResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
foreach(CDPMADescriptors descriptor in response.PMADescriptors)
{
#if DEBUG
if(descriptor.Reserved != 0) sb.AppendFormat("Reserved = 0x{0:X2}", descriptor.Reserved).AppendLine();
#endif
#if DEBUG
if(descriptor.Reserved != 0)
sb.AppendFormat("Reserved = 0x{0:X2}", descriptor.Reserved).AppendLine();
#endif
switch(descriptor.ADR)
{
@@ -201,25 +117,32 @@ namespace DiscImageChef.Decoders.CD
if(descriptor.POINT > 0)
{
sb.AppendFormat("Track {0}", descriptor.POINT);
switch((TocControl)(descriptor.CONTROL & 0x0D))
{
case TocControl.TwoChanNoPreEmph:
sb.Append(" (Stereo audio track with no pre-emphasis)");
break;
case TocControl.TwoChanPreEmph:
sb.Append(" (Stereo audio track with 50/15 μs pre-emphasis)");
break;
case TocControl.FourChanNoPreEmph:
sb.Append(" (Quadraphonic audio track with no pre-emphasis)");
break;
case TocControl.FourChanPreEmph:
sb.Append(" (Quadraphonic audio track with 50/15 μs pre-emphasis)");
break;
case TocControl.DataTrack:
sb.Append(" (Data track, recorded uninterrupted)");
break;
case TocControl.DataTrackIncremental:
sb.Append(" (Data track, recorded incrementally)");
break;
}
@@ -229,6 +152,7 @@ namespace DiscImageChef.Decoders.CD
else
sb.AppendFormat(" starts at {0:D2}:{1:D2}:{2:D2}", descriptor.PMIN, descriptor.PSEC,
descriptor.PFRAME);
if(descriptor.PHOUR > 0)
sb.AppendFormat(" and ends at {3}:{0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec,
descriptor.Frame, descriptor.HOUR);
@@ -238,60 +162,100 @@ namespace DiscImageChef.Decoders.CD
sb.AppendLine();
}
else goto default;
else
goto default;
break;
case 2:
uint id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame);
sb.AppendFormat("Disc ID: {0:X6}", id & 0x00FFFFFF).AppendLine();
break;
case 3:
sb.AppendFormat("Skip track assignment {0} says that tracks ", descriptor.POINT);
if(descriptor.Min > 0) sb.AppendFormat("{0} ", descriptor.Min);
if(descriptor.Sec > 0) sb.AppendFormat("{0} ", descriptor.Sec);
if(descriptor.Frame > 0) sb.AppendFormat("{0} ", descriptor.Frame);
if(descriptor.PMIN > 0) sb.AppendFormat("{0} ", descriptor.PMIN);
if(descriptor.PSEC > 0) sb.AppendFormat("{0} ", descriptor.PSEC);
if(descriptor.PFRAME > 0) sb.AppendFormat("{0} ", descriptor.PFRAME);
if(descriptor.Min > 0)
sb.AppendFormat("{0} ", descriptor.Min);
if(descriptor.Sec > 0)
sb.AppendFormat("{0} ", descriptor.Sec);
if(descriptor.Frame > 0)
sb.AppendFormat("{0} ", descriptor.Frame);
if(descriptor.PMIN > 0)
sb.AppendFormat("{0} ", descriptor.PMIN);
if(descriptor.PSEC > 0)
sb.AppendFormat("{0} ", descriptor.PSEC);
if(descriptor.PFRAME > 0)
sb.AppendFormat("{0} ", descriptor.PFRAME);
sb.AppendLine("should be skipped");
break;
case 4:
sb.AppendFormat("Unskip track assignment {0} says that tracks ", descriptor.POINT);
if(descriptor.Min > 0) sb.AppendFormat("{0} ", descriptor.Min);
if(descriptor.Sec > 0) sb.AppendFormat("{0} ", descriptor.Sec);
if(descriptor.Frame > 0) sb.AppendFormat("{0} ", descriptor.Frame);
if(descriptor.PMIN > 0) sb.AppendFormat("{0} ", descriptor.PMIN);
if(descriptor.PSEC > 0) sb.AppendFormat("{0} ", descriptor.PSEC);
if(descriptor.PFRAME > 0) sb.AppendFormat("{0} ", descriptor.PFRAME);
if(descriptor.Min > 0)
sb.AppendFormat("{0} ", descriptor.Min);
if(descriptor.Sec > 0)
sb.AppendFormat("{0} ", descriptor.Sec);
if(descriptor.Frame > 0)
sb.AppendFormat("{0} ", descriptor.Frame);
if(descriptor.PMIN > 0)
sb.AppendFormat("{0} ", descriptor.PMIN);
if(descriptor.PSEC > 0)
sb.AppendFormat("{0} ", descriptor.PSEC);
if(descriptor.PFRAME > 0)
sb.AppendFormat("{0} ", descriptor.PFRAME);
sb.AppendLine("should not be skipped");
break;
case 5:
sb.AppendFormat("Skip time interval assignment {0} says that from ", descriptor.POINT);
if(descriptor.PHOUR > 0)
sb.AppendFormat("{3}:{0:D2}:{1:D2}:{2:D2} to ", descriptor.PMIN, descriptor.PSEC,
descriptor.PFRAME, descriptor.PHOUR);
else
sb.AppendFormat("{0:D2}:{1:D2}:{2:D2} to ", descriptor.PMIN, descriptor.PSEC,
descriptor.PFRAME);
if(descriptor.PHOUR > 0)
sb.AppendFormat("{3}:{0:D2}:{1:D2}:{2:D2} ", descriptor.Min, descriptor.Sec,
descriptor.Frame, descriptor.HOUR);
else sb.AppendFormat("{0:D2}:{1:D2}:{2:D2} ", descriptor.Min, descriptor.Sec, descriptor.Frame);
else
sb.AppendFormat("{0:D2}:{1:D2}:{2:D2} ", descriptor.Min, descriptor.Sec, descriptor.Frame);
sb.AppendLine("should be skipped");
break;
case 6:
sb.AppendFormat("Unskip time interval assignment {0} says that from ", descriptor.POINT);
if(descriptor.PHOUR > 0)
sb.AppendFormat("{3}:{0:D2}:{1:D2}:{2:D2} to ", descriptor.PMIN, descriptor.PSEC,
descriptor.PFRAME, descriptor.PHOUR);
else
sb.AppendFormat("{0:D2}:{1:D2}:{2:D2} to ", descriptor.PMIN, descriptor.PSEC,
descriptor.PFRAME);
if(descriptor.PHOUR > 0)
sb.AppendFormat("{3}:{0:D2}:{1:D2}:{2:D2} ", descriptor.Min, descriptor.Sec,
descriptor.Frame, descriptor.HOUR);
else sb.AppendFormat("{0:D2}:{1:D2}:{2:D2} ", descriptor.Min, descriptor.Sec, descriptor.Frame);
else
sb.AppendFormat("{0:D2}:{1:D2}:{2:D2} ", descriptor.Min, descriptor.Sec, descriptor.Frame);
sb.AppendLine("should not be skipped");
break;
default:
@@ -307,6 +271,7 @@ namespace DiscImageChef.Decoders.CD
sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine();
sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine();
sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine();
break;
}
}
@@ -317,7 +282,50 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(byte[] CDPMAResponse)
{
CDPMA? decoded = Decode(CDPMAResponse);
return Prettify(decoded);
}
public struct CDPMA
{
/// <summary>Total size of returned session information minus this field</summary>
public ushort DataLength;
/// <summary>Reserved</summary>
public byte Reserved1;
/// <summary>Reserved</summary>
public byte Reserved2;
/// <summary>Track descriptors</summary>
public CDPMADescriptors[] PMADescriptors;
}
public struct CDPMADescriptors
{
/// <summary>Byte 0 Reserved</summary>
public byte Reserved;
/// <summary>Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found</summary>
public byte ADR;
/// <summary>Byte 1, bits 3 to 0 Track attributes</summary>
public byte CONTROL;
/// <summary>Byte 2</summary>
public byte TNO;
/// <summary>Byte 3</summary>
public byte POINT;
/// <summary>Byte 4</summary>
public byte Min;
/// <summary>Byte 5</summary>
public byte Sec;
/// <summary>Byte 6</summary>
public byte Frame;
/// <summary>Byte 7, bits 7 to 4</summary>
public byte HOUR;
/// <summary>Byte 7, bits 3 to 0</summary>
public byte PHOUR;
/// <summary>Byte 8</summary>
public byte PMIN;
/// <summary>Byte 9</summary>
public byte PSEC;
/// <summary>Byte 10</summary>
public byte PFRAME;
}
}
}

View File

@@ -36,152 +36,143 @@ using System.Linq;
namespace DiscImageChef.Decoders.CD
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class Sector
{
public static readonly byte[] ScrambleTable =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00,
0x28, 0x00, 0x1E, 0x80, 0x08, 0x60, 0x06, 0xA8, 0x02, 0xFE, 0x81, 0x80, 0x60, 0x60, 0x28, 0x28, 0x1E,
0x9E, 0x88, 0x68, 0x66, 0xAE, 0xAA, 0xFC, 0x7F, 0x01, 0xE0, 0x00, 0x48, 0x00, 0x36, 0x80, 0x16, 0xE0,
0x0E, 0xC8, 0x04, 0x56, 0x83, 0x7E, 0xE1, 0xE0, 0x48, 0x48, 0x36, 0xB6, 0x96, 0xF6, 0xEE, 0xC6, 0xCC,
0x52, 0xD5, 0xFD, 0x9F, 0x01, 0xA8, 0x00, 0x7E, 0x80, 0x20, 0x60, 0x18, 0x28, 0x0A, 0x9E, 0x87, 0x28,
0x62, 0x9E, 0xA9, 0xA8, 0x7E, 0xFE, 0xA0, 0x40, 0x78, 0x30, 0x22, 0x94, 0x19, 0xAF, 0x4A, 0xFC, 0x37,
0x01, 0xD6, 0x80, 0x5E, 0xE0, 0x38, 0x48, 0x12, 0xB6, 0x8D, 0xB6, 0xE5, 0xB6, 0xCB, 0x36, 0xD7, 0x56,
0xDE, 0xBE, 0xD8, 0x70, 0x5A, 0xA4, 0x3B, 0x3B, 0x53, 0x53, 0x7D, 0xFD, 0xE1, 0x81, 0x88, 0x60, 0x66,
0xA8, 0x2A, 0xFE, 0x9F, 0x00, 0x68, 0x00, 0x2E, 0x80, 0x1C, 0x60, 0x09, 0xE8, 0x06, 0xCE, 0x82, 0xD4,
0x61, 0x9F, 0x68, 0x68, 0x2E, 0xAE, 0x9C, 0x7C, 0x69, 0xE1, 0xEE, 0xC8, 0x4C, 0x56, 0xB5, 0xFE, 0xF7,
0x00, 0x46, 0x80, 0x32, 0xE0, 0x15, 0x88, 0x0F, 0x26, 0x84, 0x1A, 0xE3, 0x4B, 0x09, 0xF7, 0x46, 0xC6,
0xB2, 0xD2, 0xF5, 0x9D, 0x87, 0x29, 0xA2, 0x9E, 0xF9, 0xA8, 0x42, 0xFE, 0xB1, 0x80, 0x74, 0x60, 0x27,
0x68, 0x1A, 0xAE, 0x8B, 0x3C, 0x67, 0x51, 0xEA, 0xBC, 0x4F, 0x31, 0xF4, 0x14, 0x47, 0x4F, 0x72, 0xB4,
0x25, 0xB7, 0x5B, 0x36, 0xBB, 0x56, 0xF3, 0x7E, 0xC5, 0xE0, 0x53, 0x08, 0x3D, 0xC6, 0x91, 0x92, 0xEC,
0x6D, 0x8D, 0xED, 0xA5, 0x8D, 0xBB, 0x25, 0xB3, 0x5B, 0x35, 0xFB, 0x57, 0x03, 0x7E, 0x81, 0xE0, 0x60,
0x48, 0x28, 0x36, 0x9E, 0x96, 0xE8, 0x6E, 0xCE, 0xAC, 0x54, 0x7D, 0xFF, 0x61, 0x80, 0x28, 0x60, 0x1E,
0xA8, 0x08, 0x7E, 0x86, 0xA0, 0x62, 0xF8, 0x29, 0x82, 0x9E, 0xE1, 0xA8, 0x48, 0x7E, 0xB6, 0xA0, 0x76,
0xF8, 0x26, 0xC2, 0x9A, 0xD1, 0xAB, 0x1C, 0x7F, 0x49, 0xE0, 0x36, 0xC8, 0x16, 0xD6, 0x8E, 0xDE, 0xE4,
0x58, 0x4B, 0x7A, 0xB7, 0x63, 0x36, 0xA9, 0xD6, 0xFE, 0xDE, 0xC0, 0x58, 0x50, 0x3A, 0xBC, 0x13, 0x31,
0xCD, 0xD4, 0x55, 0x9F, 0x7F, 0x28, 0x20, 0x1E, 0x98, 0x08, 0x6A, 0x86, 0xAF, 0x22, 0xFC, 0x19, 0x81,
0xCA, 0xE0, 0x57, 0x08, 0x3E, 0x86, 0x90, 0x62, 0xEC, 0x29, 0x8D, 0xDE, 0xE5, 0x98, 0x4B, 0x2A, 0xB7,
0x5F, 0x36, 0xB8, 0x16, 0xF2, 0x8E, 0xC5, 0xA4, 0x53, 0x3B, 0x7D, 0xD3, 0x61, 0x9D, 0xE8, 0x69, 0x8E,
0xAE, 0xE4, 0x7C, 0x4B, 0x61, 0xF7, 0x68, 0x46, 0xAE, 0xB2, 0xFC, 0x75, 0x81, 0xE7, 0x20, 0x4A, 0x98,
0x37, 0x2A, 0x96, 0x9F, 0x2E, 0xE8, 0x1C, 0x4E, 0x89, 0xF4, 0x66, 0xC7, 0x6A, 0xD2, 0xAF, 0x1D, 0xBC,
0x09, 0xB1, 0xC6, 0xF4, 0x52, 0xC7, 0x7D, 0x92, 0xA1, 0xAD, 0xB8, 0x7D, 0xB2, 0xA1, 0xB5, 0xB8, 0x77,
0x32, 0xA6, 0x95, 0xBA, 0xEF, 0x33, 0x0C, 0x15, 0xC5, 0xCF, 0x13, 0x14, 0x0D, 0xCF, 0x45, 0x94, 0x33,
0x2F, 0x55, 0xDC, 0x3F, 0x19, 0xD0, 0x0A, 0xDC, 0x07, 0x19, 0xC2, 0x8A, 0xD1, 0xA7, 0x1C, 0x7A, 0x89,
0xE3, 0x26, 0xC9, 0xDA, 0xD6, 0xDB, 0x1E, 0xDB, 0x48, 0x5B, 0x76, 0xBB, 0x66, 0xF3, 0x6A, 0xC5, 0xEF,
0x13, 0x0C, 0x0D, 0xC5, 0xC5, 0x93, 0x13, 0x2D, 0xCD, 0xDD, 0x95, 0x99, 0xAF, 0x2A, 0xFC, 0x1F, 0x01,
0xC8, 0x00, 0x56, 0x80, 0x3E, 0xE0, 0x10, 0x48, 0x0C, 0x36, 0x85, 0xD6, 0xE3, 0x1E, 0xC9, 0xC8, 0x56,
0xD6, 0xBE, 0xDE, 0xF0, 0x58, 0x44, 0x3A, 0xB3, 0x53, 0x35, 0xFD, 0xD7, 0x01, 0x9E, 0x80, 0x68, 0x60,
0x2E, 0xA8, 0x1C, 0x7E, 0x89, 0xE0, 0x66, 0xC8, 0x2A, 0xD6, 0x9F, 0x1E, 0xE8, 0x08, 0x4E, 0x86, 0xB4,
0x62, 0xF7, 0x69, 0x86, 0xAE, 0xE2, 0xFC, 0x49, 0x81, 0xF6, 0xE0, 0x46, 0xC8, 0x32, 0xD6, 0x95, 0x9E,
0xEF, 0x28, 0x4C, 0x1E, 0xB5, 0xC8, 0x77, 0x16, 0xA6, 0x8E, 0xFA, 0xE4, 0x43, 0x0B, 0x71, 0xC7, 0x64,
0x52, 0xAB, 0x7D, 0xBF, 0x61, 0xB0, 0x28, 0x74, 0x1E, 0xA7, 0x48, 0x7A, 0xB6, 0xA3, 0x36, 0xF9, 0xD6,
0xC2, 0xDE, 0xD1, 0x98, 0x5C, 0x6A, 0xB9, 0xEF, 0x32, 0xCC, 0x15, 0x95, 0xCF, 0x2F, 0x14, 0x1C, 0x0F,
0x49, 0xC4, 0x36, 0xD3, 0x56, 0xDD, 0xFE, 0xD9, 0x80, 0x5A, 0xE0, 0x3B, 0x08, 0x13, 0x46, 0x8D, 0xF2,
0xE5, 0x85, 0x8B, 0x23, 0x27, 0x59, 0xDA, 0xBA, 0xDB, 0x33, 0x1B, 0x55, 0xCB, 0x7F, 0x17, 0x60, 0x0E,
0xA8, 0x04, 0x7E, 0x83, 0x60, 0x61, 0xE8, 0x28, 0x4E, 0x9E, 0xB4, 0x68, 0x77, 0x6E, 0xA6, 0xAC, 0x7A,
0xFD, 0xE3, 0x01, 0x89, 0xC0, 0x66, 0xD0, 0x2A, 0xDC, 0x1F, 0x19, 0xC8, 0x0A, 0xD6, 0x87, 0x1E, 0xE2,
0x88, 0x49, 0xA6, 0xB6, 0xFA, 0xF6, 0xC3, 0x06, 0xD1, 0xC2, 0xDC, 0x51, 0x99, 0xFC, 0x6A, 0xC1, 0xEF,
0x10, 0x4C, 0x0C, 0x35, 0xC5, 0xD7, 0x13, 0x1E, 0x8D, 0xC8, 0x65, 0x96, 0xAB, 0x2E, 0xFF, 0x5C, 0x40,
0x39, 0xF0, 0x12, 0xC4, 0x0D, 0x93, 0x45, 0xAD, 0xF3, 0x3D, 0x85, 0xD1, 0xA3, 0x1C, 0x79, 0xC9, 0xE2,
0xD6, 0xC9, 0x9E, 0xD6, 0xE8, 0x5E, 0xCE, 0xB8, 0x54, 0x72, 0xBF, 0x65, 0xB0, 0x2B, 0x34, 0x1F, 0x57,
0x48, 0x3E, 0xB6, 0x90, 0x76, 0xEC, 0x26, 0xCD, 0xDA, 0xD5, 0x9B, 0x1F, 0x2B, 0x48, 0x1F, 0x76, 0x88,
0x26, 0xE6, 0x9A, 0xCA, 0xEB, 0x17, 0x0F, 0x4E, 0x84, 0x34, 0x63, 0x57, 0x69, 0xFE, 0xAE, 0xC0, 0x7C,
0x50, 0x21, 0xFC, 0x18, 0x41, 0xCA, 0xB0, 0x57, 0x34, 0x3E, 0x97, 0x50, 0x6E, 0xBC, 0x2C, 0x71, 0xDD,
0xE4, 0x59, 0x8B, 0x7A, 0xE7, 0x63, 0x0A, 0xA9, 0xC7, 0x3E, 0xD2, 0x90, 0x5D, 0xAC, 0x39, 0xBD, 0xD2,
0xF1, 0x9D, 0x84, 0x69, 0xA3, 0x6E, 0xF9, 0xEC, 0x42, 0xCD, 0xF1, 0x95, 0x84, 0x6F, 0x23, 0x6C, 0x19,
0xED, 0xCA, 0xCD, 0x97, 0x15, 0xAE, 0x8F, 0x3C, 0x64, 0x11, 0xEB, 0x4C, 0x4F, 0x75, 0xF4, 0x27, 0x07,
0x5A, 0x82, 0xBB, 0x21, 0xB3, 0x58, 0x75, 0xFA, 0xA7, 0x03, 0x3A, 0x81, 0xD3, 0x20, 0x5D, 0xD8, 0x39,
0x9A, 0x92, 0xEB, 0x2D, 0x8F, 0x5D, 0xA4, 0x39, 0xBB, 0x52, 0xF3, 0x7D, 0x85, 0xE1, 0xA3, 0x08, 0x79,
0xC6, 0xA2, 0xD2, 0xF9, 0x9D, 0x82, 0xE9, 0xA1, 0x8E, 0xF8, 0x64, 0x42, 0xAB, 0x71, 0xBF, 0x64, 0x70,
0x2B, 0x64, 0x1F, 0x6B, 0x48, 0x2F, 0x76, 0x9C, 0x26, 0xE9, 0xDA, 0xCE, 0xDB, 0x14, 0x5B, 0x4F, 0x7B,
0x74, 0x23, 0x67, 0x59, 0xEA, 0xBA, 0xCF, 0x33, 0x14, 0x15, 0xCF, 0x4F, 0x14, 0x34, 0x0F, 0x57, 0x44,
0x3E, 0xB3, 0x50, 0x75, 0xFC, 0x27, 0x01, 0xDA, 0x80, 0x5B, 0x20, 0x3B, 0x58, 0x13, 0x7A, 0x8D, 0xE3,
0x25, 0x89, 0xDB, 0x26, 0xDB, 0x5A, 0xDB, 0x7B, 0x1B, 0x63, 0x4B, 0x69, 0xF7, 0x6E, 0xC6, 0xAC, 0x52,
0xFD, 0xFD, 0x81, 0x81, 0xA0, 0x60, 0x78, 0x28, 0x22, 0x9E, 0x99, 0xA8, 0x6A, 0xFE, 0xAF, 0x00, 0x7C,
0x00, 0x21, 0xC0, 0x18, 0x50, 0x0A, 0xBC, 0x07, 0x31, 0xC2, 0x94, 0x51, 0xAF, 0x7C, 0x7C, 0x21, 0xE1,
0xD8, 0x48, 0x5A, 0xB6, 0xBB, 0x36, 0xF3, 0x56, 0xC5, 0xFE, 0xD3, 0x00, 0x5D, 0xC0, 0x39, 0x90, 0x12,
0xEC, 0x0D, 0x8D, 0xC5, 0xA5, 0x93, 0x3B, 0x2D, 0xD3, 0x5D, 0x9D, 0xF9, 0xA9, 0x82, 0xFE, 0xE1, 0x80,
0x48, 0x60, 0x36, 0xA8, 0x16, 0xFE, 0x8E, 0xC0, 0x64, 0x50, 0x2B, 0x7C, 0x1F, 0x61, 0xC8, 0x28, 0x56,
0x9E, 0xBE, 0xE8, 0x70, 0x4E, 0xA4, 0x34, 0x7B, 0x57, 0x63, 0x7E, 0xA9, 0xE0, 0x7E, 0xC8, 0x20, 0x56,
0x98, 0x3E, 0xEA, 0x90, 0x4F, 0x2C, 0x34, 0x1D, 0xD7, 0x49, 0x9E, 0xB6, 0xE8, 0x76, 0xCE, 0xA6, 0xD4,
0x7A, 0xDF, 0x63, 0x18, 0x29, 0xCA, 0x9E, 0xD7, 0x28, 0x5E, 0x9E, 0xB8, 0x68, 0x72, 0xAE, 0xA5, 0xBC,
0x7B, 0x31, 0xE3, 0x54, 0x49, 0xFF, 0x76, 0xC0, 0x26, 0xD0, 0x1A, 0xDC, 0x0B, 0x19, 0xC7, 0x4A, 0xD2,
0xB7, 0x1D, 0xB6, 0x89, 0xB6, 0xE6, 0xF6, 0xCA, 0xC6, 0xD7, 0x12, 0xDE, 0x8D, 0x98, 0x65, 0xAA, 0xAB,
0x3F, 0x3F, 0x50, 0x10, 0x3C, 0x0C, 0x11, 0xC5, 0xCC, 0x53, 0x15, 0xFD, 0xCF, 0x01, 0x94, 0x00, 0x6F,
0x40, 0x2C, 0x30, 0x1D, 0xD4, 0x09, 0x9F, 0x46, 0xE8, 0x32, 0xCE, 0x95, 0x94, 0x6F, 0x2F, 0x6C, 0x1C,
0x2D, 0xC9, 0xDD, 0x96, 0xD9, 0xAE, 0xDA, 0xFC, 0x5B, 0x01, 0xFB, 0x40, 0x43, 0x70, 0x31, 0xE4, 0x14,
0x4B, 0x4F, 0x77, 0x74, 0x26, 0xA7, 0x5A, 0xFA, 0xBB, 0x03, 0x33, 0x41, 0xD5, 0xF0, 0x5F, 0x04, 0x38,
0x03, 0x52, 0x81, 0xFD, 0xA0, 0x41, 0xB8, 0x30, 0x72, 0x94, 0x25, 0xAF, 0x5B, 0x3C, 0x3B, 0x51, 0xD3,
0x7C, 0x5D, 0xE1, 0xF9, 0x88, 0x42, 0xE6, 0xB1, 0x8A, 0xF4, 0x67, 0x07, 0x6A, 0x82, 0xAF, 0x21, 0xBC,
0x18, 0x71, 0xCA, 0xA4, 0x57, 0x3B, 0x7E, 0x93, 0x60, 0x6D, 0xE8, 0x2D, 0x8E, 0x9D, 0xA4, 0x69, 0xBB,
0x6E, 0xF3, 0x6C, 0x45, 0xED, 0xF3, 0x0D, 0x85, 0xC5, 0xA3, 0x13, 0x39, 0xCD, 0xD2, 0xD5, 0x9D, 0x9F,
0x29, 0xA8, 0x1E, 0xFE, 0x88, 0x40, 0x66, 0xB0, 0x2A, 0xF4, 0x1F, 0x07, 0x48, 0x02, 0xB6, 0x81, 0xB6,
0xE0, 0x76, 0xC8, 0x26, 0xD6, 0x9A, 0xDE, 0xEB, 0x18, 0x4F, 0x4A, 0xB4, 0x37, 0x37, 0x56, 0x96, 0xBE,
0xEE, 0xF0, 0x4C, 0x44, 0x35, 0xF3, 0x57, 0x05, 0xFE, 0x83, 0x00, 0x61, 0xC0, 0x28, 0x50, 0x1E, 0xBC,
0x08, 0x71, 0xC6, 0xA4, 0x52, 0xFB, 0x7D, 0x83, 0x61, 0xA1, 0xE8, 0x78, 0x4E, 0xA2, 0xB4, 0x79, 0xB7,
0x62, 0xF6, 0xA9, 0x86, 0xFE, 0xE2, 0xC0, 0x49, 0x90, 0x36, 0xEC, 0x16, 0xCD, 0xCE, 0xD5, 0x94, 0x5F,
0x2F, 0x78, 0x1C, 0x22, 0x89, 0xD9, 0xA6, 0xDA, 0xFA, 0xDB, 0x03, 0x1B, 0x41, 0xCB, 0x70, 0x57, 0x64,
0x3E, 0xAB, 0x50, 0x7F, 0x7C, 0x20, 0x21, 0xD8, 0x18, 0x5A, 0x8A, 0xBB, 0x27, 0x33, 0x5A, 0x95, 0xFB,
0x2F, 0x03, 0x5C, 0x01, 0xF9, 0xC0, 0x42, 0xD0, 0x31, 0x9C, 0x14, 0x69, 0xCF, 0x6E, 0xD4, 0x2C, 0x5F,
0x5D, 0xF8, 0x39, 0x82, 0x92, 0xE1, 0xAD, 0x88, 0x7D, 0xA6, 0xA1, 0xBA, 0xF8, 0x73, 0x02, 0xA5, 0xC1,
0xBB, 0x10, 0x73, 0x4C, 0x25, 0xF5, 0xDB, 0x07, 0x1B, 0x42, 0x8B, 0x71, 0xA7, 0x64, 0x7A, 0xAB, 0x63,
0x3F, 0x69, 0xD0, 0x2E, 0xDC, 0x1C, 0x59, 0xC9, 0xFA, 0xD6, 0xC3, 0x1E, 0xD1, 0xC8, 0x5C, 0x56, 0xB9,
0xFE, 0xF2, 0xC0, 0x45, 0x90, 0x33, 0x2C, 0x15, 0xDD, 0xCF, 0x19, 0x94, 0x0A, 0xEF, 0x47, 0x0C, 0x32,
0x85, 0xD5, 0xA3, 0x1F, 0x39, 0xC8, 0x12, 0xD6, 0x8D, 0x9E, 0xE5, 0xA8, 0x4B, 0x3E, 0xB7, 0x50, 0x76,
0xBC, 0x26, 0xF1, 0xDA, 0xC4, 0x5B, 0x13, 0x7B, 0x4D, 0xE3, 0x75, 0x89, 0xE7, 0x26, 0xCA, 0x9A, 0xD7,
0x2B, 0x1E, 0x9F, 0x48, 0x68, 0x36, 0xAE, 0x96, 0xFC, 0x6E, 0xC1, 0xEC, 0x50, 0x4D, 0xFC, 0x35, 0x81,
0xD7, 0x20, 0x5E, 0x98, 0x38, 0x6A, 0x92, 0xAF, 0x2D, 0xBC, 0x1D, 0xB1, 0xC9, 0xB4, 0x56, 0xF7, 0x7E,
0xC6, 0xA0, 0x52, 0xF8, 0x3D, 0x82, 0x91, 0xA1, 0xAC, 0x78, 0x7D, 0xE2, 0xA1, 0x89, 0xB8, 0x66, 0xF2,
0xAA, 0xC5, 0xBF, 0x13, 0x30, 0x0D, 0xD4, 0x05, 0x9F, 0x43, 0x28, 0x31, 0xDE, 0x94, 0x58, 0x6F, 0x7A,
0xAC, 0x23, 0x3D, 0xD9, 0xD1, 0x9A, 0xDC, 0x6B, 0x19, 0xEF, 0x4A, 0xCC, 0x37, 0x15, 0xD6, 0x8F, 0x1E,
0xE4, 0x08, 0x4B, 0x46, 0xB7, 0x72, 0xF6, 0xA5, 0x86, 0xFB, 0x22, 0xC3, 0x59, 0x91, 0xFA, 0xEC, 0x43,
0x0D, 0xF1, 0xC5, 0x84, 0x53, 0x23, 0x7D, 0xD9, 0xE1, 0x9A, 0xC8, 0x6B, 0x16, 0xAF, 0x4E, 0xFC, 0x34,
0x41, 0xD7, 0x70, 0x5E, 0xA4, 0x38, 0x7B, 0x52, 0xA3, 0x7D, 0xB9, 0xE1, 0xB2, 0xC8, 0x75, 0x96, 0xA7,
0x2E, 0xFA, 0x9C, 0x43, 0x29, 0xF1, 0xDE, 0xC4, 0x58, 0x53, 0x7A, 0xBD, 0xE3, 0x31, 0x89, 0xD4, 0x66,
0xDF, 0x6A, 0xD8, 0x2F, 0x1A, 0x9C, 0x0B, 0x29, 0xC7, 0x5E, 0xD2, 0xB8, 0x5D, 0xB2, 0xB9, 0xB5, 0xB2,
0xF7, 0x35, 0x86, 0x97, 0x22, 0xEE, 0x99, 0x8C, 0x6A, 0xE5, 0xEF, 0x0B, 0x0C, 0x07, 0x45, 0xC2, 0xB3,
0x11, 0xB5, 0xCC, 0x77, 0x15, 0xE6, 0x8F, 0x0A, 0xE4, 0x07, 0x0B, 0x42, 0x87, 0x71, 0xA2, 0xA4, 0x79,
0xBB, 0x62, 0xF3, 0x69, 0x85, 0xEE, 0xE3, 0x0C, 0x49, 0xC5, 0xF6, 0xD3, 0x06, 0xDD, 0xC2, 0xD9, 0x91,
0x9A, 0xEC, 0x6B, 0x0D, 0xEF, 0x45, 0x8C, 0x33, 0x25, 0xD5, 0xDB, 0x1F, 0x1B, 0x48, 0x0B, 0x76, 0x87,
0x66, 0xE2, 0xAA, 0xC9, 0xBF, 0x16, 0xF0, 0x0E, 0xC4, 0x04, 0x53, 0x43, 0x7D, 0xF1, 0xE1, 0x84, 0x48,
0x63, 0x76, 0xA9, 0xE6, 0xFE, 0xCA, 0xC0, 0x57, 0x10, 0x3E, 0x8C, 0x10, 0x65, 0xCC, 0x2B, 0x15, 0xDF,
0x4F, 0x18, 0x34, 0x0A, 0x97, 0x47, 0x2E, 0xB2, 0x9C, 0x75, 0xA9, 0xE7, 0x3E, 0xCA, 0x90, 0x57, 0x2C,
0x3E, 0x9D, 0xD0, 0x69, 0x9C, 0x2E, 0xE9, 0xDC, 0x4E, 0xD9, 0xF4, 0x5A, 0xC7, 0x7B, 0x12, 0xA3, 0x4D,
0xB9, 0xF5, 0xB2, 0xC7, 0x35, 0x92, 0x97, 0x2D, 0xAE, 0x9D, 0xBC, 0x69, 0xB1, 0xEE, 0xF4, 0x4C, 0x47,
0x75, 0xF2, 0xA7, 0x05, 0xBA, 0x83, 0x33, 0x21, 0xD5, 0xD8, 0x5F, 0x1A, 0xB8, 0x0B, 0x32, 0x87, 0x55,
0xA2, 0xBF, 0x39, 0xB0, 0x12, 0xF4, 0x0D, 0x87, 0x45, 0xA2, 0xB3, 0x39, 0xB5, 0xD2, 0xF7, 0x1D, 0x86,
0x89, 0xA2, 0xE6, 0xF9, 0x8A, 0xC2, 0xE7, 0x11, 0x8A, 0x8C, 0x67, 0x25, 0xEA, 0x9B, 0x0F, 0x2B, 0x44,
0x1F, 0x73, 0x48, 0x25, 0xF6, 0x9B, 0x06, 0xEB, 0x42, 0xCF, 0x71, 0x94, 0x24, 0x6F, 0x5B, 0x6C, 0x3B,
0x6D, 0xD3, 0x6D, 0x9D, 0xED, 0xA9, 0x8D, 0xBE, 0xE5, 0xB0, 0x4B, 0x34, 0x37, 0x57, 0x56, 0xBE, 0xBE,
0xF0, 0x70, 0x44, 0x24, 0x33, 0x5B, 0x55, 0xFB, 0x7F, 0x03, 0x60, 0x01, 0xE8, 0x00, 0x4E, 0x80, 0x34,
0x60, 0x17, 0x68, 0x0E, 0xAE, 0x84, 0x7C, 0x63, 0x61, 0xE9, 0xE8, 0x4E, 0xCE, 0xB4, 0x54, 0x77, 0x7F,
0x66, 0xA0, 0x2A, 0xF8, 0x1F, 0x02, 0x88, 0x01, 0xA6, 0x80, 0x7A, 0xE0, 0x23, 0x08, 0x19, 0xC6, 0x8A,
0xD2, 0xE7, 0x1D, 0x8A, 0x89, 0xA7, 0x26, 0xFA, 0x9A, 0xC3, 0x2B, 0x11, 0xDF, 0x4C, 0x58, 0x35, 0xFA,
0x97, 0x03, 0x2E, 0x81, 0xDC, 0x60, 0x59, 0xE8, 0x3A, 0xCE, 0x93, 0x14, 0x6D, 0xCF, 0x6D, 0x94, 0x2D,
0xAF, 0x5D, 0xBC, 0x39, 0xB1, 0xD2, 0xF4, 0x5D, 0x87, 0x79, 0xA2, 0xA2, 0xF9, 0xB9, 0x82, 0xF2, 0xE1,
0x85, 0x88, 0x63, 0x26, 0xA9, 0xDA, 0xFE, 0xDB, 0x00, 0x5B, 0x40, 0x3B, 0x70, 0x13, 0x64, 0x0D, 0xEB,
0x45, 0x8F, 0x73, 0x24, 0x25, 0xDB, 0x5B, 0x1B, 0x7B, 0x4B, 0x63, 0x77, 0x69, 0xE6, 0xAE, 0xCA, 0xFC,
0x57, 0x01, 0xFE, 0x80, 0x40, 0x60, 0x30, 0x28, 0x14, 0x1E, 0x8F, 0x48, 0x64, 0x36, 0xAB, 0x56, 0xFF,
0x7E, 0xC0, 0x20, 0x50, 0x18, 0x3C, 0x0A, 0x91, 0xC7, 0x2C, 0x52, 0x9D, 0xFD, 0xA9, 0x81, 0xBE, 0xE0,
0x70, 0x48, 0x24, 0x36, 0x9B, 0x56, 0xEB, 0x7E, 0xCF, 0x60, 0x54, 0x28, 0x3F, 0x5E, 0x90, 0x38, 0x6C,
0x12, 0xAD, 0xCD, 0xBD, 0x95, 0xB1, 0xAF, 0x34, 0x7C, 0x17, 0x61, 0xCE, 0xA8, 0x54, 0x7E, 0xBF, 0x60,
0x70, 0x28, 0x24, 0x1E, 0x9B, 0x48, 0x6B, 0x76, 0xAF, 0x66, 0xFC, 0x2A, 0xC1, 0xDF, 0x10, 0x58, 0x0C,
0x3A, 0x85, 0xD3, 0x23, 0x1D, 0xD9, 0xC9, 0x9A, 0xD6, 0xEB, 0x1E, 0xCF, 0x48, 0x54, 0x36, 0xBF, 0x56,
0xF0, 0x3E, 0xC4, 0x10, 0x53, 0x4C, 0x3D, 0xF5, 0xD1, 0x87, 0x1C, 0x62, 0x89, 0xE9, 0xA6, 0xCE, 0xFA,
0xD4, 0x43, 0x1F, 0x71, 0xC8, 0x24, 0x56, 0x9B, 0x7E, 0xEB, 0x60, 0x4F, 0x68, 0x34, 0x2E, 0x97, 0x5C,
0x6E, 0xB9, 0xEC, 0x72, 0xCD, 0xE5, 0x95, 0x8B, 0x2F, 0x27, 0x5C, 0x1A, 0xB9, 0xCB, 0x32, 0xD7, 0x55,
0x9E, 0xBF, 0x28, 0x70, 0x1E, 0xA4, 0x08, 0x7B, 0x46, 0xA3, 0x72, 0xF9, 0xE5, 0x82, 0xCB, 0x21, 0x97,
0x58, 0x6E, 0xBA, 0xAC, 0x73, 0x3D, 0xE5, 0xD1, 0x8B, 0x1C, 0x67, 0x49, 0xEA, 0xB6, 0xCF, 0x36, 0xD4,
0x16, 0xDF, 0x4E, 0xD8, 0x34, 0x5A, 0x97, 0x7B, 0x2E, 0xA3, 0x5C, 0x79, 0xF9, 0xE2, 0xC2, 0xC9, 0x91,
0x96, 0xEC, 0x6E, 0xCD, 0xEC, 0x55, 0x8D, 0xFF, 0x25, 0x80, 0x1B, 0x20, 0x0B, 0x58, 0x07, 0x7A, 0x82,
0xA3, 0x21, 0xB9, 0xD8, 0x72, 0xDA, 0xA5, 0x9B, 0x3B, 0x2B, 0x53, 0x5F, 0x7D, 0xF8, 0x21, 0x82, 0x98,
0x61, 0xAA, 0xA8, 0x7F, 0x3E, 0xA0, 0x10, 0x78, 0x0C, 0x22, 0x85, 0xD9, 0xA3, 0x1A, 0xF9, 0xCB, 0x02,
0xD7, 0x41, 0x9E, 0xB0, 0x68, 0x74, 0x2E, 0xA7, 0x5C, 0x7A, 0xB9, 0xE3, 0x32, 0xC9, 0xD5, 0x96, 0xDF,
0x2E, 0xD8, 0x1C, 0x5A, 0x89, 0xFB, 0x26, 0xC3, 0x5A, 0xD1, 0xFB, 0x1C, 0x43, 0x49, 0xF1, 0xF6, 0xC4,
0x46, 0xD3, 0x72, 0xDD, 0xE5, 0x99
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x28,
0x00, 0x1E, 0x80, 0x08, 0x60, 0x06, 0xA8, 0x02, 0xFE, 0x81, 0x80, 0x60, 0x60, 0x28, 0x28, 0x1E, 0x9E, 0x88,
0x68, 0x66, 0xAE, 0xAA, 0xFC, 0x7F, 0x01, 0xE0, 0x00, 0x48, 0x00, 0x36, 0x80, 0x16, 0xE0, 0x0E, 0xC8, 0x04,
0x56, 0x83, 0x7E, 0xE1, 0xE0, 0x48, 0x48, 0x36, 0xB6, 0x96, 0xF6, 0xEE, 0xC6, 0xCC, 0x52, 0xD5, 0xFD, 0x9F,
0x01, 0xA8, 0x00, 0x7E, 0x80, 0x20, 0x60, 0x18, 0x28, 0x0A, 0x9E, 0x87, 0x28, 0x62, 0x9E, 0xA9, 0xA8, 0x7E,
0xFE, 0xA0, 0x40, 0x78, 0x30, 0x22, 0x94, 0x19, 0xAF, 0x4A, 0xFC, 0x37, 0x01, 0xD6, 0x80, 0x5E, 0xE0, 0x38,
0x48, 0x12, 0xB6, 0x8D, 0xB6, 0xE5, 0xB6, 0xCB, 0x36, 0xD7, 0x56, 0xDE, 0xBE, 0xD8, 0x70, 0x5A, 0xA4, 0x3B,
0x3B, 0x53, 0x53, 0x7D, 0xFD, 0xE1, 0x81, 0x88, 0x60, 0x66, 0xA8, 0x2A, 0xFE, 0x9F, 0x00, 0x68, 0x00, 0x2E,
0x80, 0x1C, 0x60, 0x09, 0xE8, 0x06, 0xCE, 0x82, 0xD4, 0x61, 0x9F, 0x68, 0x68, 0x2E, 0xAE, 0x9C, 0x7C, 0x69,
0xE1, 0xEE, 0xC8, 0x4C, 0x56, 0xB5, 0xFE, 0xF7, 0x00, 0x46, 0x80, 0x32, 0xE0, 0x15, 0x88, 0x0F, 0x26, 0x84,
0x1A, 0xE3, 0x4B, 0x09, 0xF7, 0x46, 0xC6, 0xB2, 0xD2, 0xF5, 0x9D, 0x87, 0x29, 0xA2, 0x9E, 0xF9, 0xA8, 0x42,
0xFE, 0xB1, 0x80, 0x74, 0x60, 0x27, 0x68, 0x1A, 0xAE, 0x8B, 0x3C, 0x67, 0x51, 0xEA, 0xBC, 0x4F, 0x31, 0xF4,
0x14, 0x47, 0x4F, 0x72, 0xB4, 0x25, 0xB7, 0x5B, 0x36, 0xBB, 0x56, 0xF3, 0x7E, 0xC5, 0xE0, 0x53, 0x08, 0x3D,
0xC6, 0x91, 0x92, 0xEC, 0x6D, 0x8D, 0xED, 0xA5, 0x8D, 0xBB, 0x25, 0xB3, 0x5B, 0x35, 0xFB, 0x57, 0x03, 0x7E,
0x81, 0xE0, 0x60, 0x48, 0x28, 0x36, 0x9E, 0x96, 0xE8, 0x6E, 0xCE, 0xAC, 0x54, 0x7D, 0xFF, 0x61, 0x80, 0x28,
0x60, 0x1E, 0xA8, 0x08, 0x7E, 0x86, 0xA0, 0x62, 0xF8, 0x29, 0x82, 0x9E, 0xE1, 0xA8, 0x48, 0x7E, 0xB6, 0xA0,
0x76, 0xF8, 0x26, 0xC2, 0x9A, 0xD1, 0xAB, 0x1C, 0x7F, 0x49, 0xE0, 0x36, 0xC8, 0x16, 0xD6, 0x8E, 0xDE, 0xE4,
0x58, 0x4B, 0x7A, 0xB7, 0x63, 0x36, 0xA9, 0xD6, 0xFE, 0xDE, 0xC0, 0x58, 0x50, 0x3A, 0xBC, 0x13, 0x31, 0xCD,
0xD4, 0x55, 0x9F, 0x7F, 0x28, 0x20, 0x1E, 0x98, 0x08, 0x6A, 0x86, 0xAF, 0x22, 0xFC, 0x19, 0x81, 0xCA, 0xE0,
0x57, 0x08, 0x3E, 0x86, 0x90, 0x62, 0xEC, 0x29, 0x8D, 0xDE, 0xE5, 0x98, 0x4B, 0x2A, 0xB7, 0x5F, 0x36, 0xB8,
0x16, 0xF2, 0x8E, 0xC5, 0xA4, 0x53, 0x3B, 0x7D, 0xD3, 0x61, 0x9D, 0xE8, 0x69, 0x8E, 0xAE, 0xE4, 0x7C, 0x4B,
0x61, 0xF7, 0x68, 0x46, 0xAE, 0xB2, 0xFC, 0x75, 0x81, 0xE7, 0x20, 0x4A, 0x98, 0x37, 0x2A, 0x96, 0x9F, 0x2E,
0xE8, 0x1C, 0x4E, 0x89, 0xF4, 0x66, 0xC7, 0x6A, 0xD2, 0xAF, 0x1D, 0xBC, 0x09, 0xB1, 0xC6, 0xF4, 0x52, 0xC7,
0x7D, 0x92, 0xA1, 0xAD, 0xB8, 0x7D, 0xB2, 0xA1, 0xB5, 0xB8, 0x77, 0x32, 0xA6, 0x95, 0xBA, 0xEF, 0x33, 0x0C,
0x15, 0xC5, 0xCF, 0x13, 0x14, 0x0D, 0xCF, 0x45, 0x94, 0x33, 0x2F, 0x55, 0xDC, 0x3F, 0x19, 0xD0, 0x0A, 0xDC,
0x07, 0x19, 0xC2, 0x8A, 0xD1, 0xA7, 0x1C, 0x7A, 0x89, 0xE3, 0x26, 0xC9, 0xDA, 0xD6, 0xDB, 0x1E, 0xDB, 0x48,
0x5B, 0x76, 0xBB, 0x66, 0xF3, 0x6A, 0xC5, 0xEF, 0x13, 0x0C, 0x0D, 0xC5, 0xC5, 0x93, 0x13, 0x2D, 0xCD, 0xDD,
0x95, 0x99, 0xAF, 0x2A, 0xFC, 0x1F, 0x01, 0xC8, 0x00, 0x56, 0x80, 0x3E, 0xE0, 0x10, 0x48, 0x0C, 0x36, 0x85,
0xD6, 0xE3, 0x1E, 0xC9, 0xC8, 0x56, 0xD6, 0xBE, 0xDE, 0xF0, 0x58, 0x44, 0x3A, 0xB3, 0x53, 0x35, 0xFD, 0xD7,
0x01, 0x9E, 0x80, 0x68, 0x60, 0x2E, 0xA8, 0x1C, 0x7E, 0x89, 0xE0, 0x66, 0xC8, 0x2A, 0xD6, 0x9F, 0x1E, 0xE8,
0x08, 0x4E, 0x86, 0xB4, 0x62, 0xF7, 0x69, 0x86, 0xAE, 0xE2, 0xFC, 0x49, 0x81, 0xF6, 0xE0, 0x46, 0xC8, 0x32,
0xD6, 0x95, 0x9E, 0xEF, 0x28, 0x4C, 0x1E, 0xB5, 0xC8, 0x77, 0x16, 0xA6, 0x8E, 0xFA, 0xE4, 0x43, 0x0B, 0x71,
0xC7, 0x64, 0x52, 0xAB, 0x7D, 0xBF, 0x61, 0xB0, 0x28, 0x74, 0x1E, 0xA7, 0x48, 0x7A, 0xB6, 0xA3, 0x36, 0xF9,
0xD6, 0xC2, 0xDE, 0xD1, 0x98, 0x5C, 0x6A, 0xB9, 0xEF, 0x32, 0xCC, 0x15, 0x95, 0xCF, 0x2F, 0x14, 0x1C, 0x0F,
0x49, 0xC4, 0x36, 0xD3, 0x56, 0xDD, 0xFE, 0xD9, 0x80, 0x5A, 0xE0, 0x3B, 0x08, 0x13, 0x46, 0x8D, 0xF2, 0xE5,
0x85, 0x8B, 0x23, 0x27, 0x59, 0xDA, 0xBA, 0xDB, 0x33, 0x1B, 0x55, 0xCB, 0x7F, 0x17, 0x60, 0x0E, 0xA8, 0x04,
0x7E, 0x83, 0x60, 0x61, 0xE8, 0x28, 0x4E, 0x9E, 0xB4, 0x68, 0x77, 0x6E, 0xA6, 0xAC, 0x7A, 0xFD, 0xE3, 0x01,
0x89, 0xC0, 0x66, 0xD0, 0x2A, 0xDC, 0x1F, 0x19, 0xC8, 0x0A, 0xD6, 0x87, 0x1E, 0xE2, 0x88, 0x49, 0xA6, 0xB6,
0xFA, 0xF6, 0xC3, 0x06, 0xD1, 0xC2, 0xDC, 0x51, 0x99, 0xFC, 0x6A, 0xC1, 0xEF, 0x10, 0x4C, 0x0C, 0x35, 0xC5,
0xD7, 0x13, 0x1E, 0x8D, 0xC8, 0x65, 0x96, 0xAB, 0x2E, 0xFF, 0x5C, 0x40, 0x39, 0xF0, 0x12, 0xC4, 0x0D, 0x93,
0x45, 0xAD, 0xF3, 0x3D, 0x85, 0xD1, 0xA3, 0x1C, 0x79, 0xC9, 0xE2, 0xD6, 0xC9, 0x9E, 0xD6, 0xE8, 0x5E, 0xCE,
0xB8, 0x54, 0x72, 0xBF, 0x65, 0xB0, 0x2B, 0x34, 0x1F, 0x57, 0x48, 0x3E, 0xB6, 0x90, 0x76, 0xEC, 0x26, 0xCD,
0xDA, 0xD5, 0x9B, 0x1F, 0x2B, 0x48, 0x1F, 0x76, 0x88, 0x26, 0xE6, 0x9A, 0xCA, 0xEB, 0x17, 0x0F, 0x4E, 0x84,
0x34, 0x63, 0x57, 0x69, 0xFE, 0xAE, 0xC0, 0x7C, 0x50, 0x21, 0xFC, 0x18, 0x41, 0xCA, 0xB0, 0x57, 0x34, 0x3E,
0x97, 0x50, 0x6E, 0xBC, 0x2C, 0x71, 0xDD, 0xE4, 0x59, 0x8B, 0x7A, 0xE7, 0x63, 0x0A, 0xA9, 0xC7, 0x3E, 0xD2,
0x90, 0x5D, 0xAC, 0x39, 0xBD, 0xD2, 0xF1, 0x9D, 0x84, 0x69, 0xA3, 0x6E, 0xF9, 0xEC, 0x42, 0xCD, 0xF1, 0x95,
0x84, 0x6F, 0x23, 0x6C, 0x19, 0xED, 0xCA, 0xCD, 0x97, 0x15, 0xAE, 0x8F, 0x3C, 0x64, 0x11, 0xEB, 0x4C, 0x4F,
0x75, 0xF4, 0x27, 0x07, 0x5A, 0x82, 0xBB, 0x21, 0xB3, 0x58, 0x75, 0xFA, 0xA7, 0x03, 0x3A, 0x81, 0xD3, 0x20,
0x5D, 0xD8, 0x39, 0x9A, 0x92, 0xEB, 0x2D, 0x8F, 0x5D, 0xA4, 0x39, 0xBB, 0x52, 0xF3, 0x7D, 0x85, 0xE1, 0xA3,
0x08, 0x79, 0xC6, 0xA2, 0xD2, 0xF9, 0x9D, 0x82, 0xE9, 0xA1, 0x8E, 0xF8, 0x64, 0x42, 0xAB, 0x71, 0xBF, 0x64,
0x70, 0x2B, 0x64, 0x1F, 0x6B, 0x48, 0x2F, 0x76, 0x9C, 0x26, 0xE9, 0xDA, 0xCE, 0xDB, 0x14, 0x5B, 0x4F, 0x7B,
0x74, 0x23, 0x67, 0x59, 0xEA, 0xBA, 0xCF, 0x33, 0x14, 0x15, 0xCF, 0x4F, 0x14, 0x34, 0x0F, 0x57, 0x44, 0x3E,
0xB3, 0x50, 0x75, 0xFC, 0x27, 0x01, 0xDA, 0x80, 0x5B, 0x20, 0x3B, 0x58, 0x13, 0x7A, 0x8D, 0xE3, 0x25, 0x89,
0xDB, 0x26, 0xDB, 0x5A, 0xDB, 0x7B, 0x1B, 0x63, 0x4B, 0x69, 0xF7, 0x6E, 0xC6, 0xAC, 0x52, 0xFD, 0xFD, 0x81,
0x81, 0xA0, 0x60, 0x78, 0x28, 0x22, 0x9E, 0x99, 0xA8, 0x6A, 0xFE, 0xAF, 0x00, 0x7C, 0x00, 0x21, 0xC0, 0x18,
0x50, 0x0A, 0xBC, 0x07, 0x31, 0xC2, 0x94, 0x51, 0xAF, 0x7C, 0x7C, 0x21, 0xE1, 0xD8, 0x48, 0x5A, 0xB6, 0xBB,
0x36, 0xF3, 0x56, 0xC5, 0xFE, 0xD3, 0x00, 0x5D, 0xC0, 0x39, 0x90, 0x12, 0xEC, 0x0D, 0x8D, 0xC5, 0xA5, 0x93,
0x3B, 0x2D, 0xD3, 0x5D, 0x9D, 0xF9, 0xA9, 0x82, 0xFE, 0xE1, 0x80, 0x48, 0x60, 0x36, 0xA8, 0x16, 0xFE, 0x8E,
0xC0, 0x64, 0x50, 0x2B, 0x7C, 0x1F, 0x61, 0xC8, 0x28, 0x56, 0x9E, 0xBE, 0xE8, 0x70, 0x4E, 0xA4, 0x34, 0x7B,
0x57, 0x63, 0x7E, 0xA9, 0xE0, 0x7E, 0xC8, 0x20, 0x56, 0x98, 0x3E, 0xEA, 0x90, 0x4F, 0x2C, 0x34, 0x1D, 0xD7,
0x49, 0x9E, 0xB6, 0xE8, 0x76, 0xCE, 0xA6, 0xD4, 0x7A, 0xDF, 0x63, 0x18, 0x29, 0xCA, 0x9E, 0xD7, 0x28, 0x5E,
0x9E, 0xB8, 0x68, 0x72, 0xAE, 0xA5, 0xBC, 0x7B, 0x31, 0xE3, 0x54, 0x49, 0xFF, 0x76, 0xC0, 0x26, 0xD0, 0x1A,
0xDC, 0x0B, 0x19, 0xC7, 0x4A, 0xD2, 0xB7, 0x1D, 0xB6, 0x89, 0xB6, 0xE6, 0xF6, 0xCA, 0xC6, 0xD7, 0x12, 0xDE,
0x8D, 0x98, 0x65, 0xAA, 0xAB, 0x3F, 0x3F, 0x50, 0x10, 0x3C, 0x0C, 0x11, 0xC5, 0xCC, 0x53, 0x15, 0xFD, 0xCF,
0x01, 0x94, 0x00, 0x6F, 0x40, 0x2C, 0x30, 0x1D, 0xD4, 0x09, 0x9F, 0x46, 0xE8, 0x32, 0xCE, 0x95, 0x94, 0x6F,
0x2F, 0x6C, 0x1C, 0x2D, 0xC9, 0xDD, 0x96, 0xD9, 0xAE, 0xDA, 0xFC, 0x5B, 0x01, 0xFB, 0x40, 0x43, 0x70, 0x31,
0xE4, 0x14, 0x4B, 0x4F, 0x77, 0x74, 0x26, 0xA7, 0x5A, 0xFA, 0xBB, 0x03, 0x33, 0x41, 0xD5, 0xF0, 0x5F, 0x04,
0x38, 0x03, 0x52, 0x81, 0xFD, 0xA0, 0x41, 0xB8, 0x30, 0x72, 0x94, 0x25, 0xAF, 0x5B, 0x3C, 0x3B, 0x51, 0xD3,
0x7C, 0x5D, 0xE1, 0xF9, 0x88, 0x42, 0xE6, 0xB1, 0x8A, 0xF4, 0x67, 0x07, 0x6A, 0x82, 0xAF, 0x21, 0xBC, 0x18,
0x71, 0xCA, 0xA4, 0x57, 0x3B, 0x7E, 0x93, 0x60, 0x6D, 0xE8, 0x2D, 0x8E, 0x9D, 0xA4, 0x69, 0xBB, 0x6E, 0xF3,
0x6C, 0x45, 0xED, 0xF3, 0x0D, 0x85, 0xC5, 0xA3, 0x13, 0x39, 0xCD, 0xD2, 0xD5, 0x9D, 0x9F, 0x29, 0xA8, 0x1E,
0xFE, 0x88, 0x40, 0x66, 0xB0, 0x2A, 0xF4, 0x1F, 0x07, 0x48, 0x02, 0xB6, 0x81, 0xB6, 0xE0, 0x76, 0xC8, 0x26,
0xD6, 0x9A, 0xDE, 0xEB, 0x18, 0x4F, 0x4A, 0xB4, 0x37, 0x37, 0x56, 0x96, 0xBE, 0xEE, 0xF0, 0x4C, 0x44, 0x35,
0xF3, 0x57, 0x05, 0xFE, 0x83, 0x00, 0x61, 0xC0, 0x28, 0x50, 0x1E, 0xBC, 0x08, 0x71, 0xC6, 0xA4, 0x52, 0xFB,
0x7D, 0x83, 0x61, 0xA1, 0xE8, 0x78, 0x4E, 0xA2, 0xB4, 0x79, 0xB7, 0x62, 0xF6, 0xA9, 0x86, 0xFE, 0xE2, 0xC0,
0x49, 0x90, 0x36, 0xEC, 0x16, 0xCD, 0xCE, 0xD5, 0x94, 0x5F, 0x2F, 0x78, 0x1C, 0x22, 0x89, 0xD9, 0xA6, 0xDA,
0xFA, 0xDB, 0x03, 0x1B, 0x41, 0xCB, 0x70, 0x57, 0x64, 0x3E, 0xAB, 0x50, 0x7F, 0x7C, 0x20, 0x21, 0xD8, 0x18,
0x5A, 0x8A, 0xBB, 0x27, 0x33, 0x5A, 0x95, 0xFB, 0x2F, 0x03, 0x5C, 0x01, 0xF9, 0xC0, 0x42, 0xD0, 0x31, 0x9C,
0x14, 0x69, 0xCF, 0x6E, 0xD4, 0x2C, 0x5F, 0x5D, 0xF8, 0x39, 0x82, 0x92, 0xE1, 0xAD, 0x88, 0x7D, 0xA6, 0xA1,
0xBA, 0xF8, 0x73, 0x02, 0xA5, 0xC1, 0xBB, 0x10, 0x73, 0x4C, 0x25, 0xF5, 0xDB, 0x07, 0x1B, 0x42, 0x8B, 0x71,
0xA7, 0x64, 0x7A, 0xAB, 0x63, 0x3F, 0x69, 0xD0, 0x2E, 0xDC, 0x1C, 0x59, 0xC9, 0xFA, 0xD6, 0xC3, 0x1E, 0xD1,
0xC8, 0x5C, 0x56, 0xB9, 0xFE, 0xF2, 0xC0, 0x45, 0x90, 0x33, 0x2C, 0x15, 0xDD, 0xCF, 0x19, 0x94, 0x0A, 0xEF,
0x47, 0x0C, 0x32, 0x85, 0xD5, 0xA3, 0x1F, 0x39, 0xC8, 0x12, 0xD6, 0x8D, 0x9E, 0xE5, 0xA8, 0x4B, 0x3E, 0xB7,
0x50, 0x76, 0xBC, 0x26, 0xF1, 0xDA, 0xC4, 0x5B, 0x13, 0x7B, 0x4D, 0xE3, 0x75, 0x89, 0xE7, 0x26, 0xCA, 0x9A,
0xD7, 0x2B, 0x1E, 0x9F, 0x48, 0x68, 0x36, 0xAE, 0x96, 0xFC, 0x6E, 0xC1, 0xEC, 0x50, 0x4D, 0xFC, 0x35, 0x81,
0xD7, 0x20, 0x5E, 0x98, 0x38, 0x6A, 0x92, 0xAF, 0x2D, 0xBC, 0x1D, 0xB1, 0xC9, 0xB4, 0x56, 0xF7, 0x7E, 0xC6,
0xA0, 0x52, 0xF8, 0x3D, 0x82, 0x91, 0xA1, 0xAC, 0x78, 0x7D, 0xE2, 0xA1, 0x89, 0xB8, 0x66, 0xF2, 0xAA, 0xC5,
0xBF, 0x13, 0x30, 0x0D, 0xD4, 0x05, 0x9F, 0x43, 0x28, 0x31, 0xDE, 0x94, 0x58, 0x6F, 0x7A, 0xAC, 0x23, 0x3D,
0xD9, 0xD1, 0x9A, 0xDC, 0x6B, 0x19, 0xEF, 0x4A, 0xCC, 0x37, 0x15, 0xD6, 0x8F, 0x1E, 0xE4, 0x08, 0x4B, 0x46,
0xB7, 0x72, 0xF6, 0xA5, 0x86, 0xFB, 0x22, 0xC3, 0x59, 0x91, 0xFA, 0xEC, 0x43, 0x0D, 0xF1, 0xC5, 0x84, 0x53,
0x23, 0x7D, 0xD9, 0xE1, 0x9A, 0xC8, 0x6B, 0x16, 0xAF, 0x4E, 0xFC, 0x34, 0x41, 0xD7, 0x70, 0x5E, 0xA4, 0x38,
0x7B, 0x52, 0xA3, 0x7D, 0xB9, 0xE1, 0xB2, 0xC8, 0x75, 0x96, 0xA7, 0x2E, 0xFA, 0x9C, 0x43, 0x29, 0xF1, 0xDE,
0xC4, 0x58, 0x53, 0x7A, 0xBD, 0xE3, 0x31, 0x89, 0xD4, 0x66, 0xDF, 0x6A, 0xD8, 0x2F, 0x1A, 0x9C, 0x0B, 0x29,
0xC7, 0x5E, 0xD2, 0xB8, 0x5D, 0xB2, 0xB9, 0xB5, 0xB2, 0xF7, 0x35, 0x86, 0x97, 0x22, 0xEE, 0x99, 0x8C, 0x6A,
0xE5, 0xEF, 0x0B, 0x0C, 0x07, 0x45, 0xC2, 0xB3, 0x11, 0xB5, 0xCC, 0x77, 0x15, 0xE6, 0x8F, 0x0A, 0xE4, 0x07,
0x0B, 0x42, 0x87, 0x71, 0xA2, 0xA4, 0x79, 0xBB, 0x62, 0xF3, 0x69, 0x85, 0xEE, 0xE3, 0x0C, 0x49, 0xC5, 0xF6,
0xD3, 0x06, 0xDD, 0xC2, 0xD9, 0x91, 0x9A, 0xEC, 0x6B, 0x0D, 0xEF, 0x45, 0x8C, 0x33, 0x25, 0xD5, 0xDB, 0x1F,
0x1B, 0x48, 0x0B, 0x76, 0x87, 0x66, 0xE2, 0xAA, 0xC9, 0xBF, 0x16, 0xF0, 0x0E, 0xC4, 0x04, 0x53, 0x43, 0x7D,
0xF1, 0xE1, 0x84, 0x48, 0x63, 0x76, 0xA9, 0xE6, 0xFE, 0xCA, 0xC0, 0x57, 0x10, 0x3E, 0x8C, 0x10, 0x65, 0xCC,
0x2B, 0x15, 0xDF, 0x4F, 0x18, 0x34, 0x0A, 0x97, 0x47, 0x2E, 0xB2, 0x9C, 0x75, 0xA9, 0xE7, 0x3E, 0xCA, 0x90,
0x57, 0x2C, 0x3E, 0x9D, 0xD0, 0x69, 0x9C, 0x2E, 0xE9, 0xDC, 0x4E, 0xD9, 0xF4, 0x5A, 0xC7, 0x7B, 0x12, 0xA3,
0x4D, 0xB9, 0xF5, 0xB2, 0xC7, 0x35, 0x92, 0x97, 0x2D, 0xAE, 0x9D, 0xBC, 0x69, 0xB1, 0xEE, 0xF4, 0x4C, 0x47,
0x75, 0xF2, 0xA7, 0x05, 0xBA, 0x83, 0x33, 0x21, 0xD5, 0xD8, 0x5F, 0x1A, 0xB8, 0x0B, 0x32, 0x87, 0x55, 0xA2,
0xBF, 0x39, 0xB0, 0x12, 0xF4, 0x0D, 0x87, 0x45, 0xA2, 0xB3, 0x39, 0xB5, 0xD2, 0xF7, 0x1D, 0x86, 0x89, 0xA2,
0xE6, 0xF9, 0x8A, 0xC2, 0xE7, 0x11, 0x8A, 0x8C, 0x67, 0x25, 0xEA, 0x9B, 0x0F, 0x2B, 0x44, 0x1F, 0x73, 0x48,
0x25, 0xF6, 0x9B, 0x06, 0xEB, 0x42, 0xCF, 0x71, 0x94, 0x24, 0x6F, 0x5B, 0x6C, 0x3B, 0x6D, 0xD3, 0x6D, 0x9D,
0xED, 0xA9, 0x8D, 0xBE, 0xE5, 0xB0, 0x4B, 0x34, 0x37, 0x57, 0x56, 0xBE, 0xBE, 0xF0, 0x70, 0x44, 0x24, 0x33,
0x5B, 0x55, 0xFB, 0x7F, 0x03, 0x60, 0x01, 0xE8, 0x00, 0x4E, 0x80, 0x34, 0x60, 0x17, 0x68, 0x0E, 0xAE, 0x84,
0x7C, 0x63, 0x61, 0xE9, 0xE8, 0x4E, 0xCE, 0xB4, 0x54, 0x77, 0x7F, 0x66, 0xA0, 0x2A, 0xF8, 0x1F, 0x02, 0x88,
0x01, 0xA6, 0x80, 0x7A, 0xE0, 0x23, 0x08, 0x19, 0xC6, 0x8A, 0xD2, 0xE7, 0x1D, 0x8A, 0x89, 0xA7, 0x26, 0xFA,
0x9A, 0xC3, 0x2B, 0x11, 0xDF, 0x4C, 0x58, 0x35, 0xFA, 0x97, 0x03, 0x2E, 0x81, 0xDC, 0x60, 0x59, 0xE8, 0x3A,
0xCE, 0x93, 0x14, 0x6D, 0xCF, 0x6D, 0x94, 0x2D, 0xAF, 0x5D, 0xBC, 0x39, 0xB1, 0xD2, 0xF4, 0x5D, 0x87, 0x79,
0xA2, 0xA2, 0xF9, 0xB9, 0x82, 0xF2, 0xE1, 0x85, 0x88, 0x63, 0x26, 0xA9, 0xDA, 0xFE, 0xDB, 0x00, 0x5B, 0x40,
0x3B, 0x70, 0x13, 0x64, 0x0D, 0xEB, 0x45, 0x8F, 0x73, 0x24, 0x25, 0xDB, 0x5B, 0x1B, 0x7B, 0x4B, 0x63, 0x77,
0x69, 0xE6, 0xAE, 0xCA, 0xFC, 0x57, 0x01, 0xFE, 0x80, 0x40, 0x60, 0x30, 0x28, 0x14, 0x1E, 0x8F, 0x48, 0x64,
0x36, 0xAB, 0x56, 0xFF, 0x7E, 0xC0, 0x20, 0x50, 0x18, 0x3C, 0x0A, 0x91, 0xC7, 0x2C, 0x52, 0x9D, 0xFD, 0xA9,
0x81, 0xBE, 0xE0, 0x70, 0x48, 0x24, 0x36, 0x9B, 0x56, 0xEB, 0x7E, 0xCF, 0x60, 0x54, 0x28, 0x3F, 0x5E, 0x90,
0x38, 0x6C, 0x12, 0xAD, 0xCD, 0xBD, 0x95, 0xB1, 0xAF, 0x34, 0x7C, 0x17, 0x61, 0xCE, 0xA8, 0x54, 0x7E, 0xBF,
0x60, 0x70, 0x28, 0x24, 0x1E, 0x9B, 0x48, 0x6B, 0x76, 0xAF, 0x66, 0xFC, 0x2A, 0xC1, 0xDF, 0x10, 0x58, 0x0C,
0x3A, 0x85, 0xD3, 0x23, 0x1D, 0xD9, 0xC9, 0x9A, 0xD6, 0xEB, 0x1E, 0xCF, 0x48, 0x54, 0x36, 0xBF, 0x56, 0xF0,
0x3E, 0xC4, 0x10, 0x53, 0x4C, 0x3D, 0xF5, 0xD1, 0x87, 0x1C, 0x62, 0x89, 0xE9, 0xA6, 0xCE, 0xFA, 0xD4, 0x43,
0x1F, 0x71, 0xC8, 0x24, 0x56, 0x9B, 0x7E, 0xEB, 0x60, 0x4F, 0x68, 0x34, 0x2E, 0x97, 0x5C, 0x6E, 0xB9, 0xEC,
0x72, 0xCD, 0xE5, 0x95, 0x8B, 0x2F, 0x27, 0x5C, 0x1A, 0xB9, 0xCB, 0x32, 0xD7, 0x55, 0x9E, 0xBF, 0x28, 0x70,
0x1E, 0xA4, 0x08, 0x7B, 0x46, 0xA3, 0x72, 0xF9, 0xE5, 0x82, 0xCB, 0x21, 0x97, 0x58, 0x6E, 0xBA, 0xAC, 0x73,
0x3D, 0xE5, 0xD1, 0x8B, 0x1C, 0x67, 0x49, 0xEA, 0xB6, 0xCF, 0x36, 0xD4, 0x16, 0xDF, 0x4E, 0xD8, 0x34, 0x5A,
0x97, 0x7B, 0x2E, 0xA3, 0x5C, 0x79, 0xF9, 0xE2, 0xC2, 0xC9, 0x91, 0x96, 0xEC, 0x6E, 0xCD, 0xEC, 0x55, 0x8D,
0xFF, 0x25, 0x80, 0x1B, 0x20, 0x0B, 0x58, 0x07, 0x7A, 0x82, 0xA3, 0x21, 0xB9, 0xD8, 0x72, 0xDA, 0xA5, 0x9B,
0x3B, 0x2B, 0x53, 0x5F, 0x7D, 0xF8, 0x21, 0x82, 0x98, 0x61, 0xAA, 0xA8, 0x7F, 0x3E, 0xA0, 0x10, 0x78, 0x0C,
0x22, 0x85, 0xD9, 0xA3, 0x1A, 0xF9, 0xCB, 0x02, 0xD7, 0x41, 0x9E, 0xB0, 0x68, 0x74, 0x2E, 0xA7, 0x5C, 0x7A,
0xB9, 0xE3, 0x32, 0xC9, 0xD5, 0x96, 0xDF, 0x2E, 0xD8, 0x1C, 0x5A, 0x89, 0xFB, 0x26, 0xC3, 0x5A, 0xD1, 0xFB,
0x1C, 0x43, 0x49, 0xF1, 0xF6, 0xC4, 0x46, 0xD3, 0x72, 0xDD, 0xE5, 0x99
};
public static readonly byte[] SyncMark =
@@ -191,19 +182,26 @@ namespace DiscImageChef.Decoders.CD
public static byte[] Scramble(byte[] sector)
{
if(sector == null || sector.Length < 2352) return sector;
if(sector == null ||
sector.Length < 2352)
return sector;
byte[] sync = new byte[12];
Array.Copy(sector, 0, sync, 0, 12);
if(!SyncMark.SequenceEqual(sync)) return sector;
if(!SyncMark.SequenceEqual(sync))
return sector;
byte[] scrambled = new byte[sector.Length];
for(int i = 0; i < 2352; i++) scrambled[i] = (byte)(sector[i] ^ ScrambleTable[i]);
byte[] scrambled = new byte[sector.Length];
if(sector.Length <= 2352) return scrambled;
for(int i = 0; i < 2352; i++)
scrambled[i] = (byte)(sector[i] ^ ScrambleTable[i]);
for(int i = 2352; i < sector.Length; i++) scrambled[i] = sector[i];
if(sector.Length <= 2352)
return scrambled;
for(int i = 2352; i < sector.Length; i++)
scrambled[i] = sector[i];
return scrambled;
}

View File

@@ -37,88 +37,23 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.CD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class Session
{
public struct CDSessionInfo
{
/// <summary>
/// Total size of returned session information minus this field
/// </summary>
public ushort DataLength;
/// <summary>
/// First track number in hex
/// </summary>
public byte FirstCompleteSession;
/// <summary>
/// Last track number in hex
/// </summary>
public byte LastCompleteSession;
/// <summary>
/// Track descriptors
/// </summary>
public TrackDataDescriptor[] TrackDescriptors;
}
public struct TrackDataDescriptor
{
/// <summary>
/// Byte 0
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 1, bits 7 to 4
/// Type of information in Q subchannel of block where this TOC entry was found
/// </summary>
public byte ADR;
/// <summary>
/// Byte 1, bits 3 to 0
/// Track attributes
/// </summary>
public byte CONTROL;
/// <summary>
/// Byte 2
/// First track number in last complete session
/// </summary>
public byte TrackNumber;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 7
/// First track number in last complete session start address in LBA or in MSF
/// </summary>
public uint TrackStartAddress;
}
public static CDSessionInfo? Decode(byte[] CDSessionInfoResponse)
{
if(CDSessionInfoResponse == null) return null;
if(CDSessionInfoResponse == null)
return null;
CDSessionInfo decoded = new CDSessionInfo
var decoded = new CDSessionInfo
{
DataLength = BigEndianBitConverter.ToUInt16(CDSessionInfoResponse, 0),
FirstCompleteSession = CDSessionInfoResponse[2],
LastCompleteSession = CDSessionInfoResponse[3]
FirstCompleteSession = CDSessionInfoResponse[2], LastCompleteSession = CDSessionInfoResponse[3]
};
decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 8];
@@ -128,6 +63,7 @@ namespace DiscImageChef.Decoders.CD
DicConsole.DebugWriteLine("CD Session Info decoder",
"Expected CDSessionInfo size ({0} bytes) is not received size ({1} bytes), not decoding",
decoded.DataLength + 2, CDSessionInfoResponse.Length);
return null;
}
@@ -138,6 +74,7 @@ namespace DiscImageChef.Decoders.CD
decoded.TrackDescriptors[i].CONTROL = (byte)(CDSessionInfoResponse[1 + i * 8 + 4] & 0x0F);
decoded.TrackDescriptors[i].TrackNumber = CDSessionInfoResponse[2 + i * 8 + 4];
decoded.TrackDescriptors[i].Reserved2 = CDSessionInfoResponse[3 + i * 8 + 4];
decoded.TrackDescriptors[i].TrackStartAddress =
BigEndianBitConverter.ToUInt32(CDSessionInfoResponse, 4 + i * 8 + 4);
}
@@ -147,18 +84,21 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(CDSessionInfo? CDSessionInfoResponse)
{
if(CDSessionInfoResponse == null) return null;
if(CDSessionInfoResponse == null)
return null;
CDSessionInfo response = CDSessionInfoResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendFormat("First complete session number: {0}", response.FirstCompleteSession).AppendLine();
sb.AppendFormat("Last complete session number: {0}", response.LastCompleteSession).AppendLine();
foreach(TrackDataDescriptor descriptor in response.TrackDescriptors)
{
sb.AppendFormat("First track number in last complete session: {0}", descriptor.TrackNumber)
.AppendLine();
sb.AppendFormat("First track number in last complete session: {0}", descriptor.TrackNumber).
AppendLine();
sb.AppendFormat("Track starts at LBA {0}, or MSF {1:X2}:{2:X2}:{3:X2}", descriptor.TrackStartAddress,
(descriptor.TrackStartAddress & 0x0000FF00) >> 8,
(descriptor.TrackStartAddress & 0x00FF0000) >> 16,
@@ -168,15 +108,19 @@ namespace DiscImageChef.Decoders.CD
{
case TocAdr.NoInformation:
sb.AppendLine("Q subchannel mode not given");
break;
case TocAdr.CurrentPosition:
sb.AppendLine("Q subchannel stores current position");
break;
case TocAdr.ISRC:
sb.AppendLine("Q subchannel stores ISRC");
break;
case TocAdr.MediaCatalogNumber:
sb.AppendLine("Q subchannel stores media catalog number");
break;
}
@@ -188,35 +132,41 @@ namespace DiscImageChef.Decoders.CD
{
case TocControl.TwoChanNoPreEmph:
sb.AppendLine("Stereo audio track with no pre-emphasis");
break;
case TocControl.TwoChanPreEmph:
sb.AppendLine("Stereo audio track with 50/15 μs pre-emphasis");
break;
case TocControl.FourChanNoPreEmph:
sb.AppendLine("Quadraphonic audio track with no pre-emphasis");
break;
case TocControl.FourChanPreEmph:
sb.AppendLine("Stereo audio track with 50/15 μs pre-emphasis");
break;
case TocControl.DataTrack:
sb.AppendLine("Data track, recorded uninterrupted");
break;
case TocControl.DataTrackIncremental:
sb.AppendLine("Data track, recorded incrementally");
break;
}
sb.AppendLine((descriptor.CONTROL & (byte)TocControl.CopyPermissionMask) ==
(byte)TocControl.CopyPermissionMask
? "Digital copy of track is permitted"
(byte)TocControl.CopyPermissionMask ? "Digital copy of track is permitted"
: "Digital copy of track is prohibited");
#if DEBUG
#if DEBUG
if(descriptor.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", descriptor.Reserved1).AppendLine();
if(descriptor.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", descriptor.Reserved2).AppendLine();
#endif
#endif
sb.AppendLine();
}
@@ -228,7 +178,36 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(byte[] CDSessionInfoResponse)
{
CDSessionInfo? decoded = Decode(CDSessionInfoResponse);
return Prettify(decoded);
}
public struct CDSessionInfo
{
/// <summary>Total size of returned session information minus this field</summary>
public ushort DataLength;
/// <summary>First track number in hex</summary>
public byte FirstCompleteSession;
/// <summary>Last track number in hex</summary>
public byte LastCompleteSession;
/// <summary>Track descriptors</summary>
public TrackDataDescriptor[] TrackDescriptors;
}
public struct TrackDataDescriptor
{
/// <summary>Byte 0 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found</summary>
public byte ADR;
/// <summary>Byte 1, bits 3 to 0 Track attributes</summary>
public byte CONTROL;
/// <summary>Byte 2 First track number in last complete session</summary>
public byte TrackNumber;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 7 First track number in last complete session start address in LBA or in MSF</summary>
public uint TrackStartAddress;
}
}
}

150
CD/TOC.cs
View File

@@ -37,89 +37,23 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.CD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ISO/IEC 61104: Compact disc video system - 12 cm CD-V
/// ISO/IEC 60908: Audio recording - Compact disc digital audio system
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ISO/IEC 61104: Compact
/// disc video system - 12 cm CD-V ISO/IEC 60908: Audio recording - Compact disc digital audio system
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class TOC
{
public struct CDTOC
{
/// <summary>
/// Total size of returned TOC minus this field
/// </summary>
public ushort DataLength;
/// <summary>
/// First track number in hex
/// </summary>
public byte FirstTrack;
/// <summary>
/// Last track number in hex
/// </summary>
public byte LastTrack;
/// <summary>
/// Track descriptors
/// </summary>
public CDTOCTrackDataDescriptor[] TrackDescriptors;
}
public struct CDTOCTrackDataDescriptor
{
/// <summary>
/// Byte 0
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 1, bits 7 to 4
/// Type of information in Q subchannel of block where this TOC entry was found
/// </summary>
public byte ADR;
/// <summary>
/// Byte 1, bits 3 to 0
/// Track attributes
/// </summary>
public byte CONTROL;
/// <summary>
/// Byte 2
/// Track number
/// </summary>
public byte TrackNumber;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 7
/// The track start address in LBA or in MSF
/// </summary>
public uint TrackStartAddress;
}
public static CDTOC? Decode(byte[] CDTOCResponse)
{
if(CDTOCResponse == null) return null;
if(CDTOCResponse == null)
return null;
CDTOC decoded = new CDTOC
var decoded = new CDTOC
{
DataLength = BigEndianBitConverter.ToUInt16(CDTOCResponse, 0),
FirstTrack = CDTOCResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(CDTOCResponse, 0), FirstTrack = CDTOCResponse[2],
LastTrack = CDTOCResponse[3]
};
@@ -130,6 +64,7 @@ namespace DiscImageChef.Decoders.CD
DicConsole.DebugWriteLine("CD TOC decoder",
"Expected CDTOC size ({0} bytes) is not received size ({1} bytes), not decoding",
decoded.DataLength + 2, CDTOCResponse.Length);
return null;
}
@@ -140,6 +75,7 @@ namespace DiscImageChef.Decoders.CD
decoded.TrackDescriptors[i].CONTROL = (byte)(CDTOCResponse[1 + i * 8 + 4] & 0x0F);
decoded.TrackDescriptors[i].TrackNumber = CDTOCResponse[2 + i * 8 + 4];
decoded.TrackDescriptors[i].Reserved2 = CDTOCResponse[3 + i * 8 + 4];
decoded.TrackDescriptors[i].TrackStartAddress =
BigEndianBitConverter.ToUInt32(CDTOCResponse, 4 + i * 8 + 4);
}
@@ -149,18 +85,23 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(CDTOC? CDTOCResponse)
{
if(CDTOCResponse == null) return null;
if(CDTOCResponse == null)
return null;
CDTOC response = CDTOCResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendFormat("First track number in first complete session: {0}", response.FirstTrack).AppendLine();
sb.AppendFormat("Last track number in last complete session: {0}", response.LastTrack).AppendLine();
foreach(CDTOCTrackDataDescriptor descriptor in response.TrackDescriptors)
{
if(descriptor.TrackNumber == 0xAA) sb.AppendLine("Track number: Lead-Out");
else sb.AppendFormat("Track number: {0}", descriptor.TrackNumber).AppendLine();
if(descriptor.TrackNumber == 0xAA)
sb.AppendLine("Track number: Lead-Out");
else
sb.AppendFormat("Track number: {0}", descriptor.TrackNumber).AppendLine();
sb.AppendFormat("Track starts at LBA {0}, or MSF {1:X2}:{2:X2}:{3:X2}", descriptor.TrackStartAddress,
(descriptor.TrackStartAddress & 0x0000FF00) >> 8,
(descriptor.TrackStartAddress & 0x00FF0000) >> 16,
@@ -170,21 +111,27 @@ namespace DiscImageChef.Decoders.CD
{
case TocAdr.NoInformation:
sb.AppendLine("Q subchannel mode not given");
break;
case TocAdr.TrackPointer:
sb.AppendLine("Q subchannel stores track pointer");
break;
case TocAdr.VideoTrackPointer:
sb.AppendLine("Q subchannel stores video track pointer");
break;
case TocAdr.ISRC:
sb.AppendLine("Q subchannel stores ISRC");
break;
case TocAdr.MediaCatalogNumber:
sb.AppendLine("Q subchannel stores media catalog number");
break;
default:
sb.AppendFormat("Q subchannel mode {0}", descriptor.ADR).AppendLine();
break;
}
@@ -196,35 +143,41 @@ namespace DiscImageChef.Decoders.CD
{
case TocControl.TwoChanNoPreEmph:
sb.AppendLine("Stereo audio track with no pre-emphasis");
break;
case TocControl.TwoChanPreEmph:
sb.AppendLine("Stereo audio track with 50/15 μs pre-emphasis");
break;
case TocControl.FourChanNoPreEmph:
sb.AppendLine("Quadraphonic audio track with no pre-emphasis");
break;
case TocControl.FourChanPreEmph:
sb.AppendLine("Quadraphonic audio track with 50/15 μs pre-emphasis");
break;
case TocControl.DataTrack:
sb.AppendLine("Data track, recorded uninterrupted");
break;
case TocControl.DataTrackIncremental:
sb.AppendLine("Data track, recorded incrementally");
break;
}
sb.AppendLine((descriptor.CONTROL & (byte)TocControl.CopyPermissionMask) ==
(byte)TocControl.CopyPermissionMask
? "Digital copy of track is permitted"
(byte)TocControl.CopyPermissionMask ? "Digital copy of track is permitted"
: "Digital copy of track is prohibited");
#if DEBUG
#if DEBUG
if(descriptor.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", descriptor.Reserved1).AppendLine();
if(descriptor.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", descriptor.Reserved2).AppendLine();
#endif
#endif
sb.AppendLine();
}
@@ -236,7 +189,36 @@ namespace DiscImageChef.Decoders.CD
public static string Prettify(byte[] CDTOCResponse)
{
CDTOC? decoded = Decode(CDTOCResponse);
return Prettify(decoded);
}
public struct CDTOC
{
/// <summary>Total size of returned TOC minus this field</summary>
public ushort DataLength;
/// <summary>First track number in hex</summary>
public byte FirstTrack;
/// <summary>Last track number in hex</summary>
public byte LastTrack;
/// <summary>Track descriptors</summary>
public CDTOCTrackDataDescriptor[] TrackDescriptors;
}
public struct CDTOCTrackDataDescriptor
{
/// <summary>Byte 0 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found</summary>
public byte ADR;
/// <summary>Byte 1, bits 3 to 0 Track attributes</summary>
public byte CONTROL;
/// <summary>Byte 2 Track number</summary>
public byte TrackNumber;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 7 The track start address in LBA or in MSF</summary>
public uint TrackStartAddress;
}
}
}

View File

@@ -35,47 +35,23 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class AACS
{
public struct HDLeadInCopyright
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 2052
/// HD DVD Lead-In Copyright Information
/// </summary>
/// <summary>Bytes 4 to 2052 HD DVD Lead-In Copyright Information</summary>
public byte[] CopyrightInformation;
}
}

View File

@@ -35,47 +35,23 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class ADIP
{
public struct ADIPInformation
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 259
/// ADIP, defined in DVD standards
/// </summary>
/// <summary>Bytes 4 to 259 ADIP, defined in DVD standards</summary>
public byte[] ADIP;
}
}

View File

@@ -35,47 +35,23 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class BCA
{
public struct BurstCuttingArea
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// Burst cutting area contents, 12 to 188 bytes
/// </summary>
/// <summary>Bytes 4 to end Burst cutting area contents, 12 to 188 bytes</summary>
public byte[] BCA;
}
}

View File

@@ -35,71 +35,35 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class CPRM
{
public struct DiscMediaIdentifier
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// Disc Media Identifier for CPRM
/// </summary>
/// <summary>Bytes 4 to end Disc Media Identifier for CPRM</summary>
public byte[] MediaIdentifier;
}
public struct DiscMediaKeyBlock
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// Disc Media Key Block for CPRM
/// </summary>
/// <summary>Bytes 4 to end Disc Media Key Block for CPRM</summary>
public byte[] MediaKeyBlock;
}
}

View File

@@ -36,147 +36,94 @@ using System.Text;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class CSS_CPRM
{
public struct LeadInCopyright
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Byte 4
/// Copy protection system type
/// </summary>
public CopyrightType CopyrightType;
/// <summary>
/// Byte 5
/// Bitmask of regions where this disc is playable
/// </summary>
public byte RegionInformation;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
public byte Reserved4;
}
public struct DiscKey
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 2052
/// Disc key for CSS, Album Identifier for CPPM
/// </summary>
public byte[] Key;
}
public static LeadInCopyright? DecodeLeadInCopyright(byte[] response)
{
if(response?.Length != 8) return null;
if(response?.Length != 8)
return null;
return new LeadInCopyright
{
DataLength = (ushort)((response[0] << 8) + response[1]),
Reserved1 = response[2],
Reserved2 = response[3],
CopyrightType = (CopyrightType)response[4],
DataLength = (ushort)((response[0] << 8) + response[1]), Reserved1 = response[2],
Reserved2 = response[3], CopyrightType = (CopyrightType)response[4],
RegionInformation = response[5],
Reserved3 = response[6],
Reserved4 = response[7]
Reserved3 = response[6], Reserved4 = response[7]
};
}
public static string PrettifyLeadInCopyright(LeadInCopyright? cmi)
{
if(cmi == null) return null;
if(cmi == null)
return null;
LeadInCopyright decoded = cmi.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
switch(decoded.CopyrightType)
{
case CopyrightType.NoProtection:
sb.AppendLine("Disc has no encryption.");
break;
case CopyrightType.CSS:
sb.AppendLine("Disc is encrypted using CSS or CPPM.");
break;
case CopyrightType.CPRM:
sb.AppendLine("Disc is encrypted using CPRM.");
break;
case CopyrightType.AACS:
sb.AppendLine("Disc is encrypted using AACS.");
break;
default:
sb.AppendFormat("Disc is encrypted using unknown algorithm with ID {0}.", decoded.CopyrightType);
break;
}
if(decoded.CopyrightType == 0) return sb.ToString();
if(decoded.CopyrightType == 0)
return sb.ToString();
if(decoded.RegionInformation == 0xFF) sb.AppendLine("Disc cannot be played in any region at all.");
else if(decoded.RegionInformation == 0x00) sb.AppendLine("Disc can be played in any region.");
if(decoded.RegionInformation == 0xFF)
sb.AppendLine("Disc cannot be played in any region at all.");
else if(decoded.RegionInformation == 0x00)
sb.AppendLine("Disc can be played in any region.");
else
{
sb.Append("Disc can be played in the following regions:");
if((decoded.RegionInformation & 0x01) != 0x01) sb.Append(" 0");
if((decoded.RegionInformation & 0x02) != 0x02) sb.Append(" 1");
if((decoded.RegionInformation & 0x04) != 0x04) sb.Append(" 2");
if((decoded.RegionInformation & 0x08) != 0x08) sb.Append(" 3");
if((decoded.RegionInformation & 0x10) != 0x10) sb.Append(" 4");
if((decoded.RegionInformation & 0x20) != 0x20) sb.Append(" 5");
if((decoded.RegionInformation & 0x40) != 0x40) sb.Append(" 6");
if((decoded.RegionInformation & 0x80) != 0x80) sb.Append(" 7");
if((decoded.RegionInformation & 0x01) != 0x01)
sb.Append(" 0");
if((decoded.RegionInformation & 0x02) != 0x02)
sb.Append(" 1");
if((decoded.RegionInformation & 0x04) != 0x04)
sb.Append(" 2");
if((decoded.RegionInformation & 0x08) != 0x08)
sb.Append(" 3");
if((decoded.RegionInformation & 0x10) != 0x10)
sb.Append(" 4");
if((decoded.RegionInformation & 0x20) != 0x20)
sb.Append(" 5");
if((decoded.RegionInformation & 0x40) != 0x40)
sb.Append(" 6");
if((decoded.RegionInformation & 0x80) != 0x80)
sb.Append(" 7");
}
return sb.ToString();
@@ -184,5 +131,35 @@ namespace DiscImageChef.Decoders.DVD
public static string PrettifyLeadInCopyright(byte[] response) =>
PrettifyLeadInCopyright(DecodeLeadInCopyright(response));
public struct LeadInCopyright
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Byte 4 Copy protection system type</summary>
public CopyrightType CopyrightType;
/// <summary>Byte 5 Bitmask of regions where this disc is playable</summary>
public byte RegionInformation;
/// <summary>Byte 6 Reserved</summary>
public byte Reserved3;
/// <summary>Byte 7 Reserved</summary>
public byte Reserved4;
}
public struct DiscKey
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 2052 Disc key for CSS, Album Identifier for CPPM</summary>
public byte[] Key;
}
}
}

View File

@@ -36,159 +36,88 @@ using System.Text;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class Cartridge
{
public struct MediumStatus
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Byte 4, bit 7
/// Medium is in a cartridge
/// </summary>
public bool Cartridge;
/// <summary>
/// Byte 4, bit 6
/// Medium has been taken out/inserted in a cartridge
/// </summary>
public bool OUT;
/// <summary>
/// Byte 4, bits 5 to 4
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Byte 4, bit 3
/// Media is write protected by reason stablished in RAMSWI
/// </summary>
public bool MSWI;
/// <summary>
/// Byte 4, bit 2
/// Media is write protected by cartridge
/// </summary>
public bool CWP;
/// <summary>
/// Byte 4, bit 1
/// Media is persistently write protected
/// </summary>
public bool PWP;
/// <summary>
/// Byte 4, bit 0
/// Reserved
/// </summary>
public bool Reserved4;
/// <summary>
/// Byte 5
/// Writable status depending on cartridge
/// </summary>
public byte DiscType;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
public byte Reserved5;
/// <summary>
/// Byte 7
/// Reason of specific write protection, only defined 0x01 as "bare disc wp", and 0xFF as unspecified. Rest reserved.
/// </summary>
public byte RAMSWI;
}
public static MediumStatus? Decode(byte[] response)
{
if(response?.Length != 8) return null;
if(response?.Length != 8)
return null;
return new MediumStatus
{
DataLength = (ushort)((response[0] << 8) + response[1]),
Reserved1 = response[2],
Reserved2 = response[3],
Cartridge = (response[4] & 0x80) == 0x80,
OUT = (response[4] & 0x40) == 0x40,
Reserved3 = (byte)((response[4] & 0x30) >> 4),
MSWI = (response[4] & 0x08) == 0x08,
CWP = (response[4] & 0x04) == 0x04,
PWP = (response[4] & 0x02) == 0x02,
Reserved4 = (response[4] & 0x01) == 0x01,
DiscType = response[5],
Reserved5 = response[6],
DataLength = (ushort)((response[0] << 8) + response[1]), Reserved1 = response[2],
Reserved2 = response[3], Cartridge = (response[4] & 0x80) == 0x80,
OUT = (response[4] & 0x40) == 0x40,
Reserved3 = (byte)((response[4] & 0x30) >> 4), MSWI = (response[4] & 0x08) == 0x08,
CWP = (response[4] & 0x04) == 0x04,
PWP = (response[4] & 0x02) == 0x02,
Reserved4 = (response[4] & 0x01) == 0x01,
DiscType = response[5], Reserved5 = response[6],
RAMSWI = response[7]
};
}
public static string Prettify(MediumStatus? status)
{
if(status == null) return null;
if(status == null)
return null;
MediumStatus decoded = status.Value;
StringBuilder sb = new StringBuilder();
MediumStatus decoded = status.Value;
var sb = new StringBuilder();
if(decoded.PWP) sb.AppendLine("Disc surface is set to write protected status");
if(decoded.PWP)
sb.AppendLine("Disc surface is set to write protected status");
if(decoded.Cartridge)
{
sb.AppendLine("Disc comes in a cartridge");
if(decoded.OUT) sb.AppendLine("Disc has been extracted from the cartridge");
if(decoded.CWP) sb.AppendLine("Cartridge is set to write protected");
if(decoded.OUT)
sb.AppendLine("Disc has been extracted from the cartridge");
if(decoded.CWP)
sb.AppendLine("Cartridge is set to write protected");
}
switch(decoded.DiscType)
{
case 0:
sb.AppendLine("Disc shall not be written without a cartridge");
break;
case 0x10:
sb.AppendLine("Disc may be written without a cartridge");
break;
default:
sb.AppendFormat("Unknown disc type id {0}", decoded.DiscType).AppendLine();
break;
}
if(!decoded.MSWI) return sb.ToString();
if(!decoded.MSWI)
return sb.ToString();
switch(decoded.RAMSWI)
{
case 0: break;
case 1:
sb.AppendLine("Disc is write inhibited because it has been extracted from the cartridge");
break;
case 0xFF:
sb.AppendLine("Disc is write inhibited for an unspecified reason");
break;
default:
sb.AppendFormat("Disc has unknown reason {0} for write inhibition", decoded.RAMSWI).AppendLine();
break;
}
@@ -196,5 +125,38 @@ namespace DiscImageChef.Decoders.DVD
}
public static string Prettify(byte[] response) => Prettify(Decode(response));
public struct MediumStatus
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Byte 4, bit 7 Medium is in a cartridge</summary>
public bool Cartridge;
/// <summary>Byte 4, bit 6 Medium has been taken out/inserted in a cartridge</summary>
public bool OUT;
/// <summary>Byte 4, bits 5 to 4 Reserved</summary>
public byte Reserved3;
/// <summary>Byte 4, bit 3 Media is write protected by reason stablished in RAMSWI</summary>
public bool MSWI;
/// <summary>Byte 4, bit 2 Media is write protected by cartridge</summary>
public bool CWP;
/// <summary>Byte 4, bit 1 Media is persistently write protected</summary>
public bool PWP;
/// <summary>Byte 4, bit 0 Reserved</summary>
public bool Reserved4;
/// <summary>Byte 5 Writable status depending on cartridge</summary>
public byte DiscType;
/// <summary>Byte 6 Reserved</summary>
public byte Reserved5;
/// <summary>
/// Byte 7 Reason of specific write protection, only defined 0x01 as "bare disc wp", and 0xFF as unspecified. Rest
/// reserved.
/// </summary>
public byte RAMSWI;
}
}
}

View File

@@ -37,176 +37,28 @@ using System.Text;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 272: 120 mm DVD Rewritable Disk (DVD-RAM)
/// ECMA 330: 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM)
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 272: 120 mm DVD
/// Rewritable Disk (DVD-RAM) ECMA 330: 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable
/// Disk (DVD-RAM)
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class DDS
{
public struct DiscDefinitionStructure
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 5
/// DDS Identifier = 0x0A0A
/// </summary>
public ushort Identifier;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Byte 7, bit 7
/// If set, formatting is in process
/// </summary>
public bool InProcess;
/// <summary>
/// Byte 7, bit 6
/// If set, formatting is using partial certification
/// Only in ECMA-272
/// </summary>
public bool PartialCertification;
/// <summary>
/// Byte 7, bit 5
/// If set, only a group is being formatted
/// Only in ECMA-272
/// </summary>
public bool FormattingOnlyAGroup;
/// <summary>
/// Byte 7, bits 4 to 2
/// Reserved
/// </summary>
public byte Reserved4;
/// <summary>
/// Byte 7, bit 1
/// If set, disk has been certified by a user
/// </summary>
public bool UserCertification;
/// <summary>
/// Byte 7, bit 0
/// If set, disk has been certified by a manufacturer
/// </summary>
public bool ManufacturerCertification;
/// <summary>
/// Bytes 8 to 11
/// How many times the DDS has been updated
/// </summary>
public uint UpdateCount;
/// <summary>
/// Bytes 12 to 13
/// How many groups the disk has
/// 24 for ECMA-272
/// 1 for ECMA-330
/// </summary>
public ushort Groups;
/// <summary>
/// Bytes 14 to 15
/// How many zones the disk has
/// Only in ECMA-330
/// </summary>
public ushort Zones;
/// <summary>
/// Bytes 14 to 19 in ECMA-272
/// Bytes 16 to 83 in ECMA-330
/// Reserved
/// </summary>
public byte[] Reserved;
/// <summary>
/// Bytes 20 to 43
/// Group certification flags
/// </summary>
public GroupCertificationFlag[] GroupCertificationFlags;
/// <summary>
/// Bytes 85 to 87
/// Location of first sector in the Primary Spare Area
/// </summary>
public uint SpareAreaFirstPSN;
/// <summary>
/// Bytes 89 to 91
/// Location of first sector in the Primary Spare Area
/// </summary>
public uint SpareAreaLastPSN;
/// <summary>
/// Bytes 93 to 95
/// PSN for LSN 0
/// </summary>
public uint LSN0Location;
/// <summary>
/// The starting LSN of each zone
/// </summary>
public uint[] StartLSNForZone;
}
public struct GroupCertificationFlag
{
/// <summary>
/// Bit 7
/// If set, formatting of this group is in process
/// </summary>
public bool InProcess;
/// <summary>
/// Bit 6
/// If set, formatting is using partial certification
/// </summary>
public bool PartialCertification;
/// <summary>
/// Bits 5 to 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Bit 1
/// If set, this group has been certified by user
/// </summary>
public bool UserCertification;
/// <summary>
/// Bit 0
/// Reserved
/// </summary>
public bool Reserved2;
}
public static DiscDefinitionStructure? Decode(byte[] response)
{
if(response?.Length != 2052) return null;
if(response?.Length != 2052)
return null;
DiscDefinitionStructure dds =
new DiscDefinitionStructure {Identifier = (ushort)((response[4] << 8) + response[5])};
var dds = new DiscDefinitionStructure
{
Identifier = (ushort)((response[4] << 8) + response[5])
};
if(dds.Identifier != 0x0A0A) return null;
if(dds.Identifier != 0x0A0A)
return null;
// Common to both DVD-RAM versions
dds.DataLength = (ushort)((response[0] << 8) + response[1]);
@@ -216,8 +68,10 @@ namespace DiscImageChef.Decoders.DVD
dds.InProcess |= (response[7] & 0x80) == 0x80;
dds.UserCertification |= (response[7] & 0x02) == 0x02;
dds.ManufacturerCertification |= (response[7] & 0x01) == 0x01;
dds.UpdateCount =
(uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]);
dds.Groups =
(ushort)((response[12] << 8) + response[13]);
@@ -230,6 +84,7 @@ namespace DiscImageChef.Decoders.DVD
dds.Reserved = new byte[6];
Array.Copy(response, 14, dds.Reserved, 0, 6);
dds.GroupCertificationFlags = new GroupCertificationFlag[24];
for(int i = 0; i < 24; i++)
{
dds.GroupCertificationFlags[i].InProcess |= (response[20 + i] & 0x80) == 0x80;
@@ -241,7 +96,8 @@ namespace DiscImageChef.Decoders.DVD
}
// ECMA-330
if(dds.Groups != 1) return dds;
if(dds.Groups != 1)
return dds;
{
dds.Reserved4 = (byte)((response[7] & 0x7C) >> 2);
@@ -263,23 +119,31 @@ namespace DiscImageChef.Decoders.DVD
public static string Prettify(DiscDefinitionStructure? dds)
{
if(dds == null) return null;
if(dds == null)
return null;
DiscDefinitionStructure decoded = dds.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
if(decoded.InProcess)
{
sb.AppendLine("Formatting in progress.");
if(decoded.Groups == 24)
{
if(decoded.PartialCertification) sb.AppendLine("Formatting is only using partial certification");
if(decoded.FormattingOnlyAGroup) sb.AppendLine("Only a group is being formatted");
if(decoded.PartialCertification)
sb.AppendLine("Formatting is only using partial certification");
if(decoded.FormattingOnlyAGroup)
sb.AppendLine("Only a group is being formatted");
}
}
if(decoded.UserCertification) sb.AppendLine("Disc has been certified by an user");
if(decoded.ManufacturerCertification) sb.AppendLine("Disc has been certified by a manufacturer");
if(decoded.UserCertification)
sb.AppendLine("Disc has been certified by an user");
if(decoded.ManufacturerCertification)
sb.AppendLine("Disc has been certified by a manufacturer");
sb.AppendFormat("DDS has been updated {0} times", decoded.UpdateCount).AppendLine();
@@ -289,6 +153,7 @@ namespace DiscImageChef.Decoders.DVD
if(decoded.GroupCertificationFlags[i].InProcess)
{
sb.AppendFormat("Group {0} is being formatted", i).AppendLine();
if(decoded.GroupCertificationFlags[i].PartialCertification)
sb.AppendFormat("Group {0} is being certified partially", i).AppendLine();
}
@@ -297,12 +162,15 @@ namespace DiscImageChef.Decoders.DVD
sb.AppendFormat("Group {0} has been certified by an user", i).AppendLine();
}
if(decoded.Groups != 1) return sb.ToString();
if(decoded.Groups != 1)
return sb.ToString();
{
sb.AppendFormat("Disc has {0} zones", decoded.Zones).AppendLine();
sb.AppendFormat("Primary Spare Area stats at PSN {0:X}h and ends at PSN {1:X}h, inclusively",
decoded.SpareAreaFirstPSN, decoded.SpareAreaLastPSN).AppendLine();
sb.AppendFormat("LSN 0 is at PSN {0:X}h", decoded.LSN0Location).AppendLine();
for(int i = 0; i < decoded.StartLSNForZone.Length; i++)
@@ -313,5 +181,65 @@ namespace DiscImageChef.Decoders.DVD
}
public static string Prettify(byte[] response) => Prettify(Decode(response));
public struct DiscDefinitionStructure
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 5 DDS Identifier = 0x0A0A</summary>
public ushort Identifier;
/// <summary>Byte 6 Reserved</summary>
public byte Reserved3;
/// <summary>Byte 7, bit 7 If set, formatting is in process</summary>
public bool InProcess;
/// <summary>Byte 7, bit 6 If set, formatting is using partial certification Only in ECMA-272</summary>
public bool PartialCertification;
/// <summary>Byte 7, bit 5 If set, only a group is being formatted Only in ECMA-272</summary>
public bool FormattingOnlyAGroup;
/// <summary>Byte 7, bits 4 to 2 Reserved</summary>
public byte Reserved4;
/// <summary>Byte 7, bit 1 If set, disk has been certified by a user</summary>
public bool UserCertification;
/// <summary>Byte 7, bit 0 If set, disk has been certified by a manufacturer</summary>
public bool ManufacturerCertification;
/// <summary>Bytes 8 to 11 How many times the DDS has been updated</summary>
public uint UpdateCount;
/// <summary>Bytes 12 to 13 How many groups the disk has 24 for ECMA-272 1 for ECMA-330</summary>
public ushort Groups;
/// <summary>Bytes 14 to 15 How many zones the disk has Only in ECMA-330</summary>
public ushort Zones;
/// <summary>Bytes 14 to 19 in ECMA-272 Bytes 16 to 83 in ECMA-330 Reserved</summary>
public byte[] Reserved;
/// <summary>Bytes 20 to 43 Group certification flags</summary>
public GroupCertificationFlag[] GroupCertificationFlags;
/// <summary>Bytes 85 to 87 Location of first sector in the Primary Spare Area</summary>
public uint SpareAreaFirstPSN;
/// <summary>Bytes 89 to 91 Location of first sector in the Primary Spare Area</summary>
public uint SpareAreaLastPSN;
/// <summary>Bytes 93 to 95 PSN for LSN 0</summary>
public uint LSN0Location;
/// <summary>The starting LSN of each zone</summary>
public uint[] StartLSNForZone;
}
public struct GroupCertificationFlag
{
/// <summary>Bit 7 If set, formatting of this group is in process</summary>
public bool InProcess;
/// <summary>Bit 6 If set, formatting is using partial certification</summary>
public bool PartialCertification;
/// <summary>Bits 5 to 2 Reserved</summary>
public byte Reserved1;
/// <summary>Bit 1 If set, this group has been certified by user</summary>
public bool UserCertification;
/// <summary>Bit 0 Reserved</summary>
public bool Reserved2;
}
}
}

View File

@@ -35,47 +35,23 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class DMI
{
public struct DiscManufacturingInformation
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 2052
/// Disc Manufacturing Information
/// </summary>
/// <summary>Bytes 4 to 2052 Disc Manufacturing Information</summary>
public byte[] DMI;
}
}

View File

@@ -38,238 +38,111 @@ namespace DiscImageChef.Decoders.DVD
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DiskCategory : byte
{
/// <summary>
/// DVD-ROM. Version 1 is ECMA-267 and ECMA-268.
/// </summary>
DVDROM = 0,
/// <summary>
/// DVD-RAM. Version 1 is ECMA-272. Version 6 is ECMA-330.
/// </summary>
DVDRAM = 1,
/// <summary>
/// DVD-R. Version 1 is ECMA-279. Version 5 is ECMA-359. Version 6 is ECMA-382.
/// </summary>
DVDR = 2,
/// <summary>
/// DVD-RW. Version 2 is ECMA-338. Version 3 is ECMA-384.
/// </summary>
DVDRW = 3,
/// <summary>
/// HD DVD-ROM
/// </summary>
HDDVDROM = 4,
/// <summary>
/// HD DVD-RAM
/// </summary>
HDDVDRAM = 5,
/// <summary>
/// HD DVD-R
/// </summary>
HDDVDR = 6,
/// <summary>
/// HD DVD-RW
/// </summary>
HDDVDRW = 7,
/// <summary>
/// UMD. Version 0 is ECMA-365.
/// </summary>
UMD = 8,
/// <summary>
/// DVD+RW. Version 1 is ECMA-274. Version 2 is ECMA-337. Version 3 is ECMA-371.
/// </summary>
DVDPRW = 9,
/// <summary>
/// DVD+R. Version 1 is ECMA-349.
/// </summary>
DVDPR = 10,
/// <summary>
/// DVD+RW DL. Version 1 is ECMA-374.
/// </summary>
DVDPRWDL = 13,
/// <summary>
/// DVD+R DL. Version 1 is ECMA-364.
/// </summary>
DVDPRDL = 14,
/// <summary>
/// According to standards this value is reserved.
/// It's used by Nintendo GODs and WODs.
/// </summary>
/// <summary>DVD-ROM. Version 1 is ECMA-267 and ECMA-268.</summary>
DVDROM = 0, /// <summary>DVD-RAM. Version 1 is ECMA-272. Version 6 is ECMA-330.</summary>
DVDRAM = 1, /// <summary>DVD-R. Version 1 is ECMA-279. Version 5 is ECMA-359. Version 6 is ECMA-382.</summary>
DVDR = 2, /// <summary>DVD-RW. Version 2 is ECMA-338. Version 3 is ECMA-384.</summary>
DVDRW = 3, /// <summary>HD DVD-ROM</summary>
HDDVDROM = 4, /// <summary>HD DVD-RAM</summary>
HDDVDRAM = 5, /// <summary>HD DVD-R</summary>
HDDVDR = 6, /// <summary>HD DVD-RW</summary>
HDDVDRW = 7, /// <summary>UMD. Version 0 is ECMA-365.</summary>
UMD = 8, /// <summary>DVD+RW. Version 1 is ECMA-274. Version 2 is ECMA-337. Version 3 is ECMA-371.</summary>
DVDPRW = 9, /// <summary>DVD+R. Version 1 is ECMA-349.</summary>
DVDPR = 10, /// <summary>DVD+RW DL. Version 1 is ECMA-374.</summary>
DVDPRWDL = 13, /// <summary>DVD+R DL. Version 1 is ECMA-364.</summary>
DVDPRDL = 14, /// <summary>According to standards this value is reserved. It's used by Nintendo GODs and WODs.</summary>
Nintendo = 15
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum MaximumRateField : byte
{
/// <summary>
/// 2.52 Mbps
/// </summary>
TwoMbps = 0x00,
/// <summary>
/// 5.04 Mbps
/// </summary>
FiveMbps = 0x01,
/// <summary>
/// 10.08 Mbps
/// </summary>
TenMbps = 0x02,
/// <summary>
/// 20.16 Mbps
/// </summary>
TwentyMbps = 0x03,
/// <summary>
/// 30.24 Mbps
/// </summary>
ThirtyMbps = 0x04,
Unspecified = 0x0F
/// <summary>2.52 Mbps</summary>
TwoMbps = 0x00, /// <summary>5.04 Mbps</summary>
FiveMbps = 0x01, /// <summary>10.08 Mbps</summary>
TenMbps = 0x02, /// <summary>20.16 Mbps</summary>
TwentyMbps = 0x03, /// <summary>30.24 Mbps</summary>
ThirtyMbps = 0x04, Unspecified = 0x0F
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum LayerTypeFieldMask : byte
{
Embossed = 0x01,
Recordable = 0x02,
Rewritable = 0x04,
Reserved = 0x08
Embossed = 0x01, Recordable = 0x02, Rewritable = 0x04,
Reserved = 0x08
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum LinearDensityField : byte
{
/// <summary>
/// 0.267 μm/bit
/// </summary>
TwoSix = 0x00,
/// <summary>
/// 0.293 μm/bit
/// </summary>
TwoNine = 0x01,
/// <summary>
/// 0.409 to 0.435 μm/bit
/// </summary>
FourZero = 0x02,
/// <summary>
/// 0.280 to 0.291 μm/bit
/// </summary>
TwoEight = 0x04,
/// <summary>
/// 0.153 μm/bit
/// </summary>
OneFive = 0x05,
/// <summary>
/// 0.130 to 0.140 μm/bit
/// </summary>
OneThree = 0x06,
/// <summary>
/// 0.353 μm/bit
/// </summary>
/// <summary>0.267 μm/bit</summary>
TwoSix = 0x00, /// <summary>0.293 μm/bit</summary>
TwoNine = 0x01, /// <summary>0.409 to 0.435 μm/bit</summary>
FourZero = 0x02, /// <summary>0.280 to 0.291 μm/bit</summary>
TwoEight = 0x04, /// <summary>0.153 μm/bit</summary>
OneFive = 0x05, /// <summary>0.130 to 0.140 μm/bit</summary>
OneThree = 0x06, /// <summary>0.353 μm/bit</summary>
ThreeFive = 0x08
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum TrackDensityField : byte
{
/// <summary>
/// 0.74 μm/track
/// </summary>
Seven = 0x00,
/// <summary>
/// 0.80 μm/track
/// </summary>
Eight = 0x01,
/// <summary>
/// 0.615 μm/track
/// </summary>
Six = 0x02,
/// <summary>
/// 0.40 μm/track
/// </summary>
Four = 0x03,
/// <summary>
/// 0.34 μm/track
/// </summary>
/// <summary>0.74 μm/track</summary>
Seven = 0x00, /// <summary>0.80 μm/track</summary>
Eight = 0x01, /// <summary>0.615 μm/track</summary>
Six = 0x02, /// <summary>0.40 μm/track</summary>
Four = 0x03, /// <summary>0.34 μm/track</summary>
Three = 0x04
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum CopyrightType : byte
{
/// <summary>
/// There is no copy protection
/// </summary>
NoProtection = 0x00,
/// <summary>
/// Copy protection is CSS/CPPM
/// </summary>
CSS = 0x01,
/// <summary>
/// Copy protection is CPRM
/// </summary>
CPRM = 0x02,
/// <summary>
/// Copy protection is AACS
/// </summary>
/// <summary>There is no copy protection</summary>
NoProtection = 0x00, /// <summary>Copy protection is CSS/CPPM</summary>
CSS = 0x01, /// <summary>Copy protection is CPRM</summary>
CPRM = 0x02, /// <summary>Copy protection is AACS</summary>
AACS = 0x10
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum WPDiscTypes : byte
{
/// <summary>
/// Should not write without a cartridge
/// </summary>
DoNotWrite = 0x00,
/// <summary>
/// Can write without a cartridge
/// </summary>
CanWrite = 0x01,
Reserved1 = 0x02,
Reserved2 = 0x03
/// <summary>Should not write without a cartridge</summary>
DoNotWrite = 0x00, /// <summary>Can write without a cartridge</summary>
CanWrite = 0x01, Reserved1 = 0x02, Reserved2 = 0x03
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DVDSize
{
/// <summary>
/// 120 mm
/// </summary>
OneTwenty = 0,
/// <summary>
/// 80 mm
/// </summary>
/// <summary>120 mm</summary>
OneTwenty = 0, /// <summary>80 mm</summary>
Eighty = 1
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DVDRAMDiscType
{
/// <summary>
/// Shall not be recorded without a case
/// </summary>
Cased = 0,
/// <summary>
/// May be recorded without a case or within one
/// </summary>
/// <summary>Shall not be recorded without a case</summary>
Cased = 0, /// <summary>May be recorded without a case or within one</summary>
Uncased = 1
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DVDLayerStructure
{
Unspecified = 0,
InvertedStack = 1,
TwoP = 2,
Reserved = 3
Unspecified = 0, InvertedStack = 1, TwoP = 2,
Reserved = 3
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DVDRecordingSpeed
{
None = 0,
Two = 0,
Four = 0x10,
Six = 0x20,
Eight = 0x30,
Ten = 0x40,
None = 0, Two = 0, Four = 0x10,
Six = 0x20, Eight = 0x30, Ten = 0x40,
Twelve = 0x50
}
#endregion

View File

@@ -35,209 +35,95 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class Layers
{
public struct LayerCapacity
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 4, bit 7
/// If set, L0 capacity is immutable
/// </summary>
/// <summary>Byte 4, bit 7 If set, L0 capacity is immutable</summary>
public bool InitStatus;
/// <summary>
/// Byte 4, bits 6 to 0
/// Reserved
/// </summary>
/// <summary>Byte 4, bits 6 to 0 Reserved</summary>
public byte Reserved3;
/// <summary>
/// Byte 5
/// Reserved
/// </summary>
/// <summary>Byte 5 Reserved</summary>
public byte Reserved4;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
/// <summary>Byte 6 Reserved</summary>
public byte Reserved5;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
/// <summary>Byte 7 Reserved</summary>
public byte Reserved6;
/// <summary>
/// Byte 8 to 11
/// L0 Data Area Capacity
/// </summary>
/// <summary>Byte 8 to 11 L0 Data Area Capacity</summary>
public uint Capacity;
}
public struct MiddleZoneStartAddress
{
/// <summary>
/// Bytes 0 to 1
/// Data length = 10
/// </summary>
/// <summary>Bytes 0 to 1 Data length = 10</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 4, bit 7
/// If set, L0 shifter middle area is immutable
/// </summary>
/// <summary>Byte 4, bit 7 If set, L0 shifter middle area is immutable</summary>
public bool InitStatus;
/// <summary>
/// Byte 4, bits 6 to 0
/// Reserved
/// </summary>
/// <summary>Byte 4, bits 6 to 0 Reserved</summary>
public byte Reserved3;
/// <summary>
/// Byte 5
/// Reserved
/// </summary>
/// <summary>Byte 5 Reserved</summary>
public byte Reserved4;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
/// <summary>Byte 6 Reserved</summary>
public byte Reserved5;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
/// <summary>Byte 7 Reserved</summary>
public byte Reserved6;
/// <summary>
/// Byte 8 to 11
/// Start LBA of Shifted Middle Area on L0
/// </summary>
/// <summary>Byte 8 to 11 Start LBA of Shifted Middle Area on L0</summary>
public uint ShiftedMiddleAreaStartAddress;
}
public struct JumpIntervalSize
{
/// <summary>
/// Bytes 0 to 1
/// Data length = 10
/// </summary>
/// <summary>Bytes 0 to 1 Data length = 10</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 4
/// Reserved
/// </summary>
/// <summary>Byte 4 Reserved</summary>
public byte Reserved3;
/// <summary>
/// Byte 5
/// Reserved
/// </summary>
/// <summary>Byte 5 Reserved</summary>
public byte Reserved4;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
/// <summary>Byte 6 Reserved</summary>
public byte Reserved5;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
/// <summary>Byte 7 Reserved</summary>
public byte Reserved6;
/// <summary>
/// Byte 8 to 11
/// Jump Interval size for the Regular Interval Layer Jump
/// </summary>
/// <summary>Byte 8 to 11 Jump Interval size for the Regular Interval Layer Jump</summary>
public uint Size;
}
public struct ManualLayerJumpAddress
{
/// <summary>
/// Bytes 0 to 1
/// Data length = 10
/// </summary>
/// <summary>Bytes 0 to 1 Data length = 10</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 4
/// Reserved
/// </summary>
/// <summary>Byte 4 Reserved</summary>
public byte Reserved3;
/// <summary>
/// Byte 5
/// Reserved
/// </summary>
/// <summary>Byte 5 Reserved</summary>
public byte Reserved4;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
/// <summary>Byte 6 Reserved</summary>
public byte Reserved5;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
/// <summary>Byte 7 Reserved</summary>
public byte Reserved6;
/// <summary>
/// Byte 8 to 11
/// LBA for the manual layer jump
/// </summary>
/// <summary>Byte 8 to 11 LBA for the manual layer jump</summary>
public uint LBA;
}
}

1642
DVD/PFI.cs

File diff suppressed because it is too large Load Diff

View File

@@ -35,47 +35,23 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class PRI
{
public struct PreRecordedInformation
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// Pre-recorded Information in Lead-in for writable media
/// </summary>
/// <summary>Bytes 4 to end Pre-recorded Information in Lead-in for writable media</summary>
public byte[] PRI;
}
}

View File

@@ -35,86 +35,41 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class RMD
{
public struct LastBorderOutRMD
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// RMD in last recorded Border-out
/// </summary>
/// <summary>Bytes 4 to end RMD in last recorded Border-out</summary>
public byte[] RMD;
}
public struct HDMediumStatus
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 4, bits 7 to 1
/// Reserved
/// </summary>
/// <summary>Byte 4, bits 7 to 1 Reserved</summary>
public byte Reserved3;
/// <summary>
/// Byte 4, bit 0
/// Test Zone has been extended
/// </summary>
/// <summary>Byte 4, bit 0 Test Zone has been extended</summary>
public bool ExtendedTestZone;
/// <summary>
/// Byte 5
/// Number of remaining RMDs in RDZ
/// </summary>
/// <summary>Byte 5 Number of remaining RMDs in RDZ</summary>
public byte RemainingRMDs;
/// <summary>
/// Bytes 6 to 7
/// Number of remaining RMDs in current RMZ
/// </summary>
/// <summary>Bytes 6 to 7 Number of remaining RMDs in current RMZ</summary>
public ushort CurrentRemainingRMDs;
}
}

View File

@@ -36,68 +36,22 @@ using System.Text;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class Spare
{
public struct SpareAreaInformation
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 7
/// Data length
/// </summary>
public uint UnusedPrimaryBlocks;
/// <summary>
/// Bytes 8 to 11
/// Data length
/// </summary>
public uint UnusedSupplementaryBlocks;
/// <summary>
/// Bytes 12 to 15
/// Data length
/// </summary>
public uint AllocatedSupplementaryBlocks;
}
public static SpareAreaInformation? Decode(byte[] response)
{
if(response?.Length != 16) return null;
if(response?.Length != 16)
return null;
return new SpareAreaInformation
{
DataLength = (ushort)((response[0] << 8) + response[1]),
Reserved1 = response[2],
DataLength = (ushort)((response[0] << 8) + response[1]), Reserved1 = response[2],
Reserved2 = response[3],
UnusedPrimaryBlocks =
(uint)((response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7]),
@@ -110,19 +64,37 @@ namespace DiscImageChef.Decoders.DVD
public static string Prettify(SpareAreaInformation? sai)
{
if(sai == null) return null;
if(sai == null)
return null;
SpareAreaInformation decoded = sai.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendFormat("{0} unused primary spare blocks", decoded.UnusedPrimaryBlocks).AppendLine();
sb.AppendFormat("{0} unused supplementary spare blocks", decoded.UnusedSupplementaryBlocks).AppendLine();
sb.AppendFormat("{0} allocated supplementary spare blocks", decoded.AllocatedSupplementaryBlocks)
.AppendLine();
sb.AppendFormat("{0} allocated supplementary spare blocks", decoded.AllocatedSupplementaryBlocks).
AppendLine();
return sb.ToString();
}
public static string Prettify(byte[] response) => Prettify(Decode(response));
public struct SpareAreaInformation
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 7 Data length</summary>
public uint UnusedPrimaryBlocks;
/// <summary>Bytes 8 to 11 Data length</summary>
public uint UnusedSupplementaryBlocks;
/// <summary>Bytes 12 to 15 Data length</summary>
public uint AllocatedSupplementaryBlocks;
}
}
}

View File

@@ -35,87 +35,39 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.DVD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// ECMA 365
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g ECMA 365
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class UDI
{
public struct UniqueDiscIdentifier
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>
/// Byte 4
/// Reserved
/// </summary>
/// <summary>Byte 4 Reserved</summary>
public byte Reserved3;
/// <summary>
/// Byte 5
/// Reserved
/// </summary>
/// <summary>Byte 5 Reserved</summary>
public byte Reserved4;
/// <summary>
/// Bytes 6 to 7
/// Random number
/// </summary>
/// <summary>Bytes 6 to 7 Random number</summary>
public ushort RandomNumber;
/// <summary>
/// Byte 8 to 11
/// Year
/// </summary>
/// <summary>Byte 8 to 11 Year</summary>
public uint Year;
/// <summary>
/// Byte 12 to 13
/// Month
/// </summary>
/// <summary>Byte 12 to 13 Month</summary>
public ushort Month;
/// <summary>
/// Byte 14 to 15
/// Day
/// </summary>
/// <summary>Byte 14 to 15 Day</summary>
public ushort Day;
/// <summary>
/// Byte 16 to 17
/// Hour
/// </summary>
/// <summary>Byte 16 to 17 Hour</summary>
public ushort Hour;
/// <summary>
/// Byte 18 to 19
/// Minute
/// </summary>
/// <summary>Byte 18 to 19 Minute</summary>
public ushort Minute;
/// <summary>
/// Byte 20 to 21
/// Second
/// </summary>
/// <summary>Byte 20 to 21 Second</summary>
public ushort Second;
}
}

View File

@@ -35,54 +35,33 @@ using System.Runtime.InteropServices;
namespace DiscImageChef.Decoders.Floppy
{
/// <summary>
/// Methods and structures for Commodore Amiga decoding
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Methods and structures for Commodore Amiga decoding</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class Amiga
{
public struct Sector
{
/// <summary>
/// Set to 0x00
/// </summary>
/// <summary>Set to 0x00</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] zero;
/// <summary>
/// Set to 0xA1
/// </summary>
/// <summary>Set to 0xA1</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] sync;
/// <summary>
/// Set to 0xFF
/// </summary>
/// <summary>Set to 0xFF</summary>
public byte amiga;
/// <summary>
/// Track number
/// </summary>
/// <summary>Track number</summary>
public byte track;
/// <summary>
/// Sector number
/// </summary>
/// <summary>Sector number</summary>
public byte sector;
/// <summary>
/// Remaining sectors til end of writing
/// </summary>
/// <summary>Remaining sectors til end of writing</summary>
public byte remaining;
/// <summary>
/// OS dependent tag
/// </summary>
/// <summary>OS dependent tag</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] label;
/// <summary>
/// Checksum from <see cref="amiga" /> to <see cref="label" />
/// </summary>
/// <summary>Checksum from <see cref="amiga" /> to <see cref="label" /></summary>
public uint headerChecksum;
/// <summary>
/// Checksum from <see cref="data" />
/// </summary>
/// <summary>Checksum from <see cref="data" /></summary>
public uint dataChecksum;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] data;

View File

@@ -40,150 +40,58 @@ using DiscImageChef.Console;
namespace DiscImageChef.Decoders.Floppy
{
/// <summary>
/// Methods and structures for Apple ][ floppy decoding
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Methods and structures for Apple ][ floppy decoding</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class Apple2
{
/// <summary>
/// GCR-encoded Apple ][ GCR floppy track
/// </summary>
public class RawTrack
{
/// <summary>
/// Track preamble, set to self-sync 0xFF, between 40 and 95 bytes
/// </summary>
public byte[] gap;
public RawSector[] sectors;
}
/// <summary>
/// GCR-encoded Apple ][ GCR floppy sector
/// </summary>
public class RawSector
{
/// <summary>
/// Address field
/// </summary>
public RawAddressField addressField;
/// <summary>
/// Data field
/// </summary>
public RawDataField dataField;
/// <summary>
/// Track preamble, set to self-sync 0xFF, between 14 and 24 bytes
/// </summary>
public byte[] gap;
/// <summary>
/// Track preamble, set to self-sync 0xFF, between 5 and 10 bytes
/// </summary>
public byte[] innerGap;
}
/// <summary>
/// GCR-encoded Apple ][ GCR floppy sector address field
/// </summary>
public class RawAddressField
{
/// <summary>
/// decodedChecksum = decodedVolume ^ decodedTrack ^ decodedSector
/// checksum[0] = (decodedChecksum >> 1) | 0xAA
/// checksum[1] = decodedChecksum | 0xAA
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] checksum;
/// <summary>
/// Always 0xDE, 0xAA, 0xEB
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] epilogue;
/// <summary>
/// Always 0xD5, 0xAA, 0x96
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
/// <summary>
/// Sector number encoded as:
/// sector[0] = (decodedSector >> 1) | 0xAA
/// sector[1] = decodedSector | 0xAA
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] sector;
/// <summary>
/// Track number encoded as:
/// track[0] = (decodedTrack >> 1) | 0xAA
/// track[1] = decodedTrack | 0xAA
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] track;
/// <summary>
/// Volume number encoded as:
/// volume[0] = (decodedVolume >> 1) | 0xAA
/// volume[1] = decodedVolume | 0xAA
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] volume;
}
/// <summary>
/// GCR-encoded Apple ][ GCR floppy sector data field
/// </summary>
public class RawDataField
{
public byte checksum;
/// <summary>
/// Encoded data bytes.
/// 410 bytes for 5to3 (aka DOS 3.2) format
/// 342 bytes for 6to2 (aka DOS 3.3) format
/// </summary>
public byte[] data;
/// <summary>
/// Always 0xDE, 0xAA, 0xEB
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] epilogue;
/// <summary>
/// Always 0xD5, 0xAA, 0xAD
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
}
static readonly byte[] ReadTable5and3 =
{
// 00h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 10h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 20h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 30h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 40h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 50h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 60h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 70h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 80h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 90h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// A0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x01, 0x02, 0x03,
// B0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x05, 0x06, 0xFF, 0xFF, 0x07, 0x08, 0xFF, 0x09, 0x0A, 0x0B,
// C0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// D0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0x0D, 0xFF, 0xFF, 0x0E, 0x0F, 0xFF, 0x10, 0x11, 0x12,
// E0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x13, 0x14, 0xFF, 0x15, 0x16, 0x17,
// F0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x18, 0x19, 0x1A, 0xFF, 0xFF, 0x1B, 0x1C, 0xFF, 0x1D, 0x1E, 0x1F
};
@@ -192,48 +100,64 @@ namespace DiscImageChef.Decoders.Floppy
{
// 00h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 10h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 20h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 30h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 40h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 50h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 60h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 70h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 80h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 90h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, 0x05, 0x06,
// A0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x08, 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
// B0h
0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
// C0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, 0x1D, 0x1E,
// D0h
0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x20, 0x21, 0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
// E0h
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, 0x2A, 0x2B, 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
// F0h
0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
};
/// <summary>
/// Decodes the 5and3 encoded data
/// </summary>
/// <summary>Decodes the 5and3 encoded data</summary>
/// <param name="data">5and3 encoded data.</param>
public static byte[] Decode5and3(byte[] data)
{
if(data == null || data.Length != 410) return null;
if(data == null ||
data.Length != 410)
return null;
byte[] buffer = new byte[data.Length];
byte carry = 0;
for(int i = 0; i < data.Length; i++)
{
carry ^= ReadTable5and3[data[i]];
@@ -241,6 +165,7 @@ namespace DiscImageChef.Decoders.Floppy
}
byte[] output = new byte[256];
for(int i = 0; i < 51; i++)
{
byte b1 = buffer[51 * 3 - i];
@@ -260,16 +185,17 @@ namespace DiscImageChef.Decoders.Floppy
return output;
}
/// <summary>
/// Decodes the 6and2 encoded data
/// </summary>
/// <summary>Decodes the 6and2 encoded data</summary>
/// <param name="data">6and2 encoded data.</param>
public static byte[] Decode6and2(byte[] data)
{
if(data == null || data.Length != 342) return null;
if(data == null ||
data.Length != 342)
return null;
byte[] buffer = new byte[data.Length];
byte carry = 0;
for(int i = 0; i < data.Length; i++)
{
carry ^= ReadTable6and2[data[i]];
@@ -277,6 +203,7 @@ namespace DiscImageChef.Decoders.Floppy
}
byte[] output = new byte[256];
for(uint i = 0; i < 256; i++)
{
output[i] = (byte)((buffer[86 + i] << 2) & 0xFF);
@@ -303,13 +230,17 @@ namespace DiscImageChef.Decoders.Floppy
public static byte[] DecodeSector(RawSector sector)
{
if(sector.addressField.prologue[0] != 0xD5 || sector.addressField.prologue[1] != 0xAA) return null;
if(sector.addressField.prologue[0] != 0xD5 ||
sector.addressField.prologue[1] != 0xAA)
return null;
// Pre DOS 3.3
if(sector.addressField.prologue[2] == 0xB5) return Decode5and3(sector.dataField.data);
if(sector.addressField.prologue[2] == 0xB5)
return Decode5and3(sector.dataField.data);
// DOS 3.3
return sector.addressField.prologue[2] == 0x96 ? Decode6and2(sector.dataField.data) : null;
// Unknown
// Not Apple ][ GCR?
@@ -322,7 +253,9 @@ namespace DiscImageChef.Decoders.Floppy
endOffset = offset;
// Not an Apple ][ GCR sector
if(data == null || data.Length < 363) return null;
if(data == null ||
data.Length < 363)
return null;
int position = offset;
@@ -331,49 +264,71 @@ namespace DiscImageChef.Decoders.Floppy
while(position < data.Length)
{
// Prologue found
if(data[position] == 0xD5 && data[position + 1] == 0xAA)
if(data[position] == 0xD5 &&
data[position + 1] == 0xAA)
{
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Prologue found at {0}", position);
// Epilogue not in correct position
if(data[position + 11] != 0xDE || data[position + 12] != 0xAA) return null;
if(data[position + 11] != 0xDE ||
data[position + 12] != 0xAA)
return null;
RawSector sector = new RawSector
var sector = new RawSector
{
addressField = new RawAddressField
{
prologue = new[] {data[position], data[position + 1], data[position + 2]},
volume = new[] {data[position + 3], data[position + 4]},
track = new[] {data[position + 5], data[position + 6]},
sector = new[] {data[position + 7], data[position + 8]},
checksum = new[] {data[position + 9], data[position + 10]},
prologue = new[]
{
data[position], data[position + 1], data[position + 2]
},
volume = new[]
{
data[position + 3], data[position + 4]
},
track = new[]
{
data[position + 5], data[position + 6]
},
sector = new[]
{
data[position + 7], data[position + 8]
},
checksum = new[]
{
data[position + 9], data[position + 10]
},
epilogue = new[]
{
data[position + 11], data[position + 12], data[position + 13]
}
{
data[position + 11], data[position + 12], data[position + 13]
}
}
};
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Volume {0}",
(((sector.addressField.volume[0] & 0x55) << 1) |
(sector.addressField.volume[1] & 0x55)) & 0xFF);
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Track {0}",
(((sector.addressField.track[0] & 0x55) << 1) |
(sector.addressField.track[1] & 0x55)) & 0xFF);
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Sector {0}",
(((sector.addressField.sector[0] & 0x55) << 1) |
(sector.addressField.sector[1] & 0x55)) & 0xFF);
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Checksum {0}",
(((sector.addressField.checksum[0] & 0x55) << 1) |
(sector.addressField.checksum[1] & 0x55)) & 0xFF);
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Epilogue {0:X2}{1:X2}{2:X2}",
sector.addressField.epilogue[0], sector.addressField.epilogue[1],
sector.addressField.epilogue[2]);
position += 14;
int syncCount = 0;
bool onSync = false;
MemoryStream gaps = new MemoryStream();
int syncCount = 0;
bool onSync = false;
var gaps = new MemoryStream();
while(data[position] == 0xFF)
{
@@ -384,16 +339,20 @@ namespace DiscImageChef.Decoders.Floppy
}
// Lost sync
if(!onSync) return null;
if(!onSync)
return null;
// Prologue not found
if(data[position] != 0xD5 || data[position + 1] != 0xAA) return null;
if(data[position] != 0xD5 ||
data[position + 1] != 0xAA)
return null;
sector.innerGap = gaps.ToArray();
sector.dataField = new RawDataField();
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Inner gap has {0} bytes",
sector.innerGap.Length);
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Prologue found at {0}", position);
sector.dataField.prologue = new byte[3];
sector.dataField.prologue[0] = data[position];
@@ -402,19 +361,24 @@ namespace DiscImageChef.Decoders.Floppy
position += 3;
gaps = new MemoryStream();
// Read data until epilogue is found
while(data[position + 1] != 0xDE || data[position + 2] != 0xAA)
while(data[position + 1] != 0xDE ||
data[position + 2] != 0xAA)
{
gaps.WriteByte(data[position]);
position++;
// No space left for epilogue
if(position + 4 > data.Length) return null;
if(position + 4 > data.Length)
return null;
}
sector.dataField.data = gaps.ToArray();
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Data has {0} bytes",
sector.dataField.data.Length);
sector.dataField.checksum = data[position];
sector.dataField.epilogue = new byte[3];
sector.dataField.epilogue[0] = data[position + 1];
@@ -423,8 +387,10 @@ namespace DiscImageChef.Decoders.Floppy
position += 4;
gaps = new MemoryStream();
// Read gap, if any
while(position < data.Length && data[position] == 0xFF)
while(position < data.Length &&
data[position] == 0xFF)
{
gaps.WriteByte(data[position]);
position++;
@@ -438,32 +404,41 @@ namespace DiscImageChef.Decoders.Floppy
}
sector.gap = gaps.ToArray();
// Return current position to be able to read separate sectors
endOffset = position;
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Got {0} bytes of gap", sector.gap.Length);
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Got {0} bytes of gap", sector.gap.Length);
DicConsole.DebugWriteLine("Apple ][ GCR Decoder", "Finished sector at {0}", position);
return sector;
}
if(data[position] == 0xFF) position++;
if(data[position] == 0xFF)
position++;
// Found data that is not sync or a prologue
else return null;
else
return null;
}
}
catch(IndexOutOfRangeException) { return null; }
catch(IndexOutOfRangeException)
{
return null;
}
return null;
}
public static byte[] MarshalAddressField(RawAddressField addressField)
{
if(addressField == null) return null;
if(addressField == null)
return null;
MemoryStream raw = new MemoryStream();
var raw = new MemoryStream();
raw.Write(addressField.prologue, 0, addressField.prologue.Length);
raw.Write(addressField.volume, 0, addressField.volume.Length);
raw.Write(addressField.track, 0, addressField.track.Length);
raw.Write(addressField.sector, 0, addressField.sector.Length);
raw.Write(addressField.volume, 0, addressField.volume.Length);
raw.Write(addressField.track, 0, addressField.track.Length);
raw.Write(addressField.sector, 0, addressField.sector.Length);
raw.Write(addressField.checksum, 0, addressField.checksum.Length);
raw.Write(addressField.epilogue, 0, addressField.epilogue.Length);
@@ -472,21 +447,22 @@ namespace DiscImageChef.Decoders.Floppy
public static byte[] MarshalSector(RawSector sector)
{
if(sector == null) return null;
if(sector == null)
return null;
MemoryStream raw = new MemoryStream();
var raw = new MemoryStream();
raw.Write(sector.addressField.prologue, 0, sector.addressField.prologue.Length);
raw.Write(sector.addressField.volume, 0, sector.addressField.volume.Length);
raw.Write(sector.addressField.track, 0, sector.addressField.track.Length);
raw.Write(sector.addressField.sector, 0, sector.addressField.sector.Length);
raw.Write(sector.addressField.volume, 0, sector.addressField.volume.Length);
raw.Write(sector.addressField.track, 0, sector.addressField.track.Length);
raw.Write(sector.addressField.sector, 0, sector.addressField.sector.Length);
raw.Write(sector.addressField.checksum, 0, sector.addressField.checksum.Length);
raw.Write(sector.addressField.epilogue, 0, sector.addressField.epilogue.Length);
raw.Write(sector.innerGap, 0, sector.innerGap.Length);
raw.Write(sector.dataField.prologue, 0, sector.dataField.prologue.Length);
raw.Write(sector.dataField.data, 0, sector.dataField.data.Length);
raw.Write(sector.innerGap, 0, sector.innerGap.Length);
raw.Write(sector.dataField.prologue, 0, sector.dataField.prologue.Length);
raw.Write(sector.dataField.data, 0, sector.dataField.data.Length);
raw.WriteByte(sector.dataField.checksum);
raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length);
raw.Write(sector.gap, 0, sector.gap.Length);
raw.Write(sector.gap, 0, sector.gap.Length);
return raw.ToArray();
}
@@ -498,13 +474,14 @@ namespace DiscImageChef.Decoders.Floppy
int position = offset;
bool firstSector = true;
bool onSync = false;
MemoryStream gaps = new MemoryStream();
var gaps = new MemoryStream();
int count = 0;
List<RawSector> sectors = new List<RawSector>();
byte[] trackNumber = new byte[2];
endOffset = offset;
while(position < data.Length && data[position] == 0xFF)
while(position < data.Length &&
data[position] == 0xFF)
{
gaps.WriteByte(data[position]);
count++;
@@ -512,15 +489,19 @@ namespace DiscImageChef.Decoders.Floppy
onSync = count >= 5;
}
if(position >= data.Length) return null;
if(position >= data.Length)
return null;
if(!onSync) return null;
if(!onSync)
return null;
while(position < data.Length)
{
int oldPosition = position;
RawSector sector = MarshalSector(data, out position, position);
if(sector == null) break;
if(sector == null)
break;
if(firstSector)
{
@@ -529,9 +510,11 @@ namespace DiscImageChef.Decoders.Floppy
firstSector = false;
}
if(sector.addressField.track[0] != trackNumber[0] || sector.addressField.track[1] != trackNumber[1])
if(sector.addressField.track[0] != trackNumber[0] ||
sector.addressField.track[1] != trackNumber[1])
{
position = oldPosition;
break;
}
@@ -540,23 +523,33 @@ namespace DiscImageChef.Decoders.Floppy
(sector.addressField.sector[1] & 0x55)) & 0xFF,
(((sector.addressField.track[0] & 0x55) << 1) |
(sector.addressField.track[1] & 0x55)) & 0xFF);
sectors.Add(sector);
}
if(sectors.Count == 0) return null;
if(sectors.Count == 0)
return null;
var track = new RawTrack
{
gap = gaps.ToArray(), sectors = sectors.ToArray()
};
RawTrack track = new RawTrack {gap = gaps.ToArray(), sectors = sectors.ToArray()};
endOffset = position;
return track;
}
public static byte[] MarshalTrack(RawTrack track)
{
if(track == null) return null;
if(track == null)
return null;
MemoryStream raw = new MemoryStream();
var raw = new MemoryStream();
raw.Write(track.gap, 0, track.gap.Length);
foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) raw.Write(rawSector, 0, rawSector.Length);
foreach(byte[] rawSector in track.sectors.Select(MarshalSector))
raw.Write(rawSector, 0, rawSector.Length);
return raw.ToArray();
}
@@ -570,15 +563,18 @@ namespace DiscImageChef.Decoders.Floppy
int position = offset;
RawTrack track = MarshalTrack(data, out position, position);
while(track != null)
{
tracks.Add(track);
track = MarshalTrack(data, out position, position);
}
if(tracks.Count == 0) return null;
if(tracks.Count == 0)
return null;
endOffset = position;
return tracks;
}
@@ -586,10 +582,13 @@ namespace DiscImageChef.Decoders.Floppy
public static byte[] MarshalDisk(RawTrack[] disk)
{
if(disk == null) return null;
if(disk == null)
return null;
MemoryStream raw = new MemoryStream();
foreach(byte[] rawTrack in disk.Select(MarshalTrack)) raw.Write(rawTrack, 0, rawTrack.Length);
var raw = new MemoryStream();
foreach(byte[] rawTrack in disk.Select(MarshalTrack))
raw.Write(rawTrack, 0, rawTrack.Length);
return raw.ToArray();
}
@@ -600,5 +599,66 @@ namespace DiscImageChef.Decoders.Floppy
return sector != null && position != 0;
}
/// <summary>GCR-encoded Apple ][ GCR floppy track</summary>
public class RawTrack
{
/// <summary>Track preamble, set to self-sync 0xFF, between 40 and 95 bytes</summary>
public byte[] gap;
public RawSector[] sectors;
}
/// <summary>GCR-encoded Apple ][ GCR floppy sector</summary>
public class RawSector
{
/// <summary>Address field</summary>
public RawAddressField addressField;
/// <summary>Data field</summary>
public RawDataField dataField;
/// <summary>Track preamble, set to self-sync 0xFF, between 14 and 24 bytes</summary>
public byte[] gap;
/// <summary>Track preamble, set to self-sync 0xFF, between 5 and 10 bytes</summary>
public byte[] innerGap;
}
/// <summary>GCR-encoded Apple ][ GCR floppy sector address field</summary>
public class RawAddressField
{
/// <summary>
/// decodedChecksum = decodedVolume ^ decodedTrack ^ decodedSector checksum[0] = (decodedChecksum >> 1) | 0xAA
/// checksum[1] = decodedChecksum | 0xAA
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] checksum;
/// <summary>Always 0xDE, 0xAA, 0xEB</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] epilogue;
/// <summary>Always 0xD5, 0xAA, 0x96</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
/// <summary>Sector number encoded as: sector[0] = (decodedSector >> 1) | 0xAA sector[1] = decodedSector | 0xAA</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] sector;
/// <summary>Track number encoded as: track[0] = (decodedTrack >> 1) | 0xAA track[1] = decodedTrack | 0xAA</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] track;
/// <summary>Volume number encoded as: volume[0] = (decodedVolume >> 1) | 0xAA volume[1] = decodedVolume | 0xAA</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] volume;
}
/// <summary>GCR-encoded Apple ][ GCR floppy sector data field</summary>
public class RawDataField
{
public byte checksum;
/// <summary>Encoded data bytes. 410 bytes for 5to3 (aka DOS 3.2) format 342 bytes for 6to2 (aka DOS 3.3) format</summary>
public byte[] data;
/// <summary>Always 0xDE, 0xAA, 0xEB</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] epilogue;
/// <summary>Always 0xD5, 0xAA, 0xAD</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
}
}
}

View File

@@ -42,138 +42,35 @@ namespace DiscImageChef.Decoders.Floppy
// Information from:
// Inside Macintosh, Volume II, ISBN 0-201-17732-3
/// <summary>
/// Methods and structures for Apple Sony GCR floppy decoding
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
/// <summary>Methods and structures for Apple Sony GCR floppy decoding</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class AppleSony
{
/// <summary>
/// GCR-encoded Apple Sony GCR floppy track
/// </summary>
public class RawTrack
{
/// <summary>
/// Track preamble, set to self-sync 0xFF, 36 bytes
/// </summary>
public byte[] gap;
public RawSector[] sectors;
}
/// <summary>
/// GCR-encoded Apple Sony GCR floppy sector
/// </summary>
public class RawSector
{
/// <summary>
/// Address field
/// </summary>
public RawAddressField addressField;
/// <summary>
/// Data field
/// </summary>
public RawDataField dataField;
/// <summary>
/// Track preamble, set to self-sync 0xFF, unknown size
/// </summary>
public byte[] gap;
/// <summary>
/// Track preamble, set to self-sync 0xFF, 6 bytes
/// </summary>
public byte[] innerGap;
}
/// <summary>
/// GCR-encoded Apple Sony GCR floppy sector address field
/// </summary>
public class RawAddressField
{
/// <summary>
/// Checksum
/// </summary>
public byte checksum;
/// <summary>
/// Always 0xDE, 0xAA
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] epilogue;
/// <summary>
/// Disk format
/// </summary>
public AppleEncodedFormat format;
/// <summary>
/// Always 0xD5, 0xAA, 0x96
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
/// <summary>
/// Encoded sector number
/// </summary>
public byte sector;
/// <summary>
/// Encoded side number
/// </summary>
public byte side;
/// <summary>
/// Encoded (decodedTrack &amp; 0x3F)
/// </summary>
public byte track;
}
/// <summary>
/// GCR-encoded Apple ][ GCR floppy sector data field
/// </summary>
public class RawDataField
{
/// <summary>
/// Checksum
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] checksum;
/// <summary>
/// Encoded data bytes.
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 698)]
public byte[] data;
/// <summary>
/// Always 0xDE, 0xAA
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] epilogue;
/// <summary>
/// Always 0xD5, 0xAA, 0xAD
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
/// <summary>
/// Spare, usually <see cref="RawAddressField.sector" />
/// </summary>
public byte spare;
}
public static byte[] DecodeSector(RawSector sector)
{
if(sector.addressField.prologue[0] != 0xD5 || sector.addressField.prologue[1] != 0xAA ||
sector.addressField.prologue[2] != 0x96) return null;
if(sector.addressField.prologue[0] != 0xD5 ||
sector.addressField.prologue[1] != 0xAA ||
sector.addressField.prologue[2] != 0x96)
return null;
byte[] bf1 = new byte[175];
byte[] bf2 = new byte[175];
byte[] bf3 = new byte[175];
byte[] nib_data = sector.dataField.data;
MemoryStream ms = new MemoryStream();
byte[] bf1 = new byte[175];
byte[] bf2 = new byte[175];
byte[] bf3 = new byte[175];
byte[] nib_data = sector.dataField.data;
var ms = new MemoryStream();
int j = 0;
byte w3 = 0;
for(int i = 0; i <= 174; i++)
{
byte w4 = nib_data[j++];
byte w1 = nib_data[j++];
byte w2 = nib_data[j++];
if(i != 174) w3 = nib_data[j++];
if(i != 174)
w3 = nib_data[j++];
bf1[i] = (byte)(((w1 & 0x3F) | ((w4 << 2) & 0xC0)) & 0x0F);
bf2[i] = (byte)(((w2 & 0x3F) | ((w4 << 4) & 0xC0)) & 0x0F);
@@ -184,13 +81,17 @@ namespace DiscImageChef.Decoders.Floppy
uint ck1 = 0;
uint ck2 = 0;
uint ck3 = 0;
while(true)
{
ck1 = (ck1 & 0xFF) << 1;
if((ck1 & 0x0100) > 0) ck1++;
if((ck1 & 0x0100) > 0)
ck1++;
byte carry = (byte)((bf1[j] ^ ck1) & 0xFF);
ck3 += carry;
if((ck1 & 0x0100) > 0)
{
ck3++;
@@ -201,6 +102,7 @@ namespace DiscImageChef.Decoders.Floppy
carry = (byte)((bf2[j] ^ ck3) & 0xFF);
ck2 += carry;
if(ck3 > 0xFF)
{
ck2++;
@@ -209,10 +111,12 @@ namespace DiscImageChef.Decoders.Floppy
ms.WriteByte(carry);
if(ms.Length == 524) break;
if(ms.Length == 524)
break;
carry = (byte)((bf3[j] ^ ck2) & 0xFF);
ck1 += carry;
if(ck2 > 0xFF)
{
ck1++;
@@ -235,7 +139,9 @@ namespace DiscImageChef.Decoders.Floppy
endOffset = offset;
// Not an Apple ][ GCR sector
if(data == null || data.Length < 363) return null;
if(data == null ||
data.Length < 363)
return null;
int position = offset;
@@ -244,29 +150,37 @@ namespace DiscImageChef.Decoders.Floppy
while(position < data.Length)
{
// Prologue found
if(data[position] == 0xD5 && data[position + 1] == 0xAA && data[position + 2] == 0x96)
if(data[position] == 0xD5 &&
data[position + 1] == 0xAA &&
data[position + 2] == 0x96)
{
// Epilogue not in correct position
if(data[position + 8] != 0xDE || data[position + 9] != 0xAA) return null;
if(data[position + 8] != 0xDE ||
data[position + 9] != 0xAA)
return null;
RawSector sector = new RawSector
var sector = new RawSector
{
addressField = new RawAddressField
{
prologue = new[] {data[position], data[position + 1], data[position + 2]},
track = data[position + 3],
sector = data[position + 4],
side = data[position + 5],
format = (AppleEncodedFormat)data[position + 6],
checksum = data[position + 7],
epilogue = new[] {data[position + 8], data[position + 9]}
prologue = new[]
{
data[position], data[position + 1], data[position + 2]
},
track = data[position + 3], sector = data[position + 4],
side = data[position + 5],
format = (AppleEncodedFormat)data[position + 6], checksum = data[position + 7],
epilogue = new[]
{
data[position + 8], data[position + 9]
}
}
};
position += 10;
int syncCount = 0;
bool onSync = false;
MemoryStream gaps = new MemoryStream();
int syncCount = 0;
bool onSync = false;
var gaps = new MemoryStream();
while(data[position] == 0xFF)
{
@@ -277,29 +191,40 @@ namespace DiscImageChef.Decoders.Floppy
}
// Lost sync
if(!onSync) return null;
if(!onSync)
return null;
// Prologue not found
if(data[position] != 0xDE || data[position + 1] != 0xAA || data[position + 2] != 0xAD)
if(data[position] != 0xDE ||
data[position + 1] != 0xAA ||
data[position + 2] != 0xAD)
return null;
sector.innerGap = gaps.ToArray();
sector.dataField = new RawDataField
{
prologue = new[] {data[position], data[position + 1], data[position + 2]},
spare = data[position + 3]
prologue = new[]
{
data[position], data[position + 1], data[position + 2]
},
spare = data[position + 3]
};
position += 4;
gaps = new MemoryStream();
// Read data until epilogue is found
while(data[position + 4] != 0xD5 || data[position + 5] != 0xAA)
while(data[position + 4] != 0xD5 ||
data[position + 5] != 0xAA)
{
gaps.WriteByte(data[position]);
position++;
// No space left for epilogue
if(position + 7 > data.Length) return null;
if(position + 7 > data.Length)
return null;
}
sector.dataField.data = gaps.ToArray();
@@ -314,8 +239,10 @@ namespace DiscImageChef.Decoders.Floppy
position += 7;
gaps = new MemoryStream();
// Read gap, if any
while(position < data.Length && data[position] == 0xFF)
while(position < data.Length &&
data[position] == 0xFF)
{
gaps.WriteByte(data[position]);
position++;
@@ -329,26 +256,35 @@ namespace DiscImageChef.Decoders.Floppy
}
sector.gap = gaps.ToArray();
// Return current position to be able to read separate sectors
endOffset = position;
return sector;
}
if(data[position] == 0xFF) position++;
if(data[position] == 0xFF)
position++;
// Found data that is not sync or a prologue
else return null;
else
return null;
}
}
catch(IndexOutOfRangeException) { return null; }
catch(IndexOutOfRangeException)
{
return null;
}
return null;
}
public static byte[] MarshalAddressField(RawAddressField addressField)
{
if(addressField == null) return null;
if(addressField == null)
return null;
MemoryStream raw = new MemoryStream();
var raw = new MemoryStream();
raw.Write(addressField.prologue, 0, addressField.prologue.Length);
raw.WriteByte(addressField.track);
raw.WriteByte(addressField.sector);
@@ -361,22 +297,23 @@ namespace DiscImageChef.Decoders.Floppy
public static byte[] MarshalSector(RawSector sector)
{
if(sector == null) return null;
if(sector == null)
return null;
MemoryStream raw = new MemoryStream();
var raw = new MemoryStream();
raw.Write(sector.addressField.prologue, 0, sector.addressField.prologue.Length);
raw.WriteByte(sector.addressField.track);
raw.WriteByte(sector.addressField.sector);
raw.WriteByte(sector.addressField.side);
raw.WriteByte((byte)sector.addressField.format);
raw.WriteByte(sector.addressField.checksum);
raw.Write(sector.innerGap, 0, sector.innerGap.Length);
raw.Write(sector.innerGap, 0, sector.innerGap.Length);
raw.Write(sector.dataField.prologue, 0, sector.dataField.prologue.Length);
raw.WriteByte(sector.dataField.spare);
raw.Write(sector.dataField.data, 0, sector.dataField.data.Length);
raw.Write(sector.dataField.data, 0, sector.dataField.data.Length);
raw.Write(sector.dataField.checksum, 0, sector.dataField.checksum.Length);
raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length);
raw.Write(sector.gap, 0, sector.gap.Length);
raw.Write(sector.gap, 0, sector.gap.Length);
return raw.ToArray();
}
@@ -388,14 +325,15 @@ namespace DiscImageChef.Decoders.Floppy
int position = offset;
bool firstSector = true;
bool onSync = false;
MemoryStream gaps = new MemoryStream();
var gaps = new MemoryStream();
int count = 0;
List<RawSector> sectors = new List<RawSector>();
byte trackNumber = 0;
byte sideNumber = 0;
endOffset = offset;
while(position < data.Length && data[position] == 0xFF)
while(position < data.Length &&
data[position] == 0xFF)
{
gaps.WriteByte(data[position]);
count++;
@@ -403,15 +341,19 @@ namespace DiscImageChef.Decoders.Floppy
onSync = count >= 5;
}
if(position >= data.Length) return null;
if(position >= data.Length)
return null;
if(!onSync) return null;
if(!onSync)
return null;
while(position < data.Length)
{
int oldPosition = position;
RawSector sector = MarshalSector(data, out position, position);
if(sector == null) break;
if(sector == null)
break;
if(firstSector)
{
@@ -420,29 +362,40 @@ namespace DiscImageChef.Decoders.Floppy
firstSector = false;
}
if(sector.addressField.track != trackNumber || sector.addressField.side != sideNumber)
if(sector.addressField.track != trackNumber ||
sector.addressField.side != sideNumber)
{
position = oldPosition;
break;
}
sectors.Add(sector);
}
if(sectors.Count == 0) return null;
if(sectors.Count == 0)
return null;
var track = new RawTrack
{
gap = gaps.ToArray(), sectors = sectors.ToArray()
};
RawTrack track = new RawTrack {gap = gaps.ToArray(), sectors = sectors.ToArray()};
endOffset = position;
return track;
}
public static byte[] MarshalTrack(RawTrack track)
{
if(track == null) return null;
if(track == null)
return null;
MemoryStream raw = new MemoryStream();
var raw = new MemoryStream();
raw.Write(track.gap, 0, track.gap.Length);
foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) raw.Write(rawSector, 0, rawSector.Length);
foreach(byte[] rawSector in track.sectors.Select(MarshalSector))
raw.Write(rawSector, 0, rawSector.Length);
return raw.ToArray();
}
@@ -456,15 +409,18 @@ namespace DiscImageChef.Decoders.Floppy
int position = offset;
RawTrack track = MarshalTrack(data, out position, position);
while(track != null)
{
tracks.Add(track);
track = MarshalTrack(data, out position, position);
}
if(tracks.Count == 0) return null;
if(tracks.Count == 0)
return null;
endOffset = position;
return tracks;
}
@@ -472,10 +428,13 @@ namespace DiscImageChef.Decoders.Floppy
public static byte[] MarshalDisk(RawTrack[] disk)
{
if(disk == null) return null;
if(disk == null)
return null;
MemoryStream raw = new MemoryStream();
foreach(byte[] rawTrack in disk.Select(MarshalTrack)) raw.Write(rawTrack, 0, rawTrack.Length);
var raw = new MemoryStream();
foreach(byte[] rawTrack in disk.Select(MarshalTrack))
raw.Write(rawTrack, 0, rawTrack.Length);
return raw.ToArray();
}
@@ -486,5 +445,66 @@ namespace DiscImageChef.Decoders.Floppy
return sector != null && position != 0;
}
/// <summary>GCR-encoded Apple Sony GCR floppy track</summary>
public class RawTrack
{
/// <summary>Track preamble, set to self-sync 0xFF, 36 bytes</summary>
public byte[] gap;
public RawSector[] sectors;
}
/// <summary>GCR-encoded Apple Sony GCR floppy sector</summary>
public class RawSector
{
/// <summary>Address field</summary>
public RawAddressField addressField;
/// <summary>Data field</summary>
public RawDataField dataField;
/// <summary>Track preamble, set to self-sync 0xFF, unknown size</summary>
public byte[] gap;
/// <summary>Track preamble, set to self-sync 0xFF, 6 bytes</summary>
public byte[] innerGap;
}
/// <summary>GCR-encoded Apple Sony GCR floppy sector address field</summary>
public class RawAddressField
{
/// <summary>Checksum</summary>
public byte checksum;
/// <summary>Always 0xDE, 0xAA</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] epilogue;
/// <summary>Disk format</summary>
public AppleEncodedFormat format;
/// <summary>Always 0xD5, 0xAA, 0x96</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
/// <summary>Encoded sector number</summary>
public byte sector;
/// <summary>Encoded side number</summary>
public byte side;
/// <summary>Encoded (decodedTrack &amp; 0x3F)</summary>
public byte track;
}
/// <summary>GCR-encoded Apple ][ GCR floppy sector data field</summary>
public class RawDataField
{
/// <summary>Checksum</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] checksum;
/// <summary>Encoded data bytes.</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 698)]
public byte[] data;
/// <summary>Always 0xDE, 0xAA</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] epilogue;
/// <summary>Always 0xD5, 0xAA, 0xAD</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] prologue;
/// <summary>Spare, usually <see cref="RawAddressField.sector" /></summary>
public byte spare;
}
}
}

View File

@@ -35,66 +35,39 @@ using System.Runtime.InteropServices;
namespace DiscImageChef.Decoders.Floppy
{
/// <summary>
/// Methods and structures for Commodore GCR floppy decoding
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Methods and structures for Commodore GCR floppy decoding</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class Commodore
{
/// <summary>
/// Decoded Commodore GCR sector header
/// </summary>
/// <summary>Decoded Commodore GCR sector header</summary>
public struct SectorHeader
{
/// <summary>
/// Always 0x08
/// </summary>
/// <summary>Always 0x08</summary>
public byte id;
/// <summary>
/// XOR of following fields
/// </summary>
/// <summary>XOR of following fields</summary>
public byte checksum;
/// <summary>
/// Sector number
/// </summary>
/// <summary>Sector number</summary>
public byte sector;
/// <summary>
/// Track number
/// </summary>
/// <summary>Track number</summary>
public byte track;
/// <summary>
/// Format ID, unknown meaning
/// </summary>
/// <summary>Format ID, unknown meaning</summary>
public ushort format;
/// <summary>
/// Filled with 0x0F
/// </summary>
/// <summary>Filled with 0x0F</summary>
public ushort fill;
}
/// <summary>
/// Decoded Commodore GCR sector data
/// </summary>
/// <summary>Decoded Commodore GCR sector data</summary>
public struct SectorData
{
/// <summary>
/// Always 0x07
/// </summary>
/// <summary>Always 0x07</summary>
public byte id;
/// <summary>
/// User data
/// </summary>
/// <summary>User data</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte data;
/// <summary>
/// XOR of <see cref="data" />
/// </summary>
/// <summary>XOR of <see cref="data" /></summary>
public byte checksum;
/// <summary>
/// Filled with 0x0F
/// </summary>
/// <summary>Filled with 0x0F</summary>
public ushort fill;
}
}

View File

@@ -34,73 +34,35 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.Floppy
{
/// <summary>
/// In-sector code for sector size
/// </summary>
/// <summary>In-sector code for sector size</summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum IBMSectorSizeCode : byte
{
/// <summary>
/// 128 bytes/sector
/// </summary>
EighthKilo = 0,
/// <summary>
/// 256 bytes/sector
/// </summary>
QuarterKilo = 1,
/// <summary>
/// 512 bytes/sector
/// </summary>
HalfKilo = 2,
/// <summary>
/// 1024 bytes/sector
/// </summary>
Kilo = 3,
/// <summary>
/// 2048 bytes/sector
/// </summary>
TwiceKilo = 4,
/// <summary>
/// 4096 bytes/sector
/// </summary>
FriceKilo = 5,
/// <summary>
/// 8192 bytes/sector
/// </summary>
TwiceFriceKilo = 6,
/// <summary>
/// 16384 bytes/sector
/// </summary>
/// <summary>128 bytes/sector</summary>
EighthKilo = 0, /// <summary>256 bytes/sector</summary>
QuarterKilo = 1, /// <summary>512 bytes/sector</summary>
HalfKilo = 2, /// <summary>1024 bytes/sector</summary>
Kilo = 3, /// <summary>2048 bytes/sector</summary>
TwiceKilo = 4, /// <summary>4096 bytes/sector</summary>
FriceKilo = 5, /// <summary>8192 bytes/sector</summary>
TwiceFriceKilo = 6, /// <summary>16384 bytes/sector</summary>
FricelyFriceKilo = 7
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum IBMIdType : byte
{
IndexMark = 0xFC,
AddressMark = 0xFE,
DataMark = 0xFB,
IndexMark = 0xFC, AddressMark = 0xFE, DataMark = 0xFB,
DeletedDataMark = 0xF8
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum AppleEncodedFormat : byte
{
/// <summary>
/// Disk is an Apple II 3.5" disk
/// </summary>
AppleII = 0x96,
/// <summary>
/// Disk is an Apple Lisa 3.5" disk
/// </summary>
Lisa = 0x97,
/// <summary>
/// Disk is an Apple Macintosh single-sided 3.5" disk
/// </summary>
MacSingleSide = 0x9A,
/// <summary>
/// Disk is an Apple Macintosh double-sided 3.5" disk
/// </summary>
/// <summary>Disk is an Apple II 3.5" disk</summary>
AppleII = 0x96, /// <summary>Disk is an Apple Lisa 3.5" disk</summary>
Lisa = 0x97, /// <summary>Disk is an Apple Macintosh single-sided 3.5" disk</summary>
MacSingleSide = 0x9A, /// <summary>Disk is an Apple Macintosh double-sided 3.5" disk</summary>
MacDoubleSide = 0xD9
}
}

View File

@@ -45,125 +45,76 @@ namespace DiscImageChef.Decoders.Floppy
// ECMA-147
// ECMA-100
/// <summary>
/// Methods and structures for ISO floppy decoding (also used by Atari ST and others)
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Methods and structures for ISO floppy decoding (also used by Atari ST and others)</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class ISO
{
/// <summary>
/// ISO floppy track, also used by Atari ST and others
/// </summary>
/// <summary>ISO floppy track, also used by Atari ST and others</summary>
public struct Track
{
/// <summary>
/// Start of track, 32 bytes set to 0x4E
/// </summary>
/// <summary>Start of track, 32 bytes set to 0x4E</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] innerGap;
/// <summary>
/// Track sectors
/// </summary>
/// <summary>Track sectors</summary>
public Sector[] sectors;
/// <summary>
/// Undefined size
/// </summary>
/// <summary>Undefined size</summary>
public byte[] gap;
}
/// <summary>
/// Raw demodulated format for IBM System 34 floppies
/// </summary>
/// <summary>Raw demodulated format for IBM System 34 floppies</summary>
public struct Sector
{
/// <summary>
/// Sector address mark
/// </summary>
/// <summary>Sector address mark</summary>
public AddressMark addressMark;
/// <summary>
/// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581
/// </summary>
/// <summary>22 bytes set to 0x4E, set to 0x22 on Commodore 1581</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
public byte[] innerGap;
/// <summary>
/// Sector data block
/// </summary>
/// <summary>Sector data block</summary>
public DataBlock dataBlock;
/// <summary>
/// Variable bytes set to 0x4E, ECMA defines 54
/// </summary>
/// <summary>Variable bytes set to 0x4E, ECMA defines 54</summary>
public byte[] outerGap;
}
/// <summary>
/// Sector address mark for IBM System 34 floppies, contains sync word
/// </summary>
/// <summary>Sector address mark for IBM System 34 floppies, contains sync word</summary>
public struct AddressMark
{
/// <summary>
/// 12 bytes set to 0
/// </summary>
/// <summary>12 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xA1
/// </summary>
/// <summary>3 bytes set to 0xA1</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] aone;
/// <summary>
/// Set to <see cref="IBMIdType.AddressMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.AddressMark" /></summary>
public IBMIdType type;
/// <summary>
/// Track number
/// </summary>
/// <summary>Track number</summary>
public byte track;
/// <summary>
/// Side number
/// </summary>
/// <summary>Side number</summary>
public byte side;
/// <summary>
/// Sector number
/// </summary>
/// <summary>Sector number</summary>
public byte sector;
/// <summary>
/// <see cref="IBMSectorSizeCode" />
/// </summary>
public IBMSectorSizeCode sectorSize;
/// <summary>
/// CRC16 from <see cref="aone" /> to end of <see cref="sectorSize" />
/// </summary>
/// <summary>CRC16 from <see cref="aone" /> to end of <see cref="sectorSize" /></summary>
public ushort crc;
}
/// <summary>
/// Sector data block for IBM System 34 floppies
/// </summary>
/// <summary>Sector data block for IBM System 34 floppies</summary>
public struct DataBlock
{
/// <summary>
/// 12 bytes set to 0
/// </summary>
/// <summary>12 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xA1
/// </summary>
/// <summary>3 bytes set to 0xA1</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] aone;
/// <summary>
/// Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" /></summary>
public IBMIdType type;
/// <summary>
/// User data
/// </summary>
/// <summary>User data</summary>
public byte[] data;
/// <summary>
/// CRC16 from <see cref="aone" /> to end of <see cref="data" />
/// </summary>
/// <summary>CRC16 from <see cref="aone" /> to end of <see cref="data" /></summary>
public ushort crc;
}
}

View File

@@ -45,156 +45,94 @@ namespace DiscImageChef.Decoders.Floppy
// ECMA-147
// ECMA-100
/// <summary>
/// Methods and structures for perpendicular MFM floppy decoding
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Methods and structures for perpendicular MFM floppy decoding</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class Perpendicular
{
/// <summary>
/// Perpendicular floppy track
/// </summary>
/// <summary>Perpendicular floppy track</summary>
public struct Track
{
/// <summary>
/// Start of track
/// </summary>
/// <summary>Start of track</summary>
public TrackPreamble trackStart;
/// <summary>
/// Track sectors
/// </summary>
/// <summary>Track sectors</summary>
public Sector[] sectors;
/// <summary>
/// Undefined size
/// </summary>
/// <summary>Undefined size</summary>
public byte[] gap;
}
/// <summary>
/// Raw demodulated format for perpendicular floppies
/// </summary>
/// <summary>Raw demodulated format for perpendicular floppies</summary>
public struct Sector
{
/// <summary>
/// Sector address mark
/// </summary>
/// <summary>Sector address mark</summary>
public AddressMark addressMark;
/// <summary>
/// 41 bytes set to 0x4E
/// </summary>
/// <summary>41 bytes set to 0x4E</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 41)]
public byte[] innerGap;
/// <summary>
/// Sector data block
/// </summary>
/// <summary>Sector data block</summary>
public DataBlock dataBlock;
/// <summary>
/// Variable-sized inter-sector gap, ECMA defines 83 bytes
/// </summary>
/// <summary>Variable-sized inter-sector gap, ECMA defines 83 bytes</summary>
public byte[] outerGap;
}
/// <summary>
/// Start of IBM PC MFM floppy track
/// Used by IBM PC, Apple Macintosh (high-density only), and a lot others
/// </summary>
/// <summary>Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others</summary>
public struct TrackPreamble
{
/// <summary>
/// Gap from index pulse, 80 bytes set to 0x4E
/// </summary>
/// <summary>Gap from index pulse, 80 bytes set to 0x4E</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)]
public byte[] gap;
/// <summary>
/// 12 bytes set to 0x00
/// </summary>
/// <summary>12 bytes set to 0x00</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xC2
/// </summary>
/// <summary>3 bytes set to 0xC2</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] ctwo;
/// <summary>
/// Set to <see cref="IBMIdType.IndexMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.IndexMark" /></summary>
public IBMIdType type;
/// <summary>
/// Gap until first sector, 50 bytes to 0x4E
/// </summary>
/// <summary>Gap until first sector, 50 bytes to 0x4E</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public byte[] gap1;
}
/// <summary>
/// Sector address mark for IBM System 34 floppies, contains sync word
/// </summary>
/// <summary>Sector address mark for IBM System 34 floppies, contains sync word</summary>
public struct AddressMark
{
/// <summary>
/// 12 bytes set to 0
/// </summary>
/// <summary>12 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xA1
/// </summary>
/// <summary>3 bytes set to 0xA1</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] aone;
/// <summary>
/// Set to <see cref="IBMIdType.AddressMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.AddressMark" /></summary>
public IBMIdType type;
/// <summary>
/// Track number
/// </summary>
/// <summary>Track number</summary>
public byte track;
/// <summary>
/// Side number
/// </summary>
/// <summary>Side number</summary>
public byte side;
/// <summary>
/// Sector number
/// </summary>
/// <summary>Sector number</summary>
public byte sector;
/// <summary>
/// <see cref="IBMSectorSizeCode" />
/// </summary>
public IBMSectorSizeCode sectorSize;
/// <summary>
/// CRC16 from <see cref="aone" /> to end of <see cref="sectorSize" />
/// </summary>
/// <summary>CRC16 from <see cref="aone" /> to end of <see cref="sectorSize" /></summary>
public ushort crc;
}
/// <summary>
/// Sector data block for IBM System 34 floppies
/// </summary>
/// <summary>Sector data block for IBM System 34 floppies</summary>
public struct DataBlock
{
/// <summary>
/// 12 bytes set to 0
/// </summary>
/// <summary>12 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xA1
/// </summary>
/// <summary>3 bytes set to 0xA1</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] aone;
/// <summary>
/// Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" /></summary>
public IBMIdType type;
/// <summary>
/// User data
/// </summary>
/// <summary>User data</summary>
public byte[] data;
/// <summary>
/// CRC16 from <see cref="aone" /> to end of <see cref="data" />
/// </summary>
/// <summary>CRC16 from <see cref="aone" /> to end of <see cref="data" /></summary>
public ushort crc;
}
}

View File

@@ -45,157 +45,94 @@ namespace DiscImageChef.Decoders.Floppy
// ECMA-147
// ECMA-100
/// <summary>
/// Methods and structures for IBM System 34 floppy decoding
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Methods and structures for IBM System 34 floppy decoding</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class System34
{
/// <summary>
/// Track format for IBM System 34 floppy
/// Used by IBM PC, Apple Macintosh (high-density only), and a lot others
/// </summary>
/// <summary>Track format for IBM System 34 floppy Used by IBM PC, Apple Macintosh (high-density only), and a lot others</summary>
public struct Track
{
/// <summary>
/// Start of track
/// </summary>
/// <summary>Start of track</summary>
public TrackPreamble trackStart;
/// <summary>
/// Track sectors
/// </summary>
/// <summary>Track sectors</summary>
public Sector[] sectors;
/// <summary>
/// Undefined size
/// </summary>
/// <summary>Undefined size</summary>
public byte[] gap;
}
/// <summary>
/// Start of IBM PC MFM floppy track
/// Used by IBM PC, Apple Macintosh (high-density only), and a lot others
/// </summary>
/// <summary>Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others</summary>
public struct TrackPreamble
{
/// <summary>
/// Gap from index pulse, 80 bytes set to 0x4E
/// </summary>
/// <summary>Gap from index pulse, 80 bytes set to 0x4E</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)]
public byte[] gap;
/// <summary>
/// 12 bytes set to 0x00
/// </summary>
/// <summary>12 bytes set to 0x00</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xC2
/// </summary>
/// <summary>3 bytes set to 0xC2</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] ctwo;
/// <summary>
/// Set to <see cref="IBMIdType.IndexMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.IndexMark" /></summary>
public IBMIdType type;
/// <summary>
/// Gap until first sector, 50 bytes to 0x4E
/// </summary>
/// <summary>Gap until first sector, 50 bytes to 0x4E</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)]
public byte[] gap1;
}
/// <summary>
/// Raw demodulated format for IBM System 34 floppies
/// </summary>
/// <summary>Raw demodulated format for IBM System 34 floppies</summary>
public struct Sector
{
/// <summary>
/// Sector address mark
/// </summary>
/// <summary>Sector address mark</summary>
public AddressMark addressMark;
/// <summary>
/// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581
/// </summary>
/// <summary>22 bytes set to 0x4E, set to 0x22 on Commodore 1581</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)]
public byte[] innerGap;
/// <summary>
/// Sector data block
/// </summary>
/// <summary>Sector data block</summary>
public DataBlock dataBlock;
/// <summary>
/// Variable bytes set to 0x4E, ECMA defines 54
/// </summary>
/// <summary>Variable bytes set to 0x4E, ECMA defines 54</summary>
public byte[] outerGap;
}
/// <summary>
/// Sector address mark for IBM System 34 floppies, contains sync word
/// </summary>
/// <summary>Sector address mark for IBM System 34 floppies, contains sync word</summary>
public struct AddressMark
{
/// <summary>
/// 12 bytes set to 0
/// </summary>
/// <summary>12 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xA1
/// </summary>
/// <summary>3 bytes set to 0xA1</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] aone;
/// <summary>
/// Set to <see cref="IBMIdType.AddressMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.AddressMark" /></summary>
public IBMIdType type;
/// <summary>
/// Track number
/// </summary>
/// <summary>Track number</summary>
public byte track;
/// <summary>
/// Side number
/// </summary>
/// <summary>Side number</summary>
public byte side;
/// <summary>
/// Sector number
/// </summary>
/// <summary>Sector number</summary>
public byte sector;
/// <summary>
/// <see cref="IBMSectorSizeCode" />
/// </summary>
public IBMSectorSizeCode sectorSize;
/// <summary>
/// CRC16 from <see cref="aone" /> to end of <see cref="sectorSize" />
/// </summary>
/// <summary>CRC16 from <see cref="aone" /> to end of <see cref="sectorSize" /></summary>
public ushort crc;
}
/// <summary>
/// Sector data block for IBM System 34 floppies
/// </summary>
/// <summary>Sector data block for IBM System 34 floppies</summary>
public struct DataBlock
{
/// <summary>
/// 12 bytes set to 0
/// </summary>
/// <summary>12 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// 3 bytes set to 0xA1
/// </summary>
/// <summary>3 bytes set to 0xA1</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] aone;
/// <summary>
/// Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" /></summary>
public IBMIdType type;
/// <summary>
/// User data
/// </summary>
/// <summary>User data</summary>
public byte[] data;
/// <summary>
/// CRC16 from <see cref="aone" /> to end of <see cref="data" />
/// </summary>
/// <summary>CRC16 from <see cref="aone" /> to end of <see cref="data" /></summary>
public ushort crc;
}
}

View File

@@ -45,140 +45,85 @@ namespace DiscImageChef.Decoders.Floppy
// ECMA-147
// ECMA-100
/// <summary>
/// Methods and structures for IBM System 3740 floppy decoding
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Methods and structures for IBM System 3740 floppy decoding</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class System3740
{
/// <summary>
/// Track format for IBM System 3740 floppy
/// </summary>
/// <summary>Track format for IBM System 3740 floppy</summary>
public struct Track
{
/// <summary>
/// Start of track
/// </summary>
/// <summary>Start of track</summary>
public TrackPreamble trackStart;
/// <summary>
/// Track sectors
/// </summary>
/// <summary>Track sectors</summary>
public Sector[] sectors;
/// <summary>
/// Undefined size
/// </summary>
/// <summary>Undefined size</summary>
public byte[] gap;
}
/// <summary>
/// Start of IBM PC FM floppy track
/// </summary>
/// <summary>Start of IBM PC FM floppy track</summary>
public struct TrackPreamble
{
/// <summary>
/// Gap from index pulse, 80 bytes set to 0xFF
/// </summary>
/// <summary>Gap from index pulse, 80 bytes set to 0xFF</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public byte[] gap;
/// <summary>
/// 6 bytes set to 0x00
/// </summary>
/// <summary>6 bytes set to 0x00</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] zero;
/// <summary>
/// Set to <see cref="IBMIdType.IndexMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.IndexMark" /></summary>
public IBMIdType type;
/// <summary>
/// Gap until first sector, 26 bytes to 0xFF
/// </summary>
/// <summary>Gap until first sector, 26 bytes to 0xFF</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
public byte[] gap1;
}
/// <summary>
/// Raw demodulated format for IBM System 3740 floppies
/// </summary>
/// <summary>Raw demodulated format for IBM System 3740 floppies</summary>
public struct Sector
{
/// <summary>
/// Sector address mark
/// </summary>
/// <summary>Sector address mark</summary>
public AddressMark addressMark;
/// <summary>
/// 11 bytes set to 0xFF
/// </summary>
/// <summary>11 bytes set to 0xFF</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
public byte[] innerGap;
/// <summary>
/// Sector data block
/// </summary>
/// <summary>Sector data block</summary>
public DataBlock dataBlock;
/// <summary>
/// Variable bytes set to 0xFF
/// </summary>
/// <summary>Variable bytes set to 0xFF</summary>
public byte[] outerGap;
}
/// <summary>
/// Sector address mark for IBM System 3740 floppies, contains sync word
/// </summary>
/// <summary>Sector address mark for IBM System 3740 floppies, contains sync word</summary>
public struct AddressMark
{
/// <summary>
/// 6 bytes set to 0
/// </summary>
/// <summary>6 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] zero;
/// <summary>
/// Set to <see cref="IBMIdType.AddressMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.AddressMark" /></summary>
public IBMIdType type;
/// <summary>
/// Track number
/// </summary>
/// <summary>Track number</summary>
public byte track;
/// <summary>
/// Side number
/// </summary>
/// <summary>Side number</summary>
public byte side;
/// <summary>
/// Sector number
/// </summary>
/// <summary>Sector number</summary>
public byte sector;
/// <summary>
/// <see cref="IBMSectorSizeCode" />
/// </summary>
public IBMSectorSizeCode sectorSize;
/// <summary>
/// CRC16 from <see cref="type" /> to end of <see cref="sectorSize" />
/// </summary>
/// <summary>CRC16 from <see cref="type" /> to end of <see cref="sectorSize" /></summary>
public ushort crc;
}
/// <summary>
/// Sector data block for IBM System 3740 floppies
/// </summary>
/// <summary>Sector data block for IBM System 3740 floppies</summary>
public struct DataBlock
{
/// <summary>
/// 12 bytes set to 0
/// </summary>
/// <summary>12 bytes set to 0</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] zero;
/// <summary>
/// Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" />
/// </summary>
/// <summary>Set to <see cref="IBMIdType.DataMark" /> or to <see cref="IBMIdType.DeletedDataMark" /></summary>
public IBMIdType type;
/// <summary>
/// User data
/// </summary>
/// <summary>User data</summary>
public byte[] data;
/// <summary>
/// CRC16 from <see cref="type" /> to end of <see cref="data" />
/// </summary>
/// <summary>CRC16 from <see cref="type" /> to end of <see cref="data" /></summary>
public ushort crc;
}
}

View File

@@ -35,352 +35,20 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders
{
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "NotAccessedField.Global"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class LisaTag
{
/// <summary>
/// LisaOS tag as stored on Apple Profile and FileWare disks (20 bytes)
/// </summary>
public struct ProfileTag
{
/// <summary>0x00, Lisa OS version number</summary>
public ushort Version;
/// <summary>0x02 bits 7 to 6, kind of info in this block</summary>
public byte Kind;
/// <summary>0x02 bits 5 to 0, reserved</summary>
public byte Reserved;
/// <summary>0x03, disk volume number</summary>
public byte Volume;
/// <summary>0x04, file ID</summary>
public short FileId;
/// <summary>
/// 0x06 bit 7, checksum valid?
/// </summary>
public bool ValidChk;
/// <summary>
/// 0x06 bits 6 to 0, used bytes in block
/// </summary>
public ushort UsedBytes;
/// <summary>
/// 0x08, 3 bytes, absolute page number
/// </summary>
public uint AbsPage;
/// <summary>
/// 0x0B, checksum of data
/// </summary>
public byte Checksum;
/// <summary>
/// 0x0C, relative page number
/// </summary>
public ushort RelPage;
/// <summary>
/// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block
/// </summary>
public uint NextBlock;
/// <summary>
/// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block
/// </summary>
public uint PrevBlock;
/// <summary>On-memory value for easy first block search.</summary>
public bool IsFirst;
/// <summary>On-memory value for easy last block search.</summary>
public bool IsLast;
/// <summary>
/// Converts this tag to Priam DataTower format
/// </summary>
public PriamTag ToPriam() =>
new PriamTag
{
AbsPage = AbsPage,
Checksum = Checksum,
FileId = FileId,
IsFirst = IsFirst,
IsLast = IsLast,
Kind = Kind,
NextBlock = IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF,
PrevBlock = IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF,
RelPage = RelPage,
UsedBytes = UsedBytes,
ValidChk = ValidChk,
Version = Version,
Volume = Volume
};
/// <summary>
/// Converts this tag to Sony format
/// </summary>
public SonyTag ToSony() =>
new SonyTag
{
FileId = FileId,
IsFirst = IsFirst,
IsLast = IsLast,
Kind = Kind,
NextBlock = (ushort)NextBlock,
PrevBlock = (ushort)PrevBlock,
RelPage = RelPage,
Version = Version,
Volume = Volume
};
/// <summary>
/// Gets a byte array representation of this tag
/// </summary>
public byte[] GetBytes()
{
byte[] tagBytes = new byte[20];
byte[] tmp = BigEndianBitConverter.GetBytes(Version);
Array.Copy(tmp, 0, tagBytes, 0, 2);
tagBytes[2] = (byte)(Kind << 6);
tagBytes[3] = Volume;
tmp = BigEndianBitConverter.GetBytes(FileId);
Array.Copy(tmp, 0, tagBytes, 4, 2);
tmp = BigEndianBitConverter.GetBytes((ushort)(UsedBytes & 0x7FFF));
Array.Copy(tmp, 0, tagBytes, 6, 2);
if(ValidChk) tagBytes[6] += 0x80;
tmp = BigEndianBitConverter.GetBytes(AbsPage);
Array.Copy(tmp, 1, tagBytes, 8, 3);
tagBytes[11] = Checksum;
tmp = BigEndianBitConverter.GetBytes(RelPage);
Array.Copy(tmp, 0, tagBytes, 12, 2);
tmp = BigEndianBitConverter.GetBytes(IsLast ? 0xFFFFFF : NextBlock);
Array.Copy(tmp, 1, tagBytes, 14, 3);
tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0xFFFFFF : PrevBlock);
Array.Copy(tmp, 1, tagBytes, 17, 3);
return tagBytes;
}
}
/// <summary>
/// LisaOS tag as stored on Priam DataTower disks (24 bytes)
/// </summary>
public struct PriamTag
{
/// <summary>0x00, Lisa OS version number</summary>
public ushort Version;
/// <summary>0x02 bits 7 to 6, kind of info in this block</summary>
public byte Kind;
/// <summary>0x02 bits 5 to 0, reserved</summary>
public byte Reserved;
/// <summary>0x03, disk volume number</summary>
public byte Volume;
/// <summary>0x04, file ID</summary>
public short FileId;
/// <summary>
/// 0x06 bit 7, checksum valid?
/// </summary>
public bool ValidChk;
/// <summary>
/// 0x06 bits 6 to 0, used bytes in block
/// </summary>
public ushort UsedBytes;
/// <summary>
/// 0x08, 3 bytes, absolute page number
/// </summary>
public uint AbsPage;
/// <summary>
/// 0x0B, checksum of data
/// </summary>
public byte Checksum;
/// <summary>
/// 0x0C, relative page number
/// </summary>
public ushort RelPage;
/// <summary>
/// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block
/// </summary>
public uint NextBlock;
/// <summary>
/// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block
/// </summary>
public uint PrevBlock;
/// <summary>
/// 0x14, disk size
/// </summary>
public uint DiskSize;
/// <summary>On-memory value for easy first block search.</summary>
public bool IsFirst;
/// <summary>On-memory value for easy last block search.</summary>
public bool IsLast;
/// <summary>
/// Converts this tag to Apple Profile format
/// </summary>
public ProfileTag ToProfile() =>
new ProfileTag
{
AbsPage = AbsPage,
Checksum = Checksum,
FileId = FileId,
IsFirst = IsFirst,
IsLast = IsLast,
Kind = Kind,
NextBlock = IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF,
PrevBlock = IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF,
RelPage = RelPage,
UsedBytes = UsedBytes,
ValidChk = ValidChk,
Version = Version,
Volume = Volume
};
/// <summary>
/// Converts this tag to Sony format
/// </summary>
public SonyTag ToSony() =>
new SonyTag
{
FileId = FileId,
IsFirst = IsFirst,
IsLast = IsLast,
Kind = Kind,
NextBlock = (ushort)(IsLast ? 0x7FF : NextBlock & 0x7FF),
PrevBlock = (ushort)(IsFirst ? 0x7FF : PrevBlock & 0x7FF),
RelPage = RelPage,
Version = Version,
Volume = Volume
};
/// <summary>
/// Gets a byte array representation of this tag
/// </summary>
public byte[] GetBytes()
{
byte[] tagBytes = new byte[24];
byte[] tmp = BigEndianBitConverter.GetBytes(Version);
Array.Copy(tmp, 0, tagBytes, 0, 2);
tagBytes[2] = (byte)(Kind << 6);
tagBytes[3] = Volume;
tmp = BigEndianBitConverter.GetBytes(FileId);
Array.Copy(tmp, 0, tagBytes, 4, 2);
tmp = BigEndianBitConverter.GetBytes((ushort)(UsedBytes & 0x7FFF));
Array.Copy(tmp, 0, tagBytes, 6, 2);
if(ValidChk) tagBytes[6] += 0x80;
tmp = BigEndianBitConverter.GetBytes(AbsPage);
Array.Copy(tmp, 1, tagBytes, 8, 3);
tagBytes[11] = Checksum;
tmp = BigEndianBitConverter.GetBytes(RelPage);
Array.Copy(tmp, 0, tagBytes, 12, 2);
tmp = BigEndianBitConverter.GetBytes(IsLast ? 0xFFFFFF : NextBlock);
Array.Copy(tmp, 1, tagBytes, 14, 3);
tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0xFFFFFF : PrevBlock);
Array.Copy(tmp, 1, tagBytes, 17, 3);
tmp = BigEndianBitConverter.GetBytes(DiskSize);
Array.Copy(tmp, 0, tagBytes, 20, 4);
return tagBytes;
}
}
/// <summary>
/// LisaOS tag as stored on Apple Sony disks (12 bytes)
/// </summary>
public struct SonyTag
{
/// <summary>0x00, Lisa OS version number</summary>
public ushort Version;
/// <summary>0x02 bits 7 to 6, kind of info in this block</summary>
public byte Kind;
/// <summary>0x02 bits 5 to 0, reserved</summary>
public byte Reserved;
/// <summary>0x03, disk volume number</summary>
public byte Volume;
/// <summary>0x04, file ID</summary>
public short FileId;
/// <summary>
/// 0x06, relative page number
/// </summary>
public ushort RelPage;
/// <summary>
/// 0x08, 3 bytes, next block, 0x7FF if it's last block, 0x8000 set if block is valid
/// </summary>
public ushort NextBlock;
/// <summary>
/// 0x0A, 3 bytes, previous block, 0x7FF if it's first block
/// </summary>
public ushort PrevBlock;
/// <summary>On-memory value for easy first block search.</summary>
public bool IsFirst;
/// <summary>On-memory value for easy last block search.</summary>
public bool IsLast;
/// <summary>
/// Converts this tag to Apple Profile format
/// </summary>
public ProfileTag ToProfile() =>
new ProfileTag
{
FileId = FileId,
IsFirst = IsFirst,
IsLast = IsLast,
Kind = Kind,
NextBlock = (uint)(IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF),
PrevBlock = (uint)(IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF),
RelPage = RelPage,
Version = Version,
Volume = Volume
};
/// <summary>
/// Converts this tag to Priam DataTower format
/// </summary>
public PriamTag ToPriam() =>
new PriamTag
{
FileId = FileId,
IsFirst = IsFirst,
IsLast = IsLast,
Kind = Kind,
NextBlock = (uint)(IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF),
PrevBlock = (uint)(IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF),
RelPage = RelPage,
Version = Version,
Volume = Volume
};
/// <summary>
/// Gets a byte array representation of this tag
/// </summary>
public byte[] GetBytes()
{
byte[] tagBytes = new byte[12];
byte[] tmp = BigEndianBitConverter.GetBytes(Version);
Array.Copy(tmp, 0, tagBytes, 0, 2);
tagBytes[2] = (byte)(Kind << 6);
tagBytes[3] = Volume;
tmp = BigEndianBitConverter.GetBytes(FileId);
Array.Copy(tmp, 0, tagBytes, 4, 2);
tmp = BigEndianBitConverter.GetBytes(RelPage);
Array.Copy(tmp, 0, tagBytes, 6, 2);
tmp = BigEndianBitConverter.GetBytes(IsLast ? 0x7FF : NextBlock);
Array.Copy(tmp, 1, tagBytes, 8, 2);
tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0x7FF : PrevBlock);
Array.Copy(tmp, 1, tagBytes, 10, 2);
return tagBytes;
}
}
public static SonyTag? DecodeSonyTag(byte[] tag)
{
if(tag == null || tag.Length != 12) return null;
if(tag == null ||
tag.Length != 12)
return null;
SonyTag snTag = new SonyTag
var snTag = new SonyTag
{
Version = BigEndianBitConverter.ToUInt16(tag, 0),
Kind = (byte)((tag[2] & 0xC0) >> 6),
Reserved = (byte)(tag[2] & 0x3F),
Volume = tag[3],
Version = BigEndianBitConverter.ToUInt16(tag, 0), Kind = (byte)((tag[2] & 0xC0) >> 6),
Reserved = (byte)(tag[2] & 0x3F), Volume = tag[3],
FileId = BigEndianBitConverter.ToInt16(tag, 4),
RelPage = BigEndianBitConverter.ToUInt16(tag, 6),
NextBlock = (ushort)(BigEndianBitConverter.ToUInt16(tag, 8) & 0x7FF),
@@ -395,9 +63,11 @@ namespace DiscImageChef.Decoders
public static ProfileTag? DecodeProfileTag(byte[] tag)
{
if(tag == null || tag.Length != 20) return null;
if(tag == null ||
tag.Length != 20)
return null;
ProfileTag phTag = new ProfileTag();
var phTag = new ProfileTag();
byte[] tmp = new byte[4];
@@ -438,9 +108,11 @@ namespace DiscImageChef.Decoders
public static PriamTag? DecodePriamTag(byte[] tag)
{
if(tag == null || tag.Length != 24) return null;
if(tag == null ||
tag.Length != 24)
return null;
PriamTag pmTag = new PriamTag();
var pmTag = new PriamTag();
byte[] tmp = new byte[4];
@@ -483,7 +155,8 @@ namespace DiscImageChef.Decoders
public static PriamTag? DecodeTag(byte[] tag)
{
if(tag == null) return null;
if(tag == null)
return null;
PriamTag pmTag;
@@ -492,7 +165,8 @@ namespace DiscImageChef.Decoders
case 12:
SonyTag? snTag = DecodeSonyTag(tag);
if(snTag == null) return null;
if(snTag == null)
return null;
pmTag = new PriamTag();
pmTag.AbsPage = 0;
@@ -515,7 +189,8 @@ namespace DiscImageChef.Decoders
case 20:
ProfileTag? phTag = DecodeProfileTag(tag);
if(phTag == null) return null;
if(phTag == null)
return null;
pmTag = new PriamTag();
pmTag.AbsPage = phTag.Value.AbsPage;
@@ -539,5 +214,243 @@ namespace DiscImageChef.Decoders
default: return null;
}
}
/// <summary>LisaOS tag as stored on Apple Profile and FileWare disks (20 bytes)</summary>
public struct ProfileTag
{
/// <summary>0x00, Lisa OS version number</summary>
public ushort Version;
/// <summary>0x02 bits 7 to 6, kind of info in this block</summary>
public byte Kind;
/// <summary>0x02 bits 5 to 0, reserved</summary>
public byte Reserved;
/// <summary>0x03, disk volume number</summary>
public byte Volume;
/// <summary>0x04, file ID</summary>
public short FileId;
/// <summary>0x06 bit 7, checksum valid?</summary>
public bool ValidChk;
/// <summary>0x06 bits 6 to 0, used bytes in block</summary>
public ushort UsedBytes;
/// <summary>0x08, 3 bytes, absolute page number</summary>
public uint AbsPage;
/// <summary>0x0B, checksum of data</summary>
public byte Checksum;
/// <summary>0x0C, relative page number</summary>
public ushort RelPage;
/// <summary>0x0E, 3 bytes, next block, 0xFFFFFF if it's last block</summary>
public uint NextBlock;
/// <summary>0x11, 3 bytes, previous block, 0xFFFFFF if it's first block</summary>
public uint PrevBlock;
/// <summary>On-memory value for easy first block search.</summary>
public bool IsFirst;
/// <summary>On-memory value for easy last block search.</summary>
public bool IsLast;
/// <summary>Converts this tag to Priam DataTower format</summary>
public PriamTag ToPriam() => new PriamTag
{
AbsPage = AbsPage, Checksum = Checksum, FileId = FileId, IsFirst = IsFirst,
IsLast = IsLast, Kind = Kind, NextBlock = IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF,
PrevBlock = IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF,
RelPage = RelPage, UsedBytes = UsedBytes,
ValidChk = ValidChk,
Version = Version,
Volume = Volume
};
/// <summary>Converts this tag to Sony format</summary>
public SonyTag ToSony() => new SonyTag
{
FileId = FileId, IsFirst = IsFirst, IsLast = IsLast, Kind = Kind,
NextBlock = (ushort)NextBlock, PrevBlock = (ushort)PrevBlock, RelPage = RelPage, Version = Version,
Volume = Volume
};
/// <summary>Gets a byte array representation of this tag</summary>
public byte[] GetBytes()
{
byte[] tagBytes = new byte[20];
byte[] tmp = BigEndianBitConverter.GetBytes(Version);
Array.Copy(tmp, 0, tagBytes, 0, 2);
tagBytes[2] = (byte)(Kind << 6);
tagBytes[3] = Volume;
tmp = BigEndianBitConverter.GetBytes(FileId);
Array.Copy(tmp, 0, tagBytes, 4, 2);
tmp = BigEndianBitConverter.GetBytes((ushort)(UsedBytes & 0x7FFF));
Array.Copy(tmp, 0, tagBytes, 6, 2);
if(ValidChk)
tagBytes[6] += 0x80;
tmp = BigEndianBitConverter.GetBytes(AbsPage);
Array.Copy(tmp, 1, tagBytes, 8, 3);
tagBytes[11] = Checksum;
tmp = BigEndianBitConverter.GetBytes(RelPage);
Array.Copy(tmp, 0, tagBytes, 12, 2);
tmp = BigEndianBitConverter.GetBytes(IsLast ? 0xFFFFFF : NextBlock);
Array.Copy(tmp, 1, tagBytes, 14, 3);
tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0xFFFFFF : PrevBlock);
Array.Copy(tmp, 1, tagBytes, 17, 3);
return tagBytes;
}
}
/// <summary>LisaOS tag as stored on Priam DataTower disks (24 bytes)</summary>
public struct PriamTag
{
/// <summary>0x00, Lisa OS version number</summary>
public ushort Version;
/// <summary>0x02 bits 7 to 6, kind of info in this block</summary>
public byte Kind;
/// <summary>0x02 bits 5 to 0, reserved</summary>
public byte Reserved;
/// <summary>0x03, disk volume number</summary>
public byte Volume;
/// <summary>0x04, file ID</summary>
public short FileId;
/// <summary>0x06 bit 7, checksum valid?</summary>
public bool ValidChk;
/// <summary>0x06 bits 6 to 0, used bytes in block</summary>
public ushort UsedBytes;
/// <summary>0x08, 3 bytes, absolute page number</summary>
public uint AbsPage;
/// <summary>0x0B, checksum of data</summary>
public byte Checksum;
/// <summary>0x0C, relative page number</summary>
public ushort RelPage;
/// <summary>0x0E, 3 bytes, next block, 0xFFFFFF if it's last block</summary>
public uint NextBlock;
/// <summary>0x11, 3 bytes, previous block, 0xFFFFFF if it's first block</summary>
public uint PrevBlock;
/// <summary>0x14, disk size</summary>
public uint DiskSize;
/// <summary>On-memory value for easy first block search.</summary>
public bool IsFirst;
/// <summary>On-memory value for easy last block search.</summary>
public bool IsLast;
/// <summary>Converts this tag to Apple Profile format</summary>
public ProfileTag ToProfile() => new ProfileTag
{
AbsPage = AbsPage, Checksum = Checksum, FileId = FileId, IsFirst = IsFirst,
IsLast = IsLast, Kind = Kind, NextBlock = IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF,
PrevBlock = IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF,
RelPage = RelPage, UsedBytes = UsedBytes,
ValidChk = ValidChk,
Version = Version,
Volume = Volume
};
/// <summary>Converts this tag to Sony format</summary>
public SonyTag ToSony() => new SonyTag
{
FileId = FileId, IsFirst = IsFirst, IsLast = IsLast, Kind = Kind,
NextBlock = (ushort)(IsLast ? 0x7FF : NextBlock & 0x7FF),
PrevBlock = (ushort)(IsFirst ? 0x7FF : PrevBlock & 0x7FF), RelPage = RelPage, Version = Version,
Volume = Volume
};
/// <summary>Gets a byte array representation of this tag</summary>
public byte[] GetBytes()
{
byte[] tagBytes = new byte[24];
byte[] tmp = BigEndianBitConverter.GetBytes(Version);
Array.Copy(tmp, 0, tagBytes, 0, 2);
tagBytes[2] = (byte)(Kind << 6);
tagBytes[3] = Volume;
tmp = BigEndianBitConverter.GetBytes(FileId);
Array.Copy(tmp, 0, tagBytes, 4, 2);
tmp = BigEndianBitConverter.GetBytes((ushort)(UsedBytes & 0x7FFF));
Array.Copy(tmp, 0, tagBytes, 6, 2);
if(ValidChk)
tagBytes[6] += 0x80;
tmp = BigEndianBitConverter.GetBytes(AbsPage);
Array.Copy(tmp, 1, tagBytes, 8, 3);
tagBytes[11] = Checksum;
tmp = BigEndianBitConverter.GetBytes(RelPage);
Array.Copy(tmp, 0, tagBytes, 12, 2);
tmp = BigEndianBitConverter.GetBytes(IsLast ? 0xFFFFFF : NextBlock);
Array.Copy(tmp, 1, tagBytes, 14, 3);
tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0xFFFFFF : PrevBlock);
Array.Copy(tmp, 1, tagBytes, 17, 3);
tmp = BigEndianBitConverter.GetBytes(DiskSize);
Array.Copy(tmp, 0, tagBytes, 20, 4);
return tagBytes;
}
}
/// <summary>LisaOS tag as stored on Apple Sony disks (12 bytes)</summary>
public struct SonyTag
{
/// <summary>0x00, Lisa OS version number</summary>
public ushort Version;
/// <summary>0x02 bits 7 to 6, kind of info in this block</summary>
public byte Kind;
/// <summary>0x02 bits 5 to 0, reserved</summary>
public byte Reserved;
/// <summary>0x03, disk volume number</summary>
public byte Volume;
/// <summary>0x04, file ID</summary>
public short FileId;
/// <summary>0x06, relative page number</summary>
public ushort RelPage;
/// <summary>0x08, 3 bytes, next block, 0x7FF if it's last block, 0x8000 set if block is valid</summary>
public ushort NextBlock;
/// <summary>0x0A, 3 bytes, previous block, 0x7FF if it's first block</summary>
public ushort PrevBlock;
/// <summary>On-memory value for easy first block search.</summary>
public bool IsFirst;
/// <summary>On-memory value for easy last block search.</summary>
public bool IsLast;
/// <summary>Converts this tag to Apple Profile format</summary>
public ProfileTag ToProfile() => new ProfileTag
{
FileId = FileId, IsFirst = IsFirst, IsLast = IsLast, Kind = Kind,
NextBlock = (uint)(IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF),
PrevBlock = (uint)(IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF), RelPage = RelPage, Version = Version,
Volume = Volume
};
/// <summary>Converts this tag to Priam DataTower format</summary>
public PriamTag ToPriam() => new PriamTag
{
FileId = FileId, IsFirst = IsFirst, IsLast = IsLast, Kind = Kind,
NextBlock = (uint)(IsLast ? 0xFFFFFF : NextBlock & 0xFFFFFF),
PrevBlock = (uint)(IsFirst ? 0xFFFFFF : PrevBlock & 0xFFFFFF), RelPage = RelPage, Version = Version,
Volume = Volume
};
/// <summary>Gets a byte array representation of this tag</summary>
public byte[] GetBytes()
{
byte[] tagBytes = new byte[12];
byte[] tmp = BigEndianBitConverter.GetBytes(Version);
Array.Copy(tmp, 0, tagBytes, 0, 2);
tagBytes[2] = (byte)(Kind << 6);
tagBytes[3] = Volume;
tmp = BigEndianBitConverter.GetBytes(FileId);
Array.Copy(tmp, 0, tagBytes, 4, 2);
tmp = BigEndianBitConverter.GetBytes(RelPage);
Array.Copy(tmp, 0, tagBytes, 6, 2);
tmp = BigEndianBitConverter.GetBytes(IsLast ? 0x7FF : NextBlock);
Array.Copy(tmp, 1, tagBytes, 8, 2);
tmp = BigEndianBitConverter.GetBytes(IsFirst ? 0x7FF : PrevBlock);
Array.Copy(tmp, 1, tagBytes, 10, 2);
return tagBytes;
}
}
}
}

View File

@@ -36,30 +36,28 @@ using System.Text;
namespace DiscImageChef.Decoders.MMC
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "UnassignedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global")]
public class CID
{
public byte Manufacturer;
public byte DeviceType;
public byte ApplicationID;
public byte CRC;
public byte DeviceType;
public byte Manufacturer;
public byte ManufacturingDate;
public string ProductName;
public byte ProductRevision;
public uint ProductSerialNumber;
public byte ManufacturingDate;
public byte CRC;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Decoders
{
public static CID DecodeCID(uint[] response)
{
if(response?.Length != 4) return null;
if(response?.Length != 4)
return null;
byte[] data = new byte[16];
@@ -77,17 +75,17 @@ namespace DiscImageChef.Decoders.MMC
public static CID DecodeCID(byte[] response)
{
if(response?.Length != 16) return null;
if(response?.Length != 16)
return null;
CID cid = new CID
var cid = new CID
{
Manufacturer = response[0],
DeviceType = (byte)(response[1] & 0x03),
ProductRevision = response[9],
ProductSerialNumber = BitConverter.ToUInt32(response, 10),
ManufacturingDate = response[14],
DeviceType = (byte)(response[1] & 0x03), ProductRevision = response[9],
ProductSerialNumber = BitConverter.ToUInt32(response, 10), ManufacturingDate = response[14],
CRC = (byte)((response[15] & 0xFE) >> 1)
};
byte[] tmp = new byte[6];
Array.Copy(response, 3, tmp, 0, 6);
cid.ProductName = StringHandlers.CToString(tmp);
@@ -97,85 +95,110 @@ namespace DiscImageChef.Decoders.MMC
public static string PrettifyCID(CID cid)
{
if(cid == null) return null;
if(cid == null)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("MultiMediaCard Device Identification Register:");
sb.AppendFormat("\tManufacturer: {0}", VendorString.Prettify(cid.Manufacturer)).AppendLine();
switch(cid.DeviceType)
{
case 0:
sb.AppendLine("\tRemovable device");
break;
case 1:
sb.AppendLine("\tBGA device");
break;
case 2:
sb.AppendLine("\tPOP device");
break;
}
sb.AppendFormat("\tApplication ID: {0}", cid.ApplicationID).AppendLine();
sb.AppendFormat("\tProduct name: {0}", cid.ProductName).AppendLine();
sb.AppendFormat("\tProduct revision: {0:X2}.{1:X2}", (cid.ProductRevision & 0xF0) >> 4,
cid.ProductRevision & 0x0F).AppendLine();
sb.AppendFormat("\tProduct serial number: {0}", cid.ProductSerialNumber).AppendLine();
string year = "";
switch(cid.ManufacturingDate & 0x0F)
{
case 0:
year = "1997 or 2013";
break;
case 1:
year = "1998 or 2014";
break;
case 2:
year = "1999 or 2015";
break;
case 3:
year = "2000 or 2016";
break;
case 4:
year = "2001 or 2017";
break;
case 5:
year = "2002 or 2018";
break;
case 6:
year = "2003 or 2019";
break;
case 7:
year = "2004 or 2020";
break;
case 8:
year = "2005 or 2021";
break;
case 9:
year = "2006 or 2022";
break;
case 10:
year = "2007 or 2023";
break;
case 11:
year = "2008 or 2024";
break;
case 12:
year = "2009 or 2025";
break;
case 13:
year = "2010";
break;
case 14:
year = "2011";
break;
case 15:
year = "2012";
break;
}
sb.AppendFormat("\tDevice manufactured month {0} of {1}", (cid.ManufacturingDate & 0xF0) >> 4, year)
.AppendLine();
sb.AppendFormat("\tDevice manufactured month {0} of {1}", (cid.ManufacturingDate & 0xF0) >> 4, year).
AppendLine();
sb.AppendFormat("\tCID CRC: 0x{0:X2}", cid.CRC).AppendLine();
return sb.ToString();

View File

@@ -36,55 +36,53 @@ using System.Text;
namespace DiscImageChef.Decoders.MMC
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public class CSD
{
public byte Structure;
public byte Version;
public byte TAAC;
public byte NSAC;
public byte Speed;
public ushort Classes;
public byte ReadBlockLength;
public bool ReadsPartialBlocks;
public bool WriteMisalignment;
public bool ReadMisalignment;
public bool ContentProtection;
public bool Copy;
public byte CRC;
public byte DefaultECC;
public bool DSRImplemented;
public ushort Size;
public byte ReadCurrentAtVddMin;
public byte ReadCurrentAtVddMax;
public byte WriteCurrentAtVddMin;
public byte WriteCurrentAtVddMax;
public byte SizeMultiplier;
public byte ECC;
public byte EraseGroupSize;
public byte EraseGroupSizeMultiplier;
public byte WriteProtectGroupSize;
public bool WriteProtectGroupEnable;
public byte DefaultECC;
public byte WriteSpeedFactor;
public byte WriteBlockLength;
public bool WritesPartialBlocks;
public bool ContentProtection;
public bool FileFormatGroup;
public bool Copy;
public bool PermanentWriteProtect;
public bool TemporaryWriteProtect;
public byte FileFormat;
public byte ECC;
public byte CRC;
public bool FileFormatGroup;
public byte NSAC;
public bool PermanentWriteProtect;
public byte ReadBlockLength;
public byte ReadCurrentAtVddMax;
public byte ReadCurrentAtVddMin;
public bool ReadMisalignment;
public bool ReadsPartialBlocks;
public ushort Size;
public byte SizeMultiplier;
public byte Speed;
public byte Structure;
public byte TAAC;
public bool TemporaryWriteProtect;
public byte Version;
public byte WriteBlockLength;
public byte WriteCurrentAtVddMax;
public byte WriteCurrentAtVddMin;
public bool WriteMisalignment;
public bool WriteProtectGroupEnable;
public byte WriteProtectGroupSize;
public bool WritesPartialBlocks;
public byte WriteSpeedFactor;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Decoders
{
public static CSD DecodeCSD(uint[] response)
{
if(response?.Length != 4) return null;
if(response?.Length != 4)
return null;
byte[] data = new byte[16];
@@ -102,21 +100,23 @@ namespace DiscImageChef.Decoders.MMC
public static CSD DecodeCSD(byte[] response)
{
if(response?.Length != 16) return null;
if(response?.Length != 16)
return null;
return new CSD
{
Structure = (byte)((response[0] & 0xC0) >> 6),
Version = (byte)((response[0] & 0x3C) >> 2),
TAAC = response[1],
NSAC = response[2],
TAAC = response[1], NSAC = response[2],
Speed = response[3],
Classes = (ushort)((response[4] << 4) + ((response[5] & 0xF0) >> 4)),
ReadBlockLength = (byte)(response[5] & 0x0F),
ReadsPartialBlocks = (response[6] & 0x80) == 0x80,
WriteMisalignment = (response[6] & 0x40) == 0x40,
ReadMisalignment = (response[6] & 0x20) == 0x20,
DSRImplemented = (response[6] & 0x10) == 0x10,
WriteMisalignment =
(response[6] & 0x40) == 0x40,
ReadMisalignment = (response[6] & 0x20) == 0x20,
DSRImplemented =
(response[6] & 0x10) == 0x10,
Size =
(ushort)(((response[6] & 0x03) << 10) + (response[7] << 2) + ((response[8] & 0xC0) >> 6)),
ReadCurrentAtVddMin = (byte)((response[8] & 0x38) >> 3),
@@ -145,27 +145,33 @@ namespace DiscImageChef.Decoders.MMC
public static string PrettifyCSD(CSD csd)
{
if(csd == null) return null;
if(csd == null)
return null;
double unitFactor = 0;
double multiplier = 0;
string unit = "";
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("MultiMediaCard Device Specific Data Register:");
switch(csd.Structure)
{
case 0:
sb.AppendLine("\tRegister version 1.0");
break;
case 1:
sb.AppendLine("\tRegister version 1.1");
break;
case 2:
sb.AppendLine("\tRegister version 1.2");
break;
case 3:
sb.AppendLine("\tRegister version is defined in Extended Device Specific Data Register");
break;
}
@@ -174,34 +180,42 @@ namespace DiscImageChef.Decoders.MMC
case 0:
unit = "ns";
unitFactor = 1;
break;
case 1:
unit = "ns";
unitFactor = 10;
break;
case 2:
unit = "ns";
unitFactor = 100;
break;
case 3:
unit = "μs";
unitFactor = 1;
break;
case 4:
unit = "μs";
unitFactor = 10;
break;
case 5:
unit = "μs";
unitFactor = 100;
break;
case 6:
unit = "ms";
unitFactor = 1;
break;
case 7:
unit = "ms";
unitFactor = 10;
break;
}
@@ -209,51 +223,67 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
multiplier = 0;
break;
case 1:
multiplier = 1;
break;
case 2:
multiplier = 1.2;
break;
case 3:
multiplier = 1.3;
break;
case 4:
multiplier = 1.5;
break;
case 5:
multiplier = 2;
break;
case 6:
multiplier = 2.5;
break;
case 7:
multiplier = 3;
break;
case 8:
multiplier = 3.5;
break;
case 9:
multiplier = 4;
break;
case 10:
multiplier = 4.5;
break;
case 11:
multiplier = 5;
break;
case 12:
multiplier = 5.5;
break;
case 13:
multiplier = 6;
break;
case 14:
multiplier = 7;
break;
case 15:
multiplier = 8;
break;
}
@@ -263,23 +293,29 @@ namespace DiscImageChef.Decoders.MMC
sb.AppendFormat("\tClock dependent part of data access is {0} clock cycles", csd.NSAC * 100).AppendLine();
unit = "MHz";
switch(csd.Speed & 0x07)
{
case 0:
unitFactor = 0.1;
break;
case 1:
unitFactor = 1;
break;
case 2:
unitFactor = 10;
break;
case 3:
unitFactor = 100;
break;
default:
unit = "unknown";
unitFactor = 0;
break;
}
@@ -287,51 +323,67 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
multiplier = 0;
break;
case 1:
multiplier = 1;
break;
case 2:
multiplier = 1.2;
break;
case 3:
multiplier = 1.3;
break;
case 4:
multiplier = 1.5;
break;
case 5:
multiplier = 2;
break;
case 6:
multiplier = 2.6;
break;
case 7:
multiplier = 3;
break;
case 8:
multiplier = 3.5;
break;
case 9:
multiplier = 4;
break;
case 10:
multiplier = 4.5;
break;
case 11:
multiplier = 5.2;
break;
case 12:
multiplier = 5.5;
break;
case 13:
multiplier = 6;
break;
case 14:
multiplier = 7;
break;
case 15:
multiplier = 8;
break;
}
@@ -339,20 +391,29 @@ namespace DiscImageChef.Decoders.MMC
sb.AppendFormat("\tDevice's clock frequency: {0}{1}", result, unit).AppendLine();
unit = "";
for(int cl = 0, mask = 1; cl <= 11; cl++, mask <<= 1)
if((csd.Classes & mask) == mask)
unit += $" {cl}";
sb.AppendFormat("\tDevice support command classes {0}", unit).AppendLine();
if(csd.ReadBlockLength == 15) sb.AppendLine("\tRead block length size is defined in extended CSD");
else sb.AppendFormat("\tRead block length is {0} bytes", Math.Pow(2, csd.ReadBlockLength)).AppendLine();
if(csd.ReadsPartialBlocks) sb.AppendLine("\tDevice allows reading partial blocks");
if(csd.ReadBlockLength == 15)
sb.AppendLine("\tRead block length size is defined in extended CSD");
else
sb.AppendFormat("\tRead block length is {0} bytes", Math.Pow(2, csd.ReadBlockLength)).AppendLine();
if(csd.WriteMisalignment) sb.AppendLine("\tWrite commands can cross physical block boundaries");
if(csd.ReadMisalignment) sb.AppendLine("\tRead commands can cross physical block boundaries");
if(csd.ReadsPartialBlocks)
sb.AppendLine("\tDevice allows reading partial blocks");
if(csd.DSRImplemented) sb.AppendLine("\tDevice implements configurable driver stage");
if(csd.WriteMisalignment)
sb.AppendLine("\tWrite commands can cross physical block boundaries");
if(csd.ReadMisalignment)
sb.AppendLine("\tRead commands can cross physical block boundaries");
if(csd.DSRImplemented)
sb.AppendLine("\tDevice implements configurable driver stage");
if(csd.Size == 0xFFF)
sb.AppendLine("\tDevice may be bigger than 2GiB and have its real size defined in the extended CSD");
@@ -361,36 +422,49 @@ namespace DiscImageChef.Decoders.MMC
sb.AppendFormat("\tDevice has {0} blocks", (int)result).AppendLine();
result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2) * Math.Pow(2, csd.ReadBlockLength);
if(result > 1073741824) sb.AppendFormat("\tDevice has {0} GiB", result / 1073741824.0).AppendLine();
else if(result > 1048576) sb.AppendFormat("\tDevice has {0} MiB", result / 1048576.0).AppendLine();
else if(result > 1024) sb.AppendFormat("\tDevice has {0} KiB", result / 1024.0).AppendLine();
else sb.AppendFormat("\tDevice has {0} bytes", result).AppendLine();
if(result > 1073741824)
sb.AppendFormat("\tDevice has {0} GiB", result / 1073741824.0).AppendLine();
else if(result > 1048576)
sb.AppendFormat("\tDevice has {0} MiB", result / 1048576.0).AppendLine();
else if(result > 1024)
sb.AppendFormat("\tDevice has {0} KiB", result / 1024.0).AppendLine();
else
sb.AppendFormat("\tDevice has {0} bytes", result).AppendLine();
switch(csd.ReadCurrentAtVddMin & 0x07)
{
case 0:
sb.AppendLine("\tDevice uses a maximum of 0.5mA for reading at minimum voltage");
break;
case 1:
sb.AppendLine("\tDevice uses a maximum of 1mA for reading at minimum voltage");
break;
case 2:
sb.AppendLine("\tDevice uses a maximum of 5mA for reading at minimum voltage");
break;
case 3:
sb.AppendLine("\tDevice uses a maximum of 10mA for reading at minimum voltage");
break;
case 4:
sb.AppendLine("\tDevice uses a maximum of 25mA for reading at minimum voltage");
break;
case 5:
sb.AppendLine("\tDevice uses a maximum of 35mA for reading at minimum voltage");
break;
case 6:
sb.AppendLine("\tDevice uses a maximum of 60mA for reading at minimum voltage");
break;
case 7:
sb.AppendLine("\tDevice uses a maximum of 100mA for reading at minimum voltage");
break;
}
@@ -398,27 +472,35 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
sb.AppendLine("\tDevice uses a maximum of 1mA for reading at maximum voltage");
break;
case 1:
sb.AppendLine("\tDevice uses a maximum of 5mA for reading at maximum voltage");
break;
case 2:
sb.AppendLine("\tDevice uses a maximum of 10mA for reading at maximum voltage");
break;
case 3:
sb.AppendLine("\tDevice uses a maximum of 25mA for reading at maximum voltage");
break;
case 4:
sb.AppendLine("\tDevice uses a maximum of 35mA for reading at maximum voltage");
break;
case 5:
sb.AppendLine("\tDevice uses a maximum of 45mA for reading at maximum voltage");
break;
case 6:
sb.AppendLine("\tDevice uses a maximum of 80mA for reading at maximum voltage");
break;
case 7:
sb.AppendLine("\tDevice uses a maximum of 200mA for reading at maximum voltage");
break;
}
@@ -426,27 +508,35 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
sb.AppendLine("\tDevice uses a maximum of 0.5mA for writing at minimum voltage");
break;
case 1:
sb.AppendLine("\tDevice uses a maximum of 1mA for writing at minimum voltage");
break;
case 2:
sb.AppendLine("\tDevice uses a maximum of 5mA for writing at minimum voltage");
break;
case 3:
sb.AppendLine("\tDevice uses a maximum of 10mA for writing at minimum voltage");
break;
case 4:
sb.AppendLine("\tDevice uses a maximum of 25mA for writing at minimum voltage");
break;
case 5:
sb.AppendLine("\tDevice uses a maximum of 35mA for writing at minimum voltage");
break;
case 6:
sb.AppendLine("\tDevice uses a maximum of 60mA for writing at minimum voltage");
break;
case 7:
sb.AppendLine("\tDevice uses a maximum of 100mA for writing at minimum voltage");
break;
}
@@ -454,27 +544,35 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
sb.AppendLine("\tDevice uses a maximum of 1mA for writing at maximum voltage");
break;
case 1:
sb.AppendLine("\tDevice uses a maximum of 5mA for writing at maximum voltage");
break;
case 2:
sb.AppendLine("\tDevice uses a maximum of 10mA for writing at maximum voltage");
break;
case 3:
sb.AppendLine("\tDevice uses a maximum of 25mA for writing at maximum voltage");
break;
case 4:
sb.AppendLine("\tDevice uses a maximum of 35mA for writing at maximum voltage");
break;
case 5:
sb.AppendLine("\tDevice uses a maximum of 45mA for writing at maximum voltage");
break;
case 6:
sb.AppendLine("\tDevice uses a maximum of 80mA for writing at maximum voltage");
break;
case 7:
sb.AppendLine("\tDevice uses a maximum of 200mA for writing at maximum voltage");
break;
}
@@ -487,72 +585,92 @@ namespace DiscImageChef.Decoders.MMC
if(csd.WriteProtectGroupEnable)
{
sb.AppendLine("\tDevice can write protect regions");
// TODO: Check specification
unitFactor = Convert.ToDouble(csd.WriteProtectGroupSize);
sb.AppendFormat("\tDevice can write protect a minimum of {0} blocks at a time", (int)(result + 1))
.AppendLine();
sb.AppendFormat("\tDevice can write protect a minimum of {0} blocks at a time", (int)(result + 1)).
AppendLine();
}
else sb.AppendLine("\tDevice can't write protect regions");
else
sb.AppendLine("\tDevice can't write protect regions");
switch(csd.DefaultECC)
{
case 0:
sb.AppendLine("\tDevice uses no ECC by default");
break;
case 1:
sb.AppendLine("\tDevice uses BCH(542, 512) ECC by default");
break;
case 2:
sb.AppendFormat("\tDevice uses unknown ECC code {0} by default", csd.DefaultECC).AppendLine();
break;
}
sb.AppendFormat("\tWriting is {0} times slower than reading", Math.Pow(2, csd.WriteSpeedFactor))
.AppendLine();
sb.AppendFormat("\tWriting is {0} times slower than reading", Math.Pow(2, csd.WriteSpeedFactor)).
AppendLine();
if(csd.WriteBlockLength == 15) sb.AppendLine("\tWrite block length size is defined in extended CSD");
else sb.AppendFormat("\tWrite block length is {0} bytes", Math.Pow(2, csd.WriteBlockLength)).AppendLine();
if(csd.WriteBlockLength == 15)
sb.AppendLine("\tWrite block length size is defined in extended CSD");
else
sb.AppendFormat("\tWrite block length is {0} bytes", Math.Pow(2, csd.WriteBlockLength)).AppendLine();
if(csd.WritesPartialBlocks) sb.AppendLine("\tDevice allows writing partial blocks");
if(csd.WritesPartialBlocks)
sb.AppendLine("\tDevice allows writing partial blocks");
if(csd.ContentProtection) sb.AppendLine("\tDevice supports content protection");
if(csd.ContentProtection)
sb.AppendLine("\tDevice supports content protection");
if(!csd.Copy) sb.AppendLine("\tDevice contents are original");
if(!csd.Copy)
sb.AppendLine("\tDevice contents are original");
if(csd.PermanentWriteProtect) sb.AppendLine("\tDevice is permanently write protected");
if(csd.PermanentWriteProtect)
sb.AppendLine("\tDevice is permanently write protected");
if(csd.TemporaryWriteProtect) sb.AppendLine("\tDevice is temporarily write protected");
if(csd.TemporaryWriteProtect)
sb.AppendLine("\tDevice is temporarily write protected");
if(!csd.FileFormatGroup)
switch(csd.FileFormat)
{
case 0:
sb.AppendLine("\tDevice is formatted like a hard disk");
break;
case 1:
sb.AppendLine("\tDevice is formatted like a floppy disk using Microsoft FAT");
break;
case 2:
sb.AppendLine("\tDevice uses Universal File Format");
break;
default:
sb.AppendFormat("\tDevice uses unknown file format code {0}", csd.FileFormat).AppendLine();
break;
}
else
sb.AppendFormat("\tDevice uses unknown file format code {0} and file format group 1", csd.FileFormat)
.AppendLine();
sb.AppendFormat("\tDevice uses unknown file format code {0} and file format group 1", csd.FileFormat).
AppendLine();
switch(csd.ECC)
{
case 0:
sb.AppendLine("\tDevice currently uses no ECC");
break;
case 1:
sb.AppendLine("\tDevice currently uses BCH(542, 512) ECC by default");
break;
case 2:
sb.AppendFormat("\tDevice currently uses unknown ECC code {0}", csd.DefaultECC).AppendLine();
break;
}

View File

@@ -37,193 +37,192 @@ using System.Text;
namespace DiscImageChef.Decoders.MMC
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "UnassignedField.Global")]
[StructLayout(LayoutKind.Sequential)]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"),
StructLayout(LayoutKind.Sequential)]
public class ExtendedCSD
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] Reserved0;
public byte ExtendedSecurityCommandsError;
public byte SupportedCommandSets;
public byte HPIFeatures;
public byte AccessSize;
public byte AddressedGroupToBeReleased;
public byte BackgroundOperationsStatus;
public byte BackgroundOperationsSupport;
public byte MaxPackedReadCommands;
public byte MaxPackedWriteCommands;
public byte DataTagSupport;
public byte TagUnitSize;
public byte TagResourcesSize;
public byte ContextManagementCaps;
public byte LargeUnitSize;
public byte ExtendedPartitionsSupport;
public byte SupportedModes;
public byte FFUFeatures;
public byte OperationCodesTimeout;
public uint FFUArgument;
public byte BadBlockManagementMode;
public byte BarrierControl;
public byte BarrierSupport;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)]
public byte[] Reserved1;
public byte CMDQueuingSupport;
public byte BootAreaWriteProtectionRegister;
public byte BootBusConditions;
public byte BootConfigProtection;
public byte BootInformation;
public byte BootPartitionSize;
public byte BootWriteProtectionStatus;
public byte BusWidth;
public byte CacheControl;
public byte CacheFlushing;
public byte CacheFlushingPolicy;
public uint CacheSize;
public byte Class6CommandsControl;
public byte CMDQueuingDepth;
public uint NumberofFWSectorsCorrectlyProgrammed;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] VendorHealthReport;
public byte DeviceLifeEstimationTypeB;
public byte DeviceLifeEstimationTypeA;
public byte PreEOLInformation;
public byte OptimalReadSize;
public byte OptimalWriteSize;
public byte OptimalTrimUnitSize;
public ushort DeviceVersion;
public ulong FirmwareVersion;
public byte PowerClassDDR200;
public uint CacheSize;
public byte GenericCMD6Timeout;
public byte PowerOffNotificationTimeout;
public byte BackgroundOperationsStatus;
public byte CMDQueuingSupport;
public byte CommandQueueModeEnable;
public byte CommandSet;
public byte CommandSetRevision;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public byte[] ContextConfiguration;
public byte ContextManagementCaps;
public uint CorrectlyProgrammedSectors;
public byte InitializationTimeAfterPartition;
public byte CacheFlushingPolicy;
public byte PowerClassDDR52;
public byte PowerClassDDR52_195;
public byte PowerClassDDR200_195;
public byte PowerClassDDR200_130;
public byte MinimumWritePerformanceDDR52;
public byte MinimumReadPerformanceDDR52;
public byte Reserved2;
public byte TRIMMultiplier;
public byte SecureFeatureSupport;
public byte SecureEraseMultiplier;
public byte SecureTRIMMultiplier;
public byte BootInformation;
public byte Reserved3;
public byte BootPartitionSize;
public byte AccessSize;
public byte HighCapacityEraseUnitSize;
public byte HighCapacityEraseTimeout;
public byte ReliableWriteSectorCount;
public byte HighCapacityWriteProtectGroupSize;
public byte SleepCurrentVcc;
public byte SleepCurrentVccq;
public byte ProductionStateAwarenessTimeout;
public byte SleepAwakeTimeout;
public byte SleepNotificationTimeout;
public uint SectorCount;
public byte SecureWriteProtectInformation;
public byte MinimumWritePerformance52;
public byte MinimumReadPerformance52;
public byte MinimumWritePerformance26;
public byte MinimumReadPerformance26;
public byte MinimumWritePerformance26_4;
public byte MinimumReadPerformance26_4;
public byte Reserved4;
public byte PowerClass26;
public byte PowerClass52;
public byte PowerClass26_195;
public byte PowerClass52_195;
public byte PartitionSwitchingTime;
public byte OutOfInterruptBusyTiming;
public byte DriverStrength;
public byte DataTagSupport;
public byte DeviceLifeEstimationTypeA;
public byte DeviceLifeEstimationTypeB;
public byte DeviceType;
public byte Reserved5;
public byte Structure;
public byte Reserved6;
public byte Revision;
public byte CommandSet;
public byte Reserved7;
public byte CommandSetRevision;
public byte Reserved8;
public byte PowerClass;
public byte Reserved9;
public byte HighSpeedInterfaceTiming;
public byte StrobeSupport;
public byte BusWidth;
public byte Reserved10;
public byte ErasedMemoryContent;
public byte Reserved11;
public byte PartitionConfiguration;
public byte BootConfigProtection;
public byte BootBusConditions;
public byte Reserved12;
public byte HighDensityEraseGroupDefinition;
public byte BootWriteProtectionStatus;
public byte BootAreaWriteProtectionRegister;
public byte Reserved13;
public byte UserAreaWriteProtectionRegister;
public byte Reserved14;
public byte FirmwareConfiguration;
public byte RPMBSize;
public byte WriteReliabilitySettingRegister;
public byte WriteReliabilityParameterRegister;
public byte StartSanitizeOperation;
public byte ManuallyStartBackgroundOperations;
public ushort DeviceVersion;
public byte DriverStrength;
public byte EnableBackgroundOperationsHandshake;
public byte HWResetFunction;
public byte HPIManagement;
public byte PartitioningSupport;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] MaxEnhancedAreaSize;
public byte PartitionsAttribute;
public byte PartitioningSetting;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] GeneralPurposePartitionSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] EnhancedUserDataAreaSize;
public uint EnhancedUserDataStartAddress;
public byte Reserved15;
public byte BadBlockManagementMode;
public byte ProductionStateAwareness;
public byte PackageCaseTemperatureControl;
public byte PeriodicWakeUp;
public byte SupportsProgramCxDInDDR;
public ushort Reserved16;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] VendorSpecific;
public byte NativeSectorSize;
public byte SectorSizeEmulation;
public byte SectorSize;
public byte InitializationTimeout;
public byte Class6CommandsControl;
public byte AddressedGroupToBeReleased;
public byte ErasedMemoryContent;
public ushort ExceptionEventsControl;
public ushort ExceptionEventsStatus;
public ushort ExtendedPartitionsAttribute;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public byte[] ContextConfiguration;
public byte PackedCommandStatus;
public byte PackedCommandFailureIndex;
public byte PowerOffNotification;
public byte CacheControl;
public byte CacheFlushing;
public byte BarrierControl;
public byte ModeConfig;
public byte ModeOperationCodes;
public ushort Reserved17;
public byte ExtendedPartitionsSupport;
public byte ExtendedSecurityCommandsError;
public uint FFUArgument;
public byte FFUFeatures;
public byte FFUStatus;
public uint PreLoadingDataSize;
public uint MaxPreLoadingDataSize;
public byte ProductStateAwarenessEnablement;
public byte SecureRemovalType;
public byte CommandQueueModeEnable;
public byte FirmwareConfiguration;
public ulong FirmwareVersion;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] GeneralPurposePartitionSize;
public byte GenericCMD6Timeout;
public byte HighCapacityEraseTimeout;
public byte HighCapacityEraseUnitSize;
public byte HighCapacityWriteProtectGroupSize;
public byte HighDensityEraseGroupDefinition;
public byte HighSpeedInterfaceTiming;
public byte HPIFeatures;
public byte HPIManagement;
public byte HWResetFunction;
public byte InitializationTimeAfterPartition;
public byte InitializationTimeout;
public byte LargeUnitSize;
public byte ManuallyStartBackgroundOperations;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] MaxEnhancedAreaSize;
public byte MaxPackedReadCommands;
public byte MaxPackedWriteCommands;
public uint MaxPreLoadingDataSize;
public byte MinimumReadPerformance26;
public byte MinimumReadPerformance26_4;
public byte MinimumReadPerformance52;
public byte MinimumReadPerformanceDDR52;
public byte MinimumWritePerformance26;
public byte MinimumWritePerformance26_4;
public byte MinimumWritePerformance52;
public byte MinimumWritePerformanceDDR52;
public byte ModeConfig;
public byte ModeOperationCodes;
public byte NativeSectorSize;
public uint NumberofFWSectorsCorrectlyProgrammed;
public byte OperationCodesTimeout;
public byte OptimalReadSize;
public byte OptimalTrimUnitSize;
public byte OptimalWriteSize;
public byte OutOfInterruptBusyTiming;
public byte PackageCaseTemperatureControl;
public byte PackedCommandFailureIndex;
public byte PackedCommandStatus;
public byte PartitionConfiguration;
public byte PartitioningSetting;
public byte PartitioningSupport;
public byte PartitionsAttribute;
public byte PartitionSwitchingTime;
public byte PeriodicWakeUp;
public byte PowerClass;
public byte PowerClass26;
public byte PowerClass26_195;
public byte PowerClass52;
public byte PowerClass52_195;
public byte PowerClassDDR200;
public byte PowerClassDDR200_130;
public byte PowerClassDDR200_195;
public byte PowerClassDDR52;
public byte PowerClassDDR52_195;
public byte PowerOffNotification;
public byte PowerOffNotificationTimeout;
public byte PreEOLInformation;
public uint PreLoadingDataSize;
public byte ProductionStateAwareness;
public byte ProductionStateAwarenessTimeout;
public byte ProductStateAwarenessEnablement;
public byte ReliableWriteSectorCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] Reserved0;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)]
public byte[] Reserved1;
public byte Reserved10;
public byte Reserved11;
public byte Reserved12;
public byte Reserved13;
public byte Reserved14;
public byte Reserved15;
public ushort Reserved16;
public ushort Reserved17;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)]
public byte[] Reserved18;
public byte Reserved2;
public byte Reserved3;
public byte Reserved4;
public byte Reserved5;
public byte Reserved6;
public byte Reserved7;
public byte Reserved8;
public byte Reserved9;
public byte Revision;
public byte RPMBSize;
public uint SectorCount;
public byte SectorSize;
public byte SectorSizeEmulation;
public byte SecureEraseMultiplier;
public byte SecureFeatureSupport;
public byte SecureRemovalType;
public byte SecureTRIMMultiplier;
public byte SecureWriteProtectInformation;
public byte SleepAwakeTimeout;
public byte SleepCurrentVcc;
public byte SleepCurrentVccq;
public byte SleepNotificationTimeout;
public byte StartSanitizeOperation;
public byte StrobeSupport;
public byte Structure;
public byte SupportedCommandSets;
public byte SupportedModes;
public byte SupportsProgramCxDInDDR;
public byte TagResourcesSize;
public byte TagUnitSize;
public byte TRIMMultiplier;
public byte UserAreaWriteProtectionRegister;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] VendorHealthReport;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] VendorSpecific;
public byte WriteReliabilityParameterRegister;
public byte WriteReliabilitySettingRegister;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Decoders
{
public static ExtendedCSD DecodeExtendedCSD(byte[] response)
{
if(response == null) return null;
if(response == null)
return null;
if(response.Length != 512) return null;
if(response.Length != 512)
return null;
GCHandle handle = GCHandle.Alloc(response, GCHandleType.Pinned);
ExtendedCSD csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD));
GCHandle handle = GCHandle.Alloc(response, GCHandleType.Pinned);
var csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD));
handle.Free();
return csd;
@@ -231,16 +230,16 @@ namespace DiscImageChef.Decoders.MMC
public static string PrettifyExtendedCSD(ExtendedCSD csd)
{
if(csd == null) return null;
if(csd == null)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("MultiMediaCard Extended Device Specific Data Register:");
double unit;
if((csd.HPIFeatures & 0x01) == 0x01)
sb.AppendLine((csd.HPIFeatures & 0x02) == 0x02
? "\tDevice implements HPI using CMD12"
sb.AppendLine((csd.HPIFeatures & 0x02) == 0x02 ? "\tDevice implements HPI using CMD12"
: "\tDevice implements HPI using CMD13");
if((csd.BackgroundOperationsSupport & 0x01) == 0x01)
@@ -257,53 +256,68 @@ namespace DiscImageChef.Decoders.MMC
if((csd.ExtendedPartitionsSupport & 0x01) == 0x01)
sb.AppendLine("\tDevice supports non-persistent extended partitions");
if((csd.ExtendedPartitionsSupport & 0x02) == 0x02)
sb.AppendLine("\tDevice supports system code extended partitions");
if((csd.SupportedModes & 0x01) == 0x01) sb.AppendLine("\tDevice supports FFU");
if((csd.SupportedModes & 0x02) == 0x02) sb.AppendLine("\tDevice supports Vendor Specific Mode");
if((csd.SupportedModes & 0x01) == 0x01)
sb.AppendLine("\tDevice supports FFU");
if((csd.SupportedModes & 0x02) == 0x02)
sb.AppendLine("\tDevice supports Vendor Specific Mode");
if((csd.CMDQueuingSupport & 0x01) == 0x01)
sb.AppendFormat("\tDevice supports command queuing with a depth of {0}", csd.CMDQueuingDepth + 1)
.AppendLine();
sb.AppendFormat("\tDevice supports command queuing with a depth of {0}", csd.CMDQueuingDepth + 1).
AppendLine();
sb.AppendFormat("\t{0} firmware sectors correctly programmed", csd.NumberofFWSectorsCorrectlyProgrammed)
.AppendLine();
sb.AppendFormat("\t{0} firmware sectors correctly programmed", csd.NumberofFWSectorsCorrectlyProgrammed).
AppendLine();
switch(csd.DeviceLifeEstimationTypeB)
{
case 1:
sb.AppendLine("\tDevice used between 0% and 10% of its estimated life time");
break;
case 2:
sb.AppendLine("\tDevice used between 10% and 20% of its estimated life time");
break;
case 3:
sb.AppendLine("\tDevice used between 20% and 30% of its estimated life time");
break;
case 4:
sb.AppendLine("\tDevice used between 30% and 40% of its estimated life time");
break;
case 5:
sb.AppendLine("\tDevice used between 40% and 50% of its estimated life time");
break;
case 6:
sb.AppendLine("\tDevice used between 50% and 60% of its estimated life time");
break;
case 7:
sb.AppendLine("\tDevice used between 60% and 70% of its estimated life time");
break;
case 8:
sb.AppendLine("\tDevice used between 70% and 80% of its estimated life time");
break;
case 9:
sb.AppendLine("\tDevice used between 80% and 90% of its estimated life time");
break;
case 10:
sb.AppendLine("\tDevice used between 90% and 100% of its estimated life time");
break;
case 11:
sb.AppendLine("\tDevice exceeded its maximum estimated life time");
break;
}
@@ -311,36 +325,47 @@ namespace DiscImageChef.Decoders.MMC
{
case 1:
sb.AppendLine("\tDevice used between 0% and 10% of its estimated life time");
break;
case 2:
sb.AppendLine("\tDevice used between 10% and 20% of its estimated life time");
break;
case 3:
sb.AppendLine("\tDevice used between 20% and 30% of its estimated life time");
break;
case 4:
sb.AppendLine("\tDevice used between 30% and 40% of its estimated life time");
break;
case 5:
sb.AppendLine("\tDevice used between 40% and 50% of its estimated life time");
break;
case 6:
sb.AppendLine("\tDevice used between 50% and 60% of its estimated life time");
break;
case 7:
sb.AppendLine("\tDevice used between 60% and 70% of its estimated life time");
break;
case 8:
sb.AppendLine("\tDevice used between 70% and 80% of its estimated life time");
break;
case 9:
sb.AppendLine("\tDevice used between 80% and 90% of its estimated life time");
break;
case 10:
sb.AppendLine("\tDevice used between 90% and 100% of its estimated life time");
break;
case 11:
sb.AppendLine("\tDevice exceeded its maximum estimated life time");
break;
}
@@ -348,12 +373,15 @@ namespace DiscImageChef.Decoders.MMC
{
case 1:
sb.AppendLine("\tDevice informs it's in good health");
break;
case 2:
sb.AppendLine("\tDevice informs it should be replaced soon");
break;
case 3:
sb.AppendLine("\tDevice informs it should be replace immediately");
break;
}
@@ -364,31 +392,37 @@ namespace DiscImageChef.Decoders.MMC
sb.AppendFormat("\tDevice version: {0}", csd.DeviceVersion).AppendLine();
sb.AppendFormat("\tFirmware version: {0}", csd.FirmwareVersion).AppendLine();
if(csd.CacheSize == 0) sb.AppendLine("\tDevice has no cache");
else sb.AppendFormat("\tDevice has {0} KiB of cache", csd.CacheSize).AppendLine();
if(csd.CacheSize == 0)
sb.AppendLine("\tDevice has no cache");
else
sb.AppendFormat("\tDevice has {0} KiB of cache", csd.CacheSize).AppendLine();
if(csd.GenericCMD6Timeout > 0)
sb.AppendFormat("\tDevice takes a maximum of {0} ms by default for a SWITCH command",
csd.GenericCMD6Timeout * 10).AppendLine();
if(csd.PowerOffNotificationTimeout > 0)
sb
.AppendFormat("\tDevice takes a maximum of {0} by default to power off from a SWITCH command notification",
sb.
AppendFormat("\tDevice takes a maximum of {0} by default to power off from a SWITCH command notification",
csd.PowerOffNotificationTimeout * 10).AppendLine();
switch(csd.BackgroundOperationsStatus & 0x03)
{
case 0:
sb.AppendLine("\tDevice has no pending background operations");
break;
case 1:
sb.AppendLine("\tDevice has non critical operations outstanding");
break;
case 2:
sb.AppendLine("\tDevice has performance impacted operations outstanding");
break;
case 3:
sb.AppendLine("\tDevice has critical operations outstanding");
break;
}
@@ -406,30 +440,41 @@ namespace DiscImageChef.Decoders.MMC
sb.AppendFormat("\tDevice takes a maximum of {0} ms for trimming a single erase group",
csd.TRIMMultiplier * 300).AppendLine();
if((csd.SecureFeatureSupport & 0x40) == 0x40) sb.AppendLine("\tDevice supports the sanitize operation");
if((csd.SecureFeatureSupport & 0x40) == 0x40)
sb.AppendLine("\tDevice supports the sanitize operation");
if((csd.SecureFeatureSupport & 0x10) == 0x10)
sb.AppendLine("\tDevice supports supports the secure and insecure trim operations");
if((csd.SecureFeatureSupport & 0x04) == 0x04)
sb.AppendLine("\tDevice supports automatic erase on retired defective blocks");
if((csd.SecureFeatureSupport & 0x01) == 0x01) sb.AppendLine("\tDevice supports secure purge operations");
if((csd.SecureFeatureSupport & 0x01) == 0x01)
sb.AppendLine("\tDevice supports secure purge operations");
if(csd.SecureEraseMultiplier > 0)
sb.AppendFormat("\tDevice takes a maximum of {0} ms for securely erasing a single erase group",
csd.SecureEraseMultiplier * 300).AppendLine();
if(csd.SecureTRIMMultiplier > 0)
sb.AppendFormat("\tDevice takes a maximum of {0} ms for securely trimming a single erase group",
csd.SecureTRIMMultiplier * 300).AppendLine();
if((csd.BootInformation & 0x04) == 0x04) sb.AppendLine("\tDevice supports high speed timing on boot");
if((csd.BootInformation & 0x02) == 0x02) sb.AppendLine("\tDevice supports dual data rate on boot");
if((csd.BootInformation & 0x01) == 0x01) sb.AppendLine("\tDevice supports alternative boot method");
if((csd.BootInformation & 0x04) == 0x04)
sb.AppendLine("\tDevice supports high speed timing on boot");
if((csd.BootInformation & 0x02) == 0x02)
sb.AppendLine("\tDevice supports dual data rate on boot");
if((csd.BootInformation & 0x01) == 0x01)
sb.AppendLine("\tDevice supports alternative boot method");
if(csd.BootPartitionSize > 0)
sb.AppendFormat("\tDevice has a {0} KiB boot partition", csd.BootPartitionSize * 128).AppendLine();
if((csd.AccessSize & 0x0F) > 0)
sb.AppendFormat("\tDevice has a page size of {0} KiB", (csd.AccessSize & 0x0F) * 512.0 / 1024.0)
.AppendLine();
sb.AppendFormat("\tDevice has a page size of {0} KiB", (csd.AccessSize & 0x0F) * 512.0 / 1024.0).
AppendLine();
if(csd.HighCapacityEraseUnitSize > 0)
sb.AppendFormat("\tDevice erase groups are {0} KiB", csd.HighCapacityEraseUnitSize * 512).AppendLine();
@@ -445,20 +490,27 @@ namespace DiscImageChef.Decoders.MMC
if(csd.SleepCurrentVcc > 0)
{
unit = Math.Pow(2, csd.SleepCurrentVcc);
if(unit > 1000) sb.AppendFormat("\tDevice uses {0} mA on Vcc when sleeping", unit / 1000).AppendLine();
else sb.AppendFormat("\tDevice uses {0} μA on Vcc when sleeping", unit).AppendLine();
if(unit > 1000)
sb.AppendFormat("\tDevice uses {0} mA on Vcc when sleeping", unit / 1000).AppendLine();
else
sb.AppendFormat("\tDevice uses {0} μA on Vcc when sleeping", unit).AppendLine();
}
if(csd.SleepCurrentVccq > 0)
{
unit = Math.Pow(2, csd.SleepCurrentVccq);
if(unit > 1000) sb.AppendFormat("\tDevice uses {0} mA on Vccq when sleeping", unit / 1000).AppendLine();
else sb.AppendFormat("\tDevice uses {0} μA on Vccq when sleeping", unit).AppendLine();
if(unit > 1000)
sb.AppendFormat("\tDevice uses {0} mA on Vccq when sleeping", unit / 1000).AppendLine();
else
sb.AppendFormat("\tDevice uses {0} μA on Vccq when sleeping", unit).AppendLine();
}
if(csd.ProductionStateAwarenessTimeout > 0)
{
unit = Math.Pow(2, csd.ProductionStateAwareness) * 100;
if(unit > 1000000)
sb.AppendFormat("\tDevice takes a maximum of {0} s to switch production state awareness",
unit / 1000000).AppendLine();
@@ -466,13 +518,14 @@ namespace DiscImageChef.Decoders.MMC
sb.AppendFormat("\tDevice takes a maximum of {0} ms to switch production state awareness",
unit / 1000).AppendLine();
else
sb.AppendFormat("\tDevice takes a maximum of {0} μs to switch production state awareness", unit)
.AppendLine();
sb.AppendFormat("\tDevice takes a maximum of {0} μs to switch production state awareness", unit).
AppendLine();
}
if(csd.SleepAwakeTimeout > 0)
{
unit = Math.Pow(2, csd.SleepAwakeTimeout) * 100;
if(unit > 1000000)
sb.AppendFormat("\tDevice takes a maximum of {0} ms to transition between sleep and standby states",
unit / 1000000).AppendLine();
@@ -487,13 +540,15 @@ namespace DiscImageChef.Decoders.MMC
if(csd.SleepNotificationTimeout > 0)
{
unit = Math.Pow(2, csd.SleepNotificationTimeout) * 10;
if(unit > 1000000)
sb.AppendFormat("\tDevice takes a maximum of {0} s to move to sleep state", unit / 1000000)
.AppendLine();
sb.AppendFormat("\tDevice takes a maximum of {0} s to move to sleep state", unit / 1000000).
AppendLine();
else if(unit > 1000)
sb.AppendFormat("\tDevice takes a maximum of {0} ms to move to sleep state", unit / 1000)
.AppendLine();
else sb.AppendFormat("\tDevice takes a maximum of {0} μs to move to sleep state", unit).AppendLine();
sb.AppendFormat("\tDevice takes a maximum of {0} ms to move to sleep state", unit / 1000).
AppendLine();
else
sb.AppendFormat("\tDevice takes a maximum of {0} μs to move to sleep state", unit).AppendLine();
}
sb.AppendFormat("\tDevice has {0} sectors", csd.SectorCount).AppendLine();
@@ -501,18 +556,21 @@ namespace DiscImageChef.Decoders.MMC
if((csd.SecureWriteProtectInformation & 0x01) == 0x01)
{
sb.AppendLine("\tDevice supports secure write protection");
if((csd.SecureWriteProtectInformation & 0x02) == 0x02)
sb.AppendLine("\tDevice has secure write protection enabled");
}
unit = csd.MinimumReadPerformance26 * 150;
if(csd.MinimumReadPerformance26 == 0)
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz mode");
else
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz mode", unit / 1000)
.AppendLine();
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz mode", unit / 1000).
AppendLine();
unit = csd.MinimumReadPerformance26_4 * 150;
if(csd.MinimumReadPerformance26_4 == 0)
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode");
else
@@ -520,27 +578,31 @@ namespace DiscImageChef.Decoders.MMC
unit / 1000).AppendLine();
unit = csd.MinimumReadPerformance52 * 150;
if(csd.MinimumReadPerformance52 == 0)
sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 52Mhz mode");
else
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 52Mhz mode", unit / 1000)
.AppendLine();
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 52Mhz mode", unit / 1000).
AppendLine();
unit = csd.MinimumReadPerformanceDDR52 * 300;
if(csd.MinimumReadPerformanceDDR52 == 0)
sb.AppendLine("\tDevice cannot achieve 4.8MB/s reading in DDR 52Mhz mode");
else
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in DDR 52Mhz mode", unit / 1000)
.AppendLine();
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in DDR 52Mhz mode", unit / 1000).
AppendLine();
unit = csd.MinimumWritePerformance26 * 150;
if(csd.MinimumWritePerformance26 == 0)
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz mode");
else
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz mode", unit / 1000)
.AppendLine();
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz mode", unit / 1000).
AppendLine();
unit = csd.MinimumWritePerformance26_4 * 150;
if(csd.MinimumWritePerformance26_4 == 0)
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode");
else
@@ -548,18 +610,20 @@ namespace DiscImageChef.Decoders.MMC
unit / 1000).AppendLine();
unit = csd.MinimumWritePerformance52 * 150;
if(csd.MinimumWritePerformance52 == 0)
sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 52Mhz mode");
else
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 52Mhz mode", unit / 1000)
.AppendLine();
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 52Mhz mode", unit / 1000).
AppendLine();
unit = csd.MinimumWritePerformanceDDR52 * 300;
if(csd.MinimumWritePerformanceDDR52 == 0)
sb.AppendLine("\tDevice cannot achieve 4.8MB/s writing in DDR 52Mhz mode");
else
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in DDR 52Mhz mode", unit / 1000)
.AppendLine();
sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in DDR 52Mhz mode", unit / 1000).
AppendLine();
if(csd.PartitionSwitchingTime > 0)
sb.AppendFormat("\tDevice can take a maximum of {0} ms when switching partitions",
@@ -569,20 +633,36 @@ namespace DiscImageChef.Decoders.MMC
sb.AppendFormat("\tDevice can take a maximum of {0} ms when releasing from an interrupt",
csd.OutOfInterruptBusyTiming * 10).AppendLine();
if((csd.DeviceType & 0x01) == 0x01) sb.AppendLine("\tDevice supports 26 Mhz mode");
if((csd.DeviceType & 0x02) == 0x02) sb.AppendLine("\tDevice supports 52 Mhz mode");
if((csd.DeviceType & 0x04) == 0x04) sb.AppendLine("\tDevice supports DDR 52 Mhz mode at 1.8V or 3V");
if((csd.DeviceType & 0x08) == 0x08) sb.AppendLine("\tDevice supports DDR 52 Mhz mode 1.2V");
if((csd.DeviceType & 0x10) == 0x10) sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.8V");
if((csd.DeviceType & 0x20) == 0x20) sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.2V");
if((csd.DeviceType & 0x40) == 0x40) sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.8V");
if((csd.DeviceType & 0x80) == 0x80) sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.2V");
if((csd.DeviceType & 0x01) == 0x01)
sb.AppendLine("\tDevice supports 26 Mhz mode");
if((csd.DeviceType & 0x02) == 0x02)
sb.AppendLine("\tDevice supports 52 Mhz mode");
if((csd.DeviceType & 0x04) == 0x04)
sb.AppendLine("\tDevice supports DDR 52 Mhz mode at 1.8V or 3V");
if((csd.DeviceType & 0x08) == 0x08)
sb.AppendLine("\tDevice supports DDR 52 Mhz mode 1.2V");
if((csd.DeviceType & 0x10) == 0x10)
sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.8V");
if((csd.DeviceType & 0x20) == 0x20)
sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.2V");
if((csd.DeviceType & 0x40) == 0x40)
sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.8V");
if((csd.DeviceType & 0x80) == 0x80)
sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.2V");
sb.AppendFormat("\tCSD version 1.{0} revision 1.{1}", csd.Structure, csd.Revision).AppendLine();
if((csd.StrobeSupport & 0x01) == 0x01)
{
sb.AppendLine("\tDevice supports enhanced strobe mode");
sb.AppendLine((csd.BusWidth & 0x80) == 0x80
? "\tDevice uses strobe during Data Out, CRC and CMD responses"
: "\tDevice uses strobe during Data Out and CRC responses");
@@ -592,43 +672,55 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
sb.AppendLine("\tDevice is using 1-bit data bus");
break;
case 1:
sb.AppendLine("\tDevice is using 4-bit data bus");
break;
case 2:
sb.AppendLine("\tDevice is using 8-bit data bus");
break;
case 5:
sb.AppendLine("\tDevice is using 4-bit DDR data bus");
break;
case 6:
sb.AppendLine("\tDevice is using 8-bit DDR data bus");
break;
default:
sb.AppendFormat("\tDevice is using unknown data bus code {0}", csd.BusWidth & 0x0F).AppendLine();
break;
}
if((csd.PartitionConfiguration & 0x80) == 0x80) sb.AppendLine("\tDevice sends boot acknowledge");
if((csd.PartitionConfiguration & 0x80) == 0x80)
sb.AppendLine("\tDevice sends boot acknowledge");
switch((csd.PartitionConfiguration & 0x38) >> 3)
{
case 0:
sb.AppendLine("\tDevice is not boot enabled");
break;
case 1:
sb.AppendLine("\tDevice boot partition 1 is enabled");
break;
case 2:
sb.AppendLine("\tDevice boot partition 2 is enabled");
break;
case 7:
sb.AppendLine("\tDevice user area is enable for boot");
break;
default:
sb.AppendFormat("\tUnknown enabled boot partition code {0}",
(csd.PartitionConfiguration & 0x38) >> 3).AppendLine();
break;
}
@@ -636,39 +728,48 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
sb.AppendLine("\tThere is no access to boot partition");
break;
case 1:
sb.AppendLine("\tThere is read/write access to boot partition 1");
break;
case 2:
sb.AppendLine("\tThere is read/write access to boot partition 2");
break;
case 3:
sb.AppendLine("\tThere is read/write access to replay protected memory block");
break;
default:
sb.AppendFormat("\tThere is access to general purpose partition {0}",
(csd.PartitionConfiguration & 0x07) - 3).AppendLine();
break;
}
if((csd.FirmwareConfiguration & 0x01) == 0x01) sb.AppendLine("\tFirmware updates are permanently disabled");
if((csd.FirmwareConfiguration & 0x01) == 0x01)
sb.AppendLine("\tFirmware updates are permanently disabled");
if(csd.RPMBSize > 0)
sb.AppendFormat("\tDevice has a {0} KiB replay protected memory block", csd.RPMBSize * 128)
.AppendLine();
sb.AppendFormat("\tDevice has a {0} KiB replay protected memory block", csd.RPMBSize * 128).
AppendLine();
switch(csd.NativeSectorSize)
{
case 0:
sb.AppendLine("\tDevice natively uses 512 byte sectors");
break;
case 1:
sb.AppendLine("\tDevice natively uses 4096 byte sectors");
break;
default:
sb.AppendFormat("\tDevice natively uses unknown sector size indicated by code {0}",
csd.NativeSectorSize).AppendLine();
break;
}
@@ -676,13 +777,16 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
sb.AppendLine("\tDevice is emulating 512 byte sectors");
break;
case 1:
sb.AppendLine("\tDevice is using natively sized sectors");
break;
default:
sb.AppendFormat("\tDevice emulates unknown sector size indicated by code {0}", csd.NativeSectorSize)
.AppendLine();
sb.AppendFormat("\tDevice emulates unknown sector size indicated by code {0}",
csd.NativeSectorSize).AppendLine();
break;
}
@@ -690,19 +794,24 @@ namespace DiscImageChef.Decoders.MMC
{
case 0:
sb.AppendLine("\tDevice currently addresses 512 byte sectors");
break;
case 1:
sb.AppendLine("\tDevice currently addresses 4096 byte sectors");
break;
default:
sb.AppendFormat("\tDevice currently addresses unknown sector size indicated by code {0}",
csd.NativeSectorSize).AppendLine();
break;
}
if((csd.CacheControl & 0x01) == 0x01) sb.AppendLine("\tDevice's cache is enabled");
if((csd.CacheControl & 0x01) == 0x01)
sb.AppendLine("\tDevice's cache is enabled");
if((csd.CommandQueueModeEnable & 0x01) == 0x01) sb.AppendLine("\tDevice has enabled command queuing");
if((csd.CommandQueueModeEnable & 0x01) == 0x01)
sb.AppendLine("\tDevice has enabled command queuing");
return sb.ToString();
}

View File

@@ -36,101 +36,126 @@ using System.Text;
namespace DiscImageChef.Decoders.MMC
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public class OCR
{
public bool PowerUp;
public byte AccessMode;
public bool OneSix;
public bool PowerUp;
public bool ThreeFive;
public bool ThreeFour;
public bool ThreeOne;
public bool ThreeThree;
public bool ThreeTwo;
public bool ThreeOne;
public bool ThreeZero;
public bool TwoNine;
public bool TwoEight;
public bool TwoSeven;
public bool TwoSix;
public bool TwoFive;
public bool TwoFour;
public bool TwoNine;
public bool TwoOne;
public bool TwoSeven;
public bool TwoSix;
public bool TwoThree;
public bool TwoTwo;
public bool TwoOne;
public bool TwoZero;
public bool OneSix;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Decoders
{
public static OCR DecodeOCR(uint response) =>
new OCR
{
PowerUp = (response & 0x80000000) == 0x80000000,
AccessMode = (byte)((response & 0x60000000) >> 29),
ThreeFive = (response & 0x00800000) == 0x00800000,
ThreeFour = (response & 0x00400000) == 0x00400000,
ThreeThree = (response & 0x00200000) == 0x00200000,
ThreeTwo = (response & 0x00100000) == 0x00100000,
ThreeOne = (response & 0x00080000) == 0x00080000,
ThreeZero = (response & 0x00040000) == 0x00040000,
TwoNine = (response & 0x00020000) == 0x00020000,
TwoEight = (response & 0x00010000) == 0x00010000,
TwoSeven = (response & 0x00008000) == 0x00008000,
TwoSix = (response & 0x00004000) == 0x00004000,
TwoFive = (response & 0x00002000) == 0x00002000,
TwoFour = (response & 0x00001000) == 0x00001000,
TwoThree = (response & 0x00000800) == 0x00000800,
TwoTwo = (response & 0x00000400) == 0x00000400,
TwoOne = (response & 0x00000200) == 0x00000200,
TwoZero = (response & 0x00000100) == 0x00000100,
OneSix = (response & 0x00000080) == 0x00000080
};
public static OCR DecodeOCR(uint response) => new OCR
{
PowerUp = (response & 0x80000000) == 0x80000000, AccessMode = (byte)((response & 0x60000000) >> 29),
ThreeFive = (response & 0x00800000) == 0x00800000, ThreeFour = (response & 0x00400000) == 0x00400000,
ThreeThree = (response & 0x00200000) == 0x00200000, ThreeTwo = (response & 0x00100000) == 0x00100000,
ThreeOne = (response & 0x00080000) == 0x00080000, ThreeZero = (response & 0x00040000) == 0x00040000,
TwoNine = (response & 0x00020000) == 0x00020000, TwoEight = (response & 0x00010000) == 0x00010000,
TwoSeven = (response & 0x00008000) == 0x00008000, TwoSix = (response & 0x00004000) == 0x00004000,
TwoFive = (response & 0x00002000) == 0x00002000, TwoFour = (response & 0x00001000) == 0x00001000,
TwoThree = (response & 0x00000800) == 0x00000800, TwoTwo = (response & 0x00000400) == 0x00000400,
TwoOne = (response & 0x00000200) == 0x00000200, TwoZero = (response & 0x00000100) == 0x00000100,
OneSix = (response & 0x00000080) == 0x00000080
};
public static OCR DecodeOCR(byte[] response) =>
response?.Length != 4 ? null : DecodeOCR(BitConverter.ToUInt32(response, 0));
public static string PrettifyOCR(OCR ocr)
{
if(ocr == null) return null;
if(ocr == null)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("MultiMediaCard Operation Conditions Register:");
if(!ocr.PowerUp) sb.AppendLine("\tDevice is powering up");
if(!ocr.PowerUp)
sb.AppendLine("\tDevice is powering up");
switch(ocr.AccessMode)
{
case 0:
sb.AppendLine("\tDevice is byte addressed");
break;
case 2:
sb.AppendLine("\tDevice is sector addressed");
break;
default:
sb.AppendFormat("\tUnknown device access mode {0}", ocr.AccessMode).AppendLine();
break;
}
if(ocr.ThreeFive) sb.AppendLine("\tDevice can work with supply 3.5~3.6V");
if(ocr.ThreeFour) sb.AppendLine("\tDevice can work with supply 3.4~3.5V");
if(ocr.ThreeThree) sb.AppendLine("\tDevice can work with supply 3.3~3.4V");
if(ocr.ThreeTwo) sb.AppendLine("\tDevice can work with supply 3.2~3.3V");
if(ocr.ThreeOne) sb.AppendLine("\tDevice can work with supply 3.1~3.2V");
if(ocr.TwoNine) sb.AppendLine("\tDevice can work with supply 2.9~3.0V");
if(ocr.TwoEight) sb.AppendLine("\tDevice can work with supply 2.8~2.9V");
if(ocr.TwoSeven) sb.AppendLine("\tDevice can work with supply 2.7~2.8V");
if(ocr.TwoSix) sb.AppendLine("\tDevice can work with supply 2.6~2.7V");
if(ocr.TwoFive) sb.AppendLine("\tDevice can work with supply 2.5~2.6V");
if(ocr.TwoFour) sb.AppendLine("\tDevice can work with supply 2.4~2.5V");
if(ocr.TwoThree) sb.AppendLine("\tDevice can work with supply 2.3~2.4V");
if(ocr.TwoTwo) sb.AppendLine("\tDevice can work with supply 2.2~2.3V");
if(ocr.TwoOne) sb.AppendLine("\tDevice can work with supply 2.1~2.2V");
if(ocr.TwoZero) sb.AppendLine("\tDevice can work with supply 2.0~2.1V");
if(ocr.OneSix) sb.AppendLine("\tDevice can work with supply 1.65~1.95V");
if(ocr.ThreeFive)
sb.AppendLine("\tDevice can work with supply 3.5~3.6V");
if(ocr.ThreeFour)
sb.AppendLine("\tDevice can work with supply 3.4~3.5V");
if(ocr.ThreeThree)
sb.AppendLine("\tDevice can work with supply 3.3~3.4V");
if(ocr.ThreeTwo)
sb.AppendLine("\tDevice can work with supply 3.2~3.3V");
if(ocr.ThreeOne)
sb.AppendLine("\tDevice can work with supply 3.1~3.2V");
if(ocr.TwoNine)
sb.AppendLine("\tDevice can work with supply 2.9~3.0V");
if(ocr.TwoEight)
sb.AppendLine("\tDevice can work with supply 2.8~2.9V");
if(ocr.TwoSeven)
sb.AppendLine("\tDevice can work with supply 2.7~2.8V");
if(ocr.TwoSix)
sb.AppendLine("\tDevice can work with supply 2.6~2.7V");
if(ocr.TwoFive)
sb.AppendLine("\tDevice can work with supply 2.5~2.6V");
if(ocr.TwoFour)
sb.AppendLine("\tDevice can work with supply 2.4~2.5V");
if(ocr.TwoThree)
sb.AppendLine("\tDevice can work with supply 2.3~2.4V");
if(ocr.TwoTwo)
sb.AppendLine("\tDevice can work with supply 2.2~2.3V");
if(ocr.TwoOne)
sb.AppendLine("\tDevice can work with supply 2.1~2.2V");
if(ocr.TwoZero)
sb.AppendLine("\tDevice can work with supply 2.0~2.1V");
if(ocr.OneSix)
sb.AppendLine("\tDevice can work with supply 1.65~1.95V");
return sb.ToString();
}

View File

@@ -38,9 +38,9 @@ namespace DiscImageChef.Decoders.MMC
{
switch(mmcVendorId)
{
case 0x15: return "Samsung";
case 0x2C: return "extreMEmory";
default: return $"Unknown manufacturer ID 0x{mmcVendorId:X2}";
case 0x15: return"Samsung";
case 0x2C: return"extreMEmory";
default: return$"Unknown manufacturer ID 0x{mmcVendorId:X2}";
}
}
}

View File

@@ -38,9 +38,8 @@ using System.Text;
namespace DiscImageChef.Decoders.PCMCIA
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class CIS
{
// TODO: Handle links? Or are they removed in lower layers of the operating system drivers?
@@ -51,15 +50,21 @@ namespace DiscImageChef.Decoders.PCMCIA
while(position < data.Length)
{
Tuple tuple = new Tuple {Code = (TupleCodes)data[position]};
var tuple = new Tuple
{
Code = (TupleCodes)data[position]
};
if(tuple.Code == TupleCodes.CISTPL_NULL) continue;
if(tuple.Code == TupleCodes.CISTPL_NULL)
continue;
if(tuple.Code == TupleCodes.CISTPL_END) break;
if(tuple.Code == TupleCodes.CISTPL_END)
break;
tuple.Link = data[position + 1];
if(position + 2 + tuple.Link > data.Length) break;
if(position + 2 + tuple.Link > data.Length)
break;
tuple.Data = new byte[tuple.Link + 2];
Array.Copy(data, position, tuple.Data, 0, tuple.Link + 2);
@@ -73,31 +78,35 @@ namespace DiscImageChef.Decoders.PCMCIA
public static DeviceGeometryTuple DecodeDeviceGeometryTuple(Tuple tuple)
{
if(tuple == null) return null;
if(tuple == null)
return null;
if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO && tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A) return null;
if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO &&
tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A)
return null;
return tuple.Data == null ? null : DecodeDeviceGeometryTuple(tuple.Data);
}
public static DeviceGeometryTuple DecodeDeviceGeometryTuple(byte[] data)
{
if((data?.Length - 2) % 6 != 0) return null;
if((data?.Length - 2) % 6 != 0)
return null;
DeviceGeometryTuple tuple = new DeviceGeometryTuple();
var tuple = new DeviceGeometryTuple();
List<DeviceGeometry> geometries = new List<DeviceGeometry>();
for(int position = 2; position < data.Length; position += 6)
{
DeviceGeometry geometry = new DeviceGeometry
var geometry = new DeviceGeometry
{
CardInterface = data[position],
EraseBlockSize = data[position + 1],
ReadBlockSize = data[position + 2],
WriteBlockSize = data[position + 3],
Partitions = data[position + 4],
Interleaving = data[position + 5]
CardInterface = data[position], EraseBlockSize = data[position + 1],
ReadBlockSize = data[position + 2],
WriteBlockSize = data[position + 3],
Partitions = data[position + 4],
Interleaving = data[position + 5]
};
geometries.Add(geometry);
}
@@ -110,22 +119,30 @@ namespace DiscImageChef.Decoders.PCMCIA
public static string PrettifyDeviceGeometryTuple(DeviceGeometryTuple tuple)
{
if(tuple == null) return null;
if(tuple == null)
return null;
if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO && tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A) return null;
if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO &&
tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("PCMCIA Device Geometry Tuples:");
foreach(DeviceGeometry geometry in tuple.Geometries)
{
sb.AppendLine("\tGeometry:");
sb.AppendFormat("\t\tDevice width: {0} bits", (1 << (geometry.CardInterface - 1)) * 8).AppendLine();
sb.AppendFormat("\t\tErase block = {0} bytes",
(1 << (geometry.EraseBlockSize - 1)) * (1 << (geometry.Interleaving - 1))).AppendLine();
sb.AppendFormat("\t\tRead block = {0} bytes",
(1 << (geometry.ReadBlockSize - 1)) * (1 << (geometry.Interleaving - 1))).AppendLine();
sb.AppendFormat("\t\tWrite block = {0} bytes",
(1 << (geometry.WriteBlockSize - 1)) * (1 << (geometry.Interleaving - 1))).AppendLine();
sb.AppendFormat("\t\tPartition alignment = {0} bytes",
(1 << (geometry.EraseBlockSize - 1)) * (1 << (geometry.Interleaving - 1)) *
(1 << (geometry.Partitions - 1))).AppendLine();
@@ -142,31 +159,33 @@ namespace DiscImageChef.Decoders.PCMCIA
public static ManufacturerIdentificationTuple DecodeManufacturerIdentificationTuple(Tuple tuple)
{
if(tuple?.Code != TupleCodes.CISTPL_MANFID) return null;
if(tuple?.Code != TupleCodes.CISTPL_MANFID)
return null;
return tuple.Data == null ? null : DecodeManufacturerIdentificationTuple(tuple.Data);
}
public static ManufacturerIdentificationTuple DecodeManufacturerIdentificationTuple(byte[] data)
{
if(data == null) return null;
if(data == null)
return null;
if(data.Length < 6) return null;
if(data.Length < 6)
return null;
return new ManufacturerIdentificationTuple
{
Code = (TupleCodes)data[0],
Link = data[1],
ManufacturerID = BitConverter.ToUInt16(data, 2),
CardID = BitConverter.ToUInt16(data, 4)
Code = (TupleCodes)data[0], Link = data[1], ManufacturerID = BitConverter.ToUInt16(data, 2),
CardID = BitConverter.ToUInt16(data, 4)
};
}
public static string PrettifyManufacturerIdentificationTuple(ManufacturerIdentificationTuple tuple)
{
if(tuple?.Code != TupleCodes.CISTPL_MANFID) return null;
if(tuple?.Code != TupleCodes.CISTPL_MANFID)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("PCMCIA Manufacturer Identification Tuple:");
sb.AppendFormat("\tManufacturer ID: {0}", VendorCode.Prettify(tuple.ManufacturerID)).AppendLine();
sb.AppendFormat("\tCard ID:D 0x{0:X4}", tuple.CardID).AppendLine();
@@ -182,40 +201,46 @@ namespace DiscImageChef.Decoders.PCMCIA
public static Level1VersionTuple DecodeLevel1VersionTuple(Tuple tuple)
{
if(tuple?.Code != TupleCodes.CISTPL_VERS_1) return null;
if(tuple?.Code != TupleCodes.CISTPL_VERS_1)
return null;
return tuple.Data == null ? null : DecodeLevel1VersionTuple(tuple.Data);
}
public static Level1VersionTuple DecodeLevel1VersionTuple(byte[] data)
{
if(data == null) return null;
if(data == null)
return null;
if(data.Length < 4) return null;
if(data.Length < 4)
return null;
List<byte> buffer = new List<byte>();
List<string> strings = null;
bool firstString = false;
bool secondString = false;
Level1VersionTuple tuple = new Level1VersionTuple
var tuple = new Level1VersionTuple
{
Code = (TupleCodes)data[0], Link = data[1], MajorVersion = data[2], MinorVersion = data[3]
};
for(int position = 4; position < data.Length; position++)
{
if(data[position] == 0xFF) break;
if(data[position] == 0xFF)
break;
buffer.Add(data[position]);
if(data[position] != 0x00) continue;
if(data[position] != 0x00)
continue;
if(!firstString)
{
tuple.Manufacturer = StringHandlers.CToString(buffer.ToArray());
buffer = new List<byte>();
firstString = true;
continue;
}
@@ -225,41 +250,51 @@ namespace DiscImageChef.Decoders.PCMCIA
tuple.Product = StringHandlers.CToString(buffer.ToArray());
buffer = new List<byte>();
firstString = true;
continue;
}
if(strings == null) strings = new List<string>();
if(strings == null)
strings = new List<string>();
strings.Add(StringHandlers.CToString(buffer.ToArray()));
buffer = new List<byte>();
}
if(strings != null) tuple.AdditionalInformation = strings.ToArray();
if(strings != null)
tuple.AdditionalInformation = strings.ToArray();
return tuple;
}
public static string PrettifyLevel1VersionTuple(Level1VersionTuple tuple)
{
if(tuple?.Code != TupleCodes.CISTPL_VERS_1) return null;
if(tuple?.Code != TupleCodes.CISTPL_VERS_1)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("PCMCIA Level 1 Version / Product Information Tuple:");
sb.AppendFormat("\tCard indicates compliance with PC Card Standard Release {0}.{1}", tuple.MajorVersion,
tuple.MinorVersion).AppendLine();
if(string.IsNullOrEmpty(tuple.Manufacturer)) sb.AppendLine("\tNo manufacturer information string.");
else sb.AppendFormat("\tManufacturer: {0}", tuple.Manufacturer).AppendLine();
if(string.IsNullOrEmpty(tuple.Manufacturer))
sb.AppendLine("\tNo manufacturer information string.");
else
sb.AppendFormat("\tManufacturer: {0}", tuple.Manufacturer).AppendLine();
if(string.IsNullOrEmpty(tuple.Product)) sb.AppendLine("\tNo product name string.");
else sb.AppendFormat("\tProduct name: {0}", tuple.Product).AppendLine();
if(string.IsNullOrEmpty(tuple.Product))
sb.AppendLine("\tNo product name string.");
else
sb.AppendFormat("\tProduct name: {0}", tuple.Product).AppendLine();
if(tuple.AdditionalInformation == null || tuple.AdditionalInformation.Length == 0)
if(tuple.AdditionalInformation == null ||
tuple.AdditionalInformation.Length == 0)
sb.AppendLine("\tNo additional information.");
else
{
sb.AppendLine("\tAdditional information:");
foreach(string info in tuple.AdditionalInformation.Where(info => !string.IsNullOrEmpty(info)))
sb.AppendFormat("\t\t{0}", info).AppendLine();
}

View File

@@ -34,263 +34,88 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.PCMCIA
{
/// <summary>
/// Tuple codes.
/// </summary>
/// <summary>Tuple codes.</summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum TupleCodes : byte
{
/// <summary>
/// Checksum control
/// </summary>
CISTPL_CHECKSUM = 0x10,
/// <summary>
/// End-of-chain
/// </summary>
CISTPL_END = 0xFF,
/// <summary>
/// Indirect access PC Card memory
/// </summary>
CISTPL_INDIRECT = 0x03,
/// <summary>
/// Link-target-control
/// </summary>
CISTPL_LINKTARGET = 0x13,
/// <summary>
/// Longlink to attribute memory
/// </summary>
CISTPL_LONGLINK_A = 0x11,
/// <summary>
/// Longlink to common memory
/// </summary>
CISTPL_LONGLINK_C = 0x12,
/// <summary>
/// Longlink to next chain on a Cardbus PC Card
/// </summary>
CISTPL_LONGLINK_CB = 0x02,
/// <summary>
/// Longlink to function specific chains
/// </summary>
CISTPL_LONGLINK_MFC = 0x06,
/// <summary>
/// No-link to common memory
/// </summary>
CISTPL_NO_LINK = 0x14,
/// <summary>
/// Null tuple
/// </summary>
CISTPL_NULL = 0x00,
/// <summary>
/// Alternate language string
/// </summary>
CISTPL_ALTSTR = 0x16,
/// <summary>
/// Common memory device information
/// </summary>
CISTPL_DEVICE = 0x01,
/// <summary>
/// Attribute memory device information
/// </summary>
CISTPL_DEVICE_A = 0x17,
/// <summary>
/// Other operating conditions information for attribute memory
/// </summary>
CISTPL_DEVICE_OA = 0x1D,
/// <summary>
/// Other operating conditions information for common memory
/// </summary>
CISTPL_DEVICE_OC = 0x1C,
/// <summary>
/// Device geometry information for common memory
/// </summary>
CISTPL_DEVICEGEO = 0x1E,
/// <summary>
/// Device geometry information for attribute memory
/// </summary>
CISTPL_DEVICEGEO_A = 0x1F,
/// <summary>
/// Extended common memory device information
/// </summary>
CISTPL_EXTDEVIC = 0x09,
/// <summary>
/// Function extensions
/// </summary>
CISTPL_FUNCE = 0x22,
/// <summary>
/// Function class identification
/// </summary>
CISTPL_FUNCID = 0x21,
/// <summary>
/// JEDEC programming information for attribute memory
/// </summary>
CISTPL_JEDEC_A = 0x19,
/// <summary>
/// JEDEC programming information for common memory
/// </summary>
CISTPL_JEDEC_C = 0x18,
/// <summary>
/// Manufacturer identification string
/// </summary>
CISTPL_MANFID = 0x20,
/// <summary>
/// Level 1 version/product information
/// </summary>
CISTPL_VERS_1 = 0x15,
/// <summary>
/// BAR for a CardBus PC Card
/// </summary>
CISTPL_BAR = 0x07,
/// <summary>
/// Configuration-table-entry
/// </summary>
CISTPL_CFTABLE_ENTRY = 0x1B,
/// <summary>
/// Configuration-table-entry for a CardBus PC Card
/// </summary>
CISTPL_CFTABLE_ENTRY_CB = 0x05,
/// <summary>
/// Configuration tuple for a 16-bit PC Card
/// </summary>
CISTPL_CONFIG = 0x1A,
/// <summary>
/// Configuration tuple for a CardBus PC Card
/// </summary>
CISTPL_CONFIG_CB = 0x04,
/// <summary>
/// Function state save/restore definition
/// </summary>
CISTPL_PWR_MGMNT = 0x08,
/// <summary>
/// Battery replacement date
/// </summary>
CISTPL_BATTERY = 0x45,
/// <summary>
/// Card initialization date
/// </summary>
CISTPL_DATE = 0x44,
/// <summary>
/// Level 2 version/product information
/// </summary>
CISTPL_VERS_2 = 0x40,
/// <summary>
/// Byte ordering for disk-like partitions
/// </summary>
CISTPL_BYTEORDER = 0x43,
/// <summary>
/// Data recording format for common memory
/// </summary>
CISTPL_FORMAT = 0x41,
/// <summary>
/// Data recording format for attribute memory
/// </summary>
CISTPL_FORMAT_A = 0x47,
/// <summary>
/// Partition geometry
/// </summary>
CISTPL_GEOMETRY = 0x42,
/// <summary>
/// Software interleaving
/// </summary>
CISTPL_SWIL = 0x23,
/// <summary>
/// Partition organization
/// </summary>
CISTPL_ORG = 0x46,
/// <summary>
/// Special purpose
/// </summary>
/// <summary>Checksum control</summary>
CISTPL_CHECKSUM = 0x10, /// <summary>End-of-chain</summary>
CISTPL_END = 0xFF, /// <summary>Indirect access PC Card memory</summary>
CISTPL_INDIRECT = 0x03, /// <summary>Link-target-control</summary>
CISTPL_LINKTARGET = 0x13, /// <summary>Longlink to attribute memory</summary>
CISTPL_LONGLINK_A = 0x11, /// <summary>Longlink to common memory</summary>
CISTPL_LONGLINK_C = 0x12, /// <summary>Longlink to next chain on a Cardbus PC Card</summary>
CISTPL_LONGLINK_CB = 0x02, /// <summary>Longlink to function specific chains</summary>
CISTPL_LONGLINK_MFC = 0x06, /// <summary>No-link to common memory</summary>
CISTPL_NO_LINK = 0x14, /// <summary>Null tuple</summary>
CISTPL_NULL = 0x00, /// <summary>Alternate language string</summary>
CISTPL_ALTSTR = 0x16, /// <summary>Common memory device information</summary>
CISTPL_DEVICE = 0x01, /// <summary>Attribute memory device information</summary>
CISTPL_DEVICE_A = 0x17, /// <summary>Other operating conditions information for attribute memory</summary>
CISTPL_DEVICE_OA = 0x1D, /// <summary>Other operating conditions information for common memory</summary>
CISTPL_DEVICE_OC = 0x1C, /// <summary>Device geometry information for common memory</summary>
CISTPL_DEVICEGEO = 0x1E, /// <summary>Device geometry information for attribute memory</summary>
CISTPL_DEVICEGEO_A = 0x1F, /// <summary>Extended common memory device information</summary>
CISTPL_EXTDEVIC = 0x09, /// <summary>Function extensions</summary>
CISTPL_FUNCE = 0x22, /// <summary>Function class identification</summary>
CISTPL_FUNCID = 0x21, /// <summary>JEDEC programming information for attribute memory</summary>
CISTPL_JEDEC_A = 0x19, /// <summary>JEDEC programming information for common memory</summary>
CISTPL_JEDEC_C = 0x18, /// <summary>Manufacturer identification string</summary>
CISTPL_MANFID = 0x20, /// <summary>Level 1 version/product information</summary>
CISTPL_VERS_1 = 0x15, /// <summary>BAR for a CardBus PC Card</summary>
CISTPL_BAR = 0x07, /// <summary>Configuration-table-entry</summary>
CISTPL_CFTABLE_ENTRY = 0x1B, /// <summary>Configuration-table-entry for a CardBus PC Card</summary>
CISTPL_CFTABLE_ENTRY_CB = 0x05, /// <summary>Configuration tuple for a 16-bit PC Card</summary>
CISTPL_CONFIG = 0x1A, /// <summary>Configuration tuple for a CardBus PC Card</summary>
CISTPL_CONFIG_CB = 0x04, /// <summary>Function state save/restore definition</summary>
CISTPL_PWR_MGMNT = 0x08, /// <summary>Battery replacement date</summary>
CISTPL_BATTERY = 0x45, /// <summary>Card initialization date</summary>
CISTPL_DATE = 0x44, /// <summary>Level 2 version/product information</summary>
CISTPL_VERS_2 = 0x40, /// <summary>Byte ordering for disk-like partitions</summary>
CISTPL_BYTEORDER = 0x43, /// <summary>Data recording format for common memory</summary>
CISTPL_FORMAT = 0x41, /// <summary>Data recording format for attribute memory</summary>
CISTPL_FORMAT_A = 0x47, /// <summary>Partition geometry</summary>
CISTPL_GEOMETRY = 0x42, /// <summary>Software interleaving</summary>
CISTPL_SWIL = 0x23, /// <summary>Partition organization</summary>
CISTPL_ORG = 0x46, /// <summary>Special purpose</summary>
CISTPL_SPCL = 0x90
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DeviceTypeCodes : byte
{
/// <summary>
/// No device, used to designate a hole
/// </summary>
DTYPE_NULL = 0,
/// <summary>
/// Masked ROM
/// </summary>
DTYPE_ROM = 1,
/// <summary>
/// One-type-programmable ROM
/// </summary>
DTYPE_OTPROM = 2,
/// <summary>
/// UV-Erasable Programmable ROM
/// </summary>
DTYPE_EPROM = 3,
/// <summary>
/// Electronically-Erasable Programmable ROM
/// </summary>
DTYPE_EEPROM = 4,
/// <summary>
/// Flash memory
/// </summary>
DTYPE_FLASH = 5,
/// <summary>
/// Static RAM
/// </summary>
DTYPE_SRAM = 6,
/// <summary>
/// Dynamic RAM
/// </summary>
DTYPE_DRAM = 7,
/// <summary>
/// Function-specific memory address range
/// </summary>
DTYPE_FUNCSPEC = 13,
/// <summary>
/// Extended type follows
/// </summary>
/// <summary>No device, used to designate a hole</summary>
DTYPE_NULL = 0, /// <summary>Masked ROM</summary>
DTYPE_ROM = 1, /// <summary>One-type-programmable ROM</summary>
DTYPE_OTPROM = 2, /// <summary>UV-Erasable Programmable ROM</summary>
DTYPE_EPROM = 3, /// <summary>Electronically-Erasable Programmable ROM</summary>
DTYPE_EEPROM = 4, /// <summary>Flash memory</summary>
DTYPE_FLASH = 5, /// <summary>Static RAM</summary>
DTYPE_SRAM = 6, /// <summary>Dynamic RAM</summary>
DTYPE_DRAM = 7, /// <summary>Function-specific memory address range</summary>
DTYPE_FUNCSPEC = 13, /// <summary>Extended type follows</summary>
DTYPE_EXTEND = 14
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum DeviceSpeedCodes : byte
{
/// <summary>
/// No device
/// </summary>
DSPEED_NULL = 0,
/// <summary>
/// 250 ns
/// </summary>
DSPEED_250NS = 1,
/// <summary>
/// 200 ns
/// </summary>
DSPEED_200NS = 2,
/// <summary>
/// 150 ns
/// </summary>
DSPEED_150NS = 3,
/// <summary>
/// 100 ns
/// </summary>
DSPEED_100NS = 4,
/// <summary>
/// Extended speed follows
/// </summary>
/// <summary>No device</summary>
DSPEED_NULL = 0, /// <summary>250 ns</summary>
DSPEED_250NS = 1, /// <summary>200 ns</summary>
DSPEED_200NS = 2, /// <summary>150 ns</summary>
DSPEED_150NS = 3, /// <summary>100 ns</summary>
DSPEED_100NS = 4, /// <summary>Extended speed follows</summary>
DSPEED_EXT = 7
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum FunctionCodes : byte
{
MultiFunction = 0x00,
Memory = 0x01,
Serial = 0x02,
Parallel = 0x03,
FixedDisk = 0x04,
Video = 0x05,
Network = 0x06,
AIMS = 0x07,
SCSI = 0x08,
Security = 0x09,
Instrument = 0x0A,
HighSpeedSerial = 0x0B,
VendorSpecific = 0xFE
MultiFunction = 0x00, Memory = 0x01, Serial = 0x02,
Parallel = 0x03, FixedDisk = 0x04, Video = 0x05,
Network = 0x06, AIMS = 0x07, SCSI = 0x08,
Security = 0x09, Instrument = 0x0A, HighSpeedSerial = 0x0B,
VendorSpecific = 0xFE
}
}

View File

@@ -34,181 +34,128 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.PCMCIA
{
/// <summary>
/// Basic classure of a PCMCIA tuple
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Basic classure of a PCMCIA tuple</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class Tuple
{
public TupleCodes Code;
public byte Link;
public byte[] Data;
public byte Link;
}
/// <summary>
/// Checksum tuple
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Checksum tuple</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class ChecksumTuple
{
/// <summary>Modulo-256 sum of region</summary>
public byte Checksum;
/// <summary>
/// <see cref="TupleCodes.CISTPL_CHECKSUM" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
public byte Link;
/// <summary>
/// Offset to region to be checksummed
/// </summary>
public short Offset;
/// <summary>
/// Length of region to be checksummed
/// </summary>
/// <summary>Length of region to be checksummed</summary>
public ushort Length;
/// <summary>
/// Modulo-256 sum of region
/// </summary>
public byte Checksum;
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>Offset to region to be checksummed</summary>
public short Offset;
}
/// <summary>
/// Indirect Access PC Card Memory
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Indirect Access PC Card Memory</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class IndirectTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_INDIRECT" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
}
/// <summary>
/// Link target tuple
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Link target tuple</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class LinkTargetTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_LINKTARGET" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>
/// 'C''I''S' in ASCII
/// </summary>
/// <summary>'C''I''S' in ASCII</summary>
public byte[] Tag;
}
/// <summary>
/// 16-bit PC Card Long Link Tuple
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>16-bit PC Card Long Link Tuple</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class LongLinkTuple
{
/// <summary>Target address</summary>
public uint Address;
/// <summary>
/// <see cref="TupleCodes.CISTPL_LONGLINK_A" /> or <see cref="TupleCodes.CISTPL_LONGLINK_C" /> or
/// <see cref="TupleCodes.CISTPL_LONGLINK_CB" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>
/// Target address
/// </summary>
public uint Address;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"),
SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
public class ConfigurationAddress
{
/// <summary>
/// Target address space, 0 = attribute, 1 = common
/// </summary>
public byte TargetAddressSpace;
/// <summary>
/// Target address
/// </summary>
/// <summary>Target address</summary>
public uint Address;
/// <summary>Target address space, 0 = attribute, 1 = common</summary>
public byte TargetAddressSpace;
}
/// <summary>
/// Multiple function link tuple
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
/// <summary>Multiple function link tuple</summary>
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class MultipleFunctionLinkTuple
{
/// <summary>Link to more configuration registers</summary>
public ConfigurationAddress[] Addresses;
/// <summary>
/// <see cref="TupleCodes.CISTPL_LONGLINK_MFC" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>
/// How many functions follow
/// </summary>
/// <summary>How many functions follow</summary>
public byte NumberFunctions;
/// <summary>
/// Link to more configuration registers
/// </summary>
public ConfigurationAddress[] Addresses;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class NoLinkTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_NO_LINK" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class AlternateStringTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_ALTSTR" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>
/// Array of strings. On memory they're preceded by an ISO Escape Code indicating codepage. Here they're stored as
@@ -217,335 +164,218 @@ namespace DiscImageChef.Decoders.PCMCIA
public string[] Strings;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"),
SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
public class ExtendedDeviceSpeed
{
/// <summary>
/// Another extended follows
/// </summary>
public bool Extended;
/// <summary>
/// Speed mantisa
/// </summary>
public byte Mantissa;
/// <summary>
/// Speed exponent
/// </summary>
/// <summary>Speed exponent</summary>
public byte Exponent;
/// <summary>Another extended follows</summary>
public bool Extended;
/// <summary>Speed mantisa</summary>
public byte Mantissa;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public struct DeviceInfo
{
/// <summary>
/// Device type code
/// </summary>
/// <summary>Device type code</summary>
public DeviceTypeCodes Type;
/// <summary>
/// Write protected
/// </summary>
/// <summary>Write protected</summary>
public bool WPS;
/// <summary>
/// Speed code
/// </summary>
/// <summary>Speed code</summary>
public DeviceSpeedCodes Speed;
/// <summary>
/// Extended speeds
/// </summary>
/// <summary>Extended speeds</summary>
public ExtendedDeviceSpeed[] ExtendedSpeeds;
/// <summary>
/// Extended types
/// </summary>
/// <summary>Extended types</summary>
public byte[] ExtendedTypes;
/// <summary>
/// Size in units - 1
/// </summary>
/// <summary>Size in units - 1</summary>
public byte Units;
/// <summary>
/// Code to define units unit
/// </summary>
/// <summary>Code to define units unit</summary>
public byte SizeCode;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class DeviceTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_DEVICE" /> or <see cref="TupleCodes.CISTPL_DEVICE_A" />
/// </summary>
/// <summary><see cref="TupleCodes.CISTPL_DEVICE" /> or <see cref="TupleCodes.CISTPL_DEVICE_A" /></summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
public byte Link;
/// <summary>
/// Array of device information bytes
/// </summary>
/// <summary>Array of device information bytes</summary>
public DeviceInfo[] Infos;
/// <summary>Link to next tuple</summary>
public byte Link;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public struct OtherConditionInfo
{
/// <summary>
/// True if another other condition info follows
/// </summary>
/// <summary>True if another other condition info follows</summary>
public bool Extended;
/// <summary>
/// Vcc used
/// </summary>
/// <summary>Vcc used</summary>
public byte VccUsed;
/// <summary>
/// Supports WAIT# signal
/// </summary>
/// <summary>Supports WAIT# signal</summary>
public bool MWAIT;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class OtherConditionTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_DEVICE_OC" /> or <see cref="TupleCodes.CISTPL_DEVICE_OA" />
/// </summary>
/// <summary><see cref="TupleCodes.CISTPL_DEVICE_OC" /> or <see cref="TupleCodes.CISTPL_DEVICE_OA" /></summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
public byte Link;
/// <summary>
/// Array of other condition information bytes
/// </summary>
public OtherConditionInfo[] OtherConditionInfos;
/// <summary>
/// Array of device information bytes
/// </summary>
/// <summary>Array of device information bytes</summary>
public DeviceInfo[] Infos;
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>Array of other condition information bytes</summary>
public OtherConditionInfo[] OtherConditionInfos;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public struct DeviceGeometry
{
/// <summary>
/// 1 &lt;&lt; n-1 bytes, 2 = 16-bit PC Card, 3 = CardBus PC Card
/// </summary>
/// <summary>1 &lt;&lt; n-1 bytes, 2 = 16-bit PC Card, 3 = CardBus PC Card</summary>
public byte CardInterface;
/// <summary>
/// Erase block size in 1 &lt;&lt; n-1 increments of <see cref="CardInterface" /> wide accesses.
/// If n == 4, and <see cref="CardInterface" /> == 16, erase block size = 32 * 4 = 128 bytes
/// Erase block size in 1 &lt;&lt; n-1 increments of <see cref="CardInterface" /> wide accesses. If n == 4, and
/// <see cref="CardInterface" /> == 16, erase block size = 32 * 4 = 128 bytes
/// </summary>
public byte EraseBlockSize;
/// <summary>
/// Read block size in 1 &lt;&lt; n-1 increments of <see cref="CardInterface" /> wide accesses.
/// If n == 4, and <see cref="CardInterface" /> == 16, read block size = 32 * 4 = 128 bytes
/// Read block size in 1 &lt;&lt; n-1 increments of <see cref="CardInterface" /> wide accesses. If n == 4, and
/// <see cref="CardInterface" /> == 16, read block size = 32 * 4 = 128 bytes
/// </summary>
public byte ReadBlockSize;
/// <summary>
/// Write block size in 1 &lt;&lt; n-1 increments of <see cref="CardInterface" /> wide accesses.
/// If n == 4, and <see cref="CardInterface" /> == 16, write block size = 32 * 4 = 128 bytes
/// Write block size in 1 &lt;&lt; n-1 increments of <see cref="CardInterface" /> wide accesses. If n == 4, and
/// <see cref="CardInterface" /> == 16, write block size = 32 * 4 = 128 bytes
/// </summary>
public byte WriteBlockSize;
/// <summary>
/// Device partitioning in granularity of 1 &lt;&lt; n-1 erase blocks
/// If n == 4, and erase block is 128 bytes, partitions must be aligned to 32 erase block, or 4096 bytes
/// Device partitioning in granularity of 1 &lt;&lt; n-1 erase blocks If n == 4, and erase block is 128 bytes,
/// partitions must be aligned to 32 erase block, or 4096 bytes
/// </summary>
public byte Partitions;
/// <summary>
/// Card employs a multiple of 1 &lt;&lt; n-1 times interleaving the entire memory arrays
/// </summary>
/// <summary>Card employs a multiple of 1 &lt;&lt; n-1 times interleaving the entire memory arrays</summary>
public byte Interleaving;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public class DeviceGeometryTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_DEVICEGEO" /> or <see cref="TupleCodes.CISTPL_DEVICEGEO_A" />
/// </summary>
/// <summary><see cref="TupleCodes.CISTPL_DEVICEGEO" /> or <see cref="TupleCodes.CISTPL_DEVICEGEO_A" /></summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
public byte Link;
/// <summary>
/// Array of device geometries
/// </summary>
/// <summary>Array of device geometries</summary>
public DeviceGeometry[] Geometries;
/// <summary>Link to next tuple</summary>
public byte Link;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class FunctionIdentificationTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_FUNCID" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
public byte Link;
/// <summary>
/// Function code
/// </summary>
/// <summary>Function code</summary>
public FunctionCodes Function;
/// <summary>
/// Device contains boot ROM
/// </summary>
public bool ROM;
/// <summary>
/// Device wants to be part of power-on-self-test
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>Device wants to be part of power-on-self-test</summary>
public bool POST;
/// <summary>Device contains boot ROM</summary>
public bool ROM;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public class ManufacturerIdentificationTuple
{
/// <summary>Card ID</summary>
public ushort CardID;
/// <summary>
/// <see cref="TupleCodes.CISTPL_MANFID" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>
/// Manufacturer ID
/// </summary>
/// <summary>Manufacturer ID</summary>
public ushort ManufacturerID;
/// <summary>
/// Card ID
/// </summary>
public ushort CardID;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public class Level1VersionTuple
{
/// <summary>Additional information strings</summary>
public string[] AdditionalInformation;
/// <summary>
/// <see cref="TupleCodes.CISTPL_VERS_1" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>
/// Major version of standard compliance
/// </summary>
/// <summary>Major version of standard compliance</summary>
public byte MajorVersion;
/// <summary>
/// Minor version of standard compliance
/// </summary>
public byte MinorVersion;
/// <summary>
/// Manufacturer string
/// </summary>
/// <summary>Manufacturer string</summary>
public string Manufacturer;
/// <summary>
/// Product string
/// </summary>
/// <summary>Minor version of standard compliance</summary>
public byte MinorVersion;
/// <summary>Product string</summary>
public string Product;
/// <summary>
/// Additional information strings
/// </summary>
public string[] AdditionalInformation;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class Level2VersionTuple
{
/// <summary>Address of first data byte</summary>
public ushort Address;
/// <summary>Number of copies of CIS present</summary>
public byte CISCopies;
/// <summary>
/// <see cref="TupleCodes.CISTPL_VERS_2" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
public byte Link;
/// <summary>
/// Version of this classure
/// </summary>
public byte StructureVersion;
/// <summary>
/// Level of compliance
/// </summary>
/// <summary>Level of compliance</summary>
public byte Compliance;
/// <summary>
/// Address of first data byte
/// </summary>
public ushort Address;
/// <summary>
/// Vendor-specific byte
/// </summary>
public byte VendorSpecific1;
/// <summary>
/// Vendor-specific byte
/// </summary>
public byte VendorSpecific2;
/// <summary>
/// Number of copies of CIS present
/// </summary>
public byte CISCopies;
/// <summary>
/// Vendor of software that formatted the card
/// </summary>
public string OEM;
/// <summary>
/// Informational message about the card
/// </summary>
/// <summary>Informational message about the card</summary>
public string Information;
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>Vendor of software that formatted the card</summary>
public string OEM;
/// <summary>Version of this classure</summary>
public byte StructureVersion;
/// <summary>Vendor-specific byte</summary>
public byte VendorSpecific1;
/// <summary>Vendor-specific byte</summary>
public byte VendorSpecific2;
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class GeometryTuple
{
/// <summary>
/// <see cref="TupleCodes.CISTPL_GEOMETRY" />
/// </summary>
public TupleCodes Code;
/// <summary>
/// Link to next tuple
/// </summary>
public byte Link;
/// <summary>
/// Sectors per track
/// </summary>
public byte SectorsPerTrack;
/// <summary>
/// Tracks per cylinder
/// </summary>
public byte TracksPerCylinder;
/// <summary>
/// Cylinders
/// </summary>
/// <summary>Cylinders</summary>
public ushort Cylinders;
/// <summary>Link to next tuple</summary>
public byte Link;
/// <summary>Sectors per track</summary>
public byte SectorsPerTrack;
/// <summary>Tracks per cylinder</summary>
public byte TracksPerCylinder;
}
}

View File

@@ -42,321 +42,321 @@ namespace DiscImageChef.Decoders.PCMCIA
switch(id)
{
#region JEDEC
case 0x01: return "AMD";
case 0x02: return "AMI";
case 0x83: return "Fairchild";
case 0x04: return "Fujitsu";
case 0x85: return "GTE";
case 0x86: return "Harris";
case 0x07: return "Hitachi";
case 0x08: return "Inmos";
case 0x89: return "Intel";
case 0x8A: return "I.T.T.";
case 0x0B: return "Intersil";
case 0x8C: return "Monolithic Memories";
case 0x0D: return "Mostek";
case 0x0E: return "Freescale";
case 0x8F: return "National";
case 0x10: return "NEC";
case 0x91: return "RCA";
case 0x92: return "Raytheon";
case 0x13: return "Conexant";
case 0x94: return "Seeq";
case 0x15: return "NXP";
case 0x16: return "Synertek";
case 0x97: return "Texas Instruments";
case 0x98: return "Toshiba";
case 0x19: return "Xicor";
case 0x1A: return "Zilog";
case 0x9B: return "Eurotechnique";
case 0x1C: return "Mitsubishi2";
case 0x9D: return "Lucent";
case 0x9E: return "Exel";
case 0x1F: return "Atmel";
case 0x20: return "SGS/Thomson";
case 0xA1: return "Lattice Semiconductor";
case 0xA2: return "NCR";
case 0x23: return "Wafer Scale Integration";
case 0xA4: return "International Business Machines";
case 0x25: return "Tristar";
case 0x26: return "Visic";
case 0xA7: return "International CMOS Technology";
case 0xA8: return "SSSI";
case 0x29: return "Microchip Technology";
case 0x2A: return "Ricoh";
case 0xAB: return "VLSI";
case 0x2C: return "Micron Technology";
case 0xAD: return "Hynix Semiconductor";
case 0xAE: return "OKI Semiconductor";
case 0x2F: return "ACTEL";
case 0xB0: return "Sharp";
case 0x31: return "Catalyst";
case 0x32: return "Panasonic";
case 0xB3: return "IDT";
case 0x34: return "Cypress";
case 0xB5: return "Digital Equipment Corporation";
case 0xB6: return "LSI Logic";
case 0x37: return "Zarlink";
case 0x38: return "UTMC";
case 0xB9: return "Thinking Machine";
case 0xBA: return "Thomson CSF";
case 0x3B: return "Integrated CMOS";
case 0xBC: return "Honeywell";
case 0x3D: return "Tektronix";
case 0x3E: return "Oracle Corporation";
case 0xBF: return "Silicon Storage Technology";
case 0x40: return "ProMos";
case 0xC1: return "Infineon";
case 0xC2: return "Macronix";
case 0x43: return "Xerox";
case 0xC4: return "Plus Logic";
case 0x45: return "SanDisk Corporation";
case 0x46: return "Elan Circuit Technology";
case 0xC7: return "European Silicon";
case 0xC8: return "Apple";
case 0x49: return "Xilinx";
case 0x4A: return "Compaq";
case 0xCB: return "Protocol Engines";
case 0x4C: return "SCI";
case 0xCD: return "Seiko Instruments";
case 0xCE: return "Samsung";
case 0x4F: return "I3 Design System";
case 0xD0: return "Klic";
case 0x51: return "Crosspoint Solutions";
case 0x52: return "Alliance Semiconductor";
case 0xD3: return "Tandem";
case 0x54: return "Hewlett-Packard";
case 0xD5: return "Integrated Silicon Solutions";
case 0xD6: return "Brooktree";
case 0x57: return "New Media";
case 0x58: return "MHS Electronic";
case 0xD9: return "Performance Semiconductors";
case 0xDA: return "Winbond Electronic";
case 0x5B: return "Kawasaki Steel";
case 0x5D: return "TECMAR";
case 0x5E: return "Exar";
case 0xDF: return "PCMCIA";
case 0xE0: return "LG Semiconductor";
case 0x61: return "Northern Telecom";
case 0x62: return "Sanyo2";
case 0xE3: return "Array Microsystems";
case 0x64: return "Crystal Semiconductor";
case 0xE5: return "Analog Devices";
case 0xE6: return "PMC-Sierra";
case 0x67: return "Asparix";
case 0x68: return "Convex Computer";
case 0xE9: return "Nimbus Technology";
case 0x6B: return "Transwitch";
case 0xEC: return "Micronas";
case 0x6D: return "Canon";
case 0x6E: return "Altera";
case 0xEF: return "NEXCOM";
case 0x70: return "Qualcomm";
case 0xF1: return "Sony";
case 0xF2: return "Cray Research";
case 0x73: return "AMS";
case 0xF4: return "Vitesse";
case 0x75: return "Aster Electronics";
case 0x76: return "Bay Networks";
case 0xF7: return "Zentrum";
case 0xF8: return "TRW";
case 0x79: return "Thesys";
case 0x7A: return "Solbourne Computer";
case 0xFB: return "Allied-Signal";
case 0x7C: return "Dialog Semiconductor";
case 0xFD: return "Media Vision";
case 0xFE: return "Numonyx Corporation";
case 0x7F01: return "Cirrus Logic";
case 0x7F02: return "National Instruments";
case 0x7F04: return "Alcatel Mietec";
case 0x7F07: return "JTAG Technologies";
case 0x7F08: return "Loral";
case 0x7F0B: return "Bestlink Systems";
case 0x7F0D: return "GENNUM";
case 0x7F0E: return "VideoLogic";
case 0x7F10: return "Chip Express";
case 0x7F13: return "TCSI";
case 0x7F15: return "Hughes Aircraft";
case 0x7F16: return "Lanstar Semiconductor";
case 0x7F19: return "Music Semi";
case 0x7F1A: return "Ericsson Components";
case 0x7F1C: return "Eon Silicon Devices";
case 0x7F1F: return "Integ.Memories Tech.";
case 0x7F20: return "Corollary Inc.";
case 0x7F23: return "EIV(Switzerland)";
case 0x7F25: return "Zarlink(formerly Mitel)";
case 0x7F26: return "Clearpoint";
case 0x7F29: return "Vanguard";
case 0x7F2A: return "Hagiwara Sys-Com";
case 0x7F2C: return "Celestica";
case 0x7F2F: return "Rohm Company Ltd.";
case 0x7F31: return "Libit Signal Processing";
case 0x7F32: return "Enhanced Memories Inc.";
case 0x7F34: return "Adaptec Inc.";
case 0x7F37: return "AMIC Technology";
case 0x7F38: return "Adobe Systems";
case 0x7F3B: return "Newport Digital";
case 0x7F3D: return "T Square";
case 0x7F3E: return "Seiko Epson";
case 0x7F40: return "Viking Components";
case 0x7F43: return "Suwa Electronics";
case 0x7F45: return "Micron CMS";
case 0x7F46: return "American Computer &Digital Components Inc";
case 0x7F49: return "CPU Design";
case 0x7F4A: return "Price Point";
case 0x7F4C: return "Tellabs";
case 0x7F4F: return "Transcend Information";
case 0x7F51: return "CKD Corporation Ltd.";
case 0x7F52: return "Capital Instruments, Inc.";
case 0x7F54: return "Linvex Technology";
case 0x7F57: return "Dynamem, Inc.";
case 0x7F58: return "NERA ASA";
case 0x7F5B: return "Acorn Computers";
case 0x7F5D: return "Oak Technology, Inc.";
case 0x7F5E: return "Itec Memory";
case 0x7F61: return "Wintec Industries";
case 0x7F62: return "Super PC Memory";
case 0x7F64: return "Galvantech";
case 0x7F67: return "GateField";
case 0x7F68: return "Integrated Memory System";
case 0x7F6B: return "Goldenram";
case 0x7F6D: return "Cimaron Communications";
case 0x7F6E: return "Nippon Steel Semi.Corp.";
case 0x7F70: return "AMCC";
case 0x7F73: return "Digital Microwave";
case 0x7F75: return "MIMOS Semiconductor";
case 0x7F76: return "Advanced Fibre";
case 0x7F79: return "Acbel Polytech Inc.";
case 0x7F7A: return "Apacer Technology";
case 0x7F7C: return "FOXCONN";
case 0x7F83: return "ILC Data Device";
case 0x7F85: return "Micro Linear";
case 0x7F86: return "Univ.Of NC";
case 0x7F89: return "Nchip";
case 0x7F8A: return "Galileo Tech";
case 0x7F8C: return "Graychip";
case 0x7F8F: return "Robert Bosch";
case 0x7F91: return "DATARAM";
case 0x7F92: return "United Microelec Corp.";
case 0x7F94: return "Smart Modular";
case 0x7F97: return "Qlogic";
case 0x7F98: return "Kingston";
case 0x7F9B: return "SpaSE";
case 0x7F9D: return "Programmable Micro Corp";
case 0x7F9E: return "DoD";
case 0x7FA1: return "Dallas Semiconductor";
case 0x7FA2: return "Omnivision";
case 0x7FA4: return "Novatel Wireless";
case 0x7FA7: return "Cabletron";
case 0x7FA8: return "Silicon Technology";
case 0x7FAB: return "Vantis";
case 0x7FAD: return "Century";
case 0x7FAE: return "Hal Computers";
case 0x7FB0: return "Juniper Networks";
case 0x7FB3: return "Tundra Semiconductor";
case 0x7FB5: return "LightSpeed Semi.";
case 0x7FB6: return "ZSP Corp.";
case 0x7FB9: return "Dynachip";
case 0x7FBA: return "PNY Electronics";
case 0x7FBC: return "MMC Networks";
case 0x7FBF: return "Broadcom";
case 0x7FC1: return "V3 Semiconductor";
case 0x7FC2: return "Flextronics(formerly Orbit)";
case 0x7FC4: return "Transmeta";
case 0x7FC7: return "Enhance 3000 Inc";
case 0x7FC8: return "Tower Semiconductor";
case 0x7FCB: return "Maxim Integrated Product";
case 0x7FCD: return "Centaur Technology";
case 0x7FCE: return "Unigen Corporation";
case 0x7FD0: return "Memory Card Technology";
case 0x7FD3: return "Aica Kogyo, Ltd.";
case 0x7FD5: return "MSC Vertriebs GmbH";
case 0x7FD6: return "AKM Company, Ltd.";
case 0x7FD9: return "GSI Technology";
case 0x7FDA: return "Dane-Elec (C Memory)";
case 0x7FDC: return "Lara Technology";
case 0x7FDF: return "Tanisys Technology";
case 0x7FE0: return "Truevision";
case 0x7FE3: return "MGV Memory";
case 0x7FE5: return "Gadzoox Networks";
case 0x7FE6: return "Multi Dimensional Cons.";
case 0x7FE9: return "Triscend";
case 0x7FEA: return "XaQti";
case 0x7FEC: return "Clear Logic";
case 0x7FEF: return "Advantage Memory";
case 0x7FF1: return "LeCroy";
case 0x7FF2: return "Yamaha Corporation";
case 0x7FF4: return "NetLogic Microsystems";
case 0x7FF7: return "BF Goodrich Data.";
case 0x7FF8: return "Epigram";
case 0x7FFB: return "Admor Memory";
case 0x7FFD: return "Quadratics Superconductor";
case 0x7FFE: return "3COM";
case 0x01: return"AMD";
case 0x02: return"AMI";
case 0x83: return"Fairchild";
case 0x04: return"Fujitsu";
case 0x85: return"GTE";
case 0x86: return"Harris";
case 0x07: return"Hitachi";
case 0x08: return"Inmos";
case 0x89: return"Intel";
case 0x8A: return"I.T.T.";
case 0x0B: return"Intersil";
case 0x8C: return"Monolithic Memories";
case 0x0D: return"Mostek";
case 0x0E: return"Freescale";
case 0x8F: return"National";
case 0x10: return"NEC";
case 0x91: return"RCA";
case 0x92: return"Raytheon";
case 0x13: return"Conexant";
case 0x94: return"Seeq";
case 0x15: return"NXP";
case 0x16: return"Synertek";
case 0x97: return"Texas Instruments";
case 0x98: return"Toshiba";
case 0x19: return"Xicor";
case 0x1A: return"Zilog";
case 0x9B: return"Eurotechnique";
case 0x1C: return"Mitsubishi2";
case 0x9D: return"Lucent";
case 0x9E: return"Exel";
case 0x1F: return"Atmel";
case 0x20: return"SGS/Thomson";
case 0xA1: return"Lattice Semiconductor";
case 0xA2: return"NCR";
case 0x23: return"Wafer Scale Integration";
case 0xA4: return"International Business Machines";
case 0x25: return"Tristar";
case 0x26: return"Visic";
case 0xA7: return"International CMOS Technology";
case 0xA8: return"SSSI";
case 0x29: return"Microchip Technology";
case 0x2A: return"Ricoh";
case 0xAB: return"VLSI";
case 0x2C: return"Micron Technology";
case 0xAD: return"Hynix Semiconductor";
case 0xAE: return"OKI Semiconductor";
case 0x2F: return"ACTEL";
case 0xB0: return"Sharp";
case 0x31: return"Catalyst";
case 0x32: return"Panasonic";
case 0xB3: return"IDT";
case 0x34: return"Cypress";
case 0xB5: return"Digital Equipment Corporation";
case 0xB6: return"LSI Logic";
case 0x37: return"Zarlink";
case 0x38: return"UTMC";
case 0xB9: return"Thinking Machine";
case 0xBA: return"Thomson CSF";
case 0x3B: return"Integrated CMOS";
case 0xBC: return"Honeywell";
case 0x3D: return"Tektronix";
case 0x3E: return"Oracle Corporation";
case 0xBF: return"Silicon Storage Technology";
case 0x40: return"ProMos";
case 0xC1: return"Infineon";
case 0xC2: return"Macronix";
case 0x43: return"Xerox";
case 0xC4: return"Plus Logic";
case 0x45: return"SanDisk Corporation";
case 0x46: return"Elan Circuit Technology";
case 0xC7: return"European Silicon";
case 0xC8: return"Apple";
case 0x49: return"Xilinx";
case 0x4A: return"Compaq";
case 0xCB: return"Protocol Engines";
case 0x4C: return"SCI";
case 0xCD: return"Seiko Instruments";
case 0xCE: return"Samsung";
case 0x4F: return"I3 Design System";
case 0xD0: return"Klic";
case 0x51: return"Crosspoint Solutions";
case 0x52: return"Alliance Semiconductor";
case 0xD3: return"Tandem";
case 0x54: return"Hewlett-Packard";
case 0xD5: return"Integrated Silicon Solutions";
case 0xD6: return"Brooktree";
case 0x57: return"New Media";
case 0x58: return"MHS Electronic";
case 0xD9: return"Performance Semiconductors";
case 0xDA: return"Winbond Electronic";
case 0x5B: return"Kawasaki Steel";
case 0x5D: return"TECMAR";
case 0x5E: return"Exar";
case 0xDF: return"PCMCIA";
case 0xE0: return"LG Semiconductor";
case 0x61: return"Northern Telecom";
case 0x62: return"Sanyo2";
case 0xE3: return"Array Microsystems";
case 0x64: return"Crystal Semiconductor";
case 0xE5: return"Analog Devices";
case 0xE6: return"PMC-Sierra";
case 0x67: return"Asparix";
case 0x68: return"Convex Computer";
case 0xE9: return"Nimbus Technology";
case 0x6B: return"Transwitch";
case 0xEC: return"Micronas";
case 0x6D: return"Canon";
case 0x6E: return"Altera";
case 0xEF: return"NEXCOM";
case 0x70: return"Qualcomm";
case 0xF1: return"Sony";
case 0xF2: return"Cray Research";
case 0x73: return"AMS";
case 0xF4: return"Vitesse";
case 0x75: return"Aster Electronics";
case 0x76: return"Bay Networks";
case 0xF7: return"Zentrum";
case 0xF8: return"TRW";
case 0x79: return"Thesys";
case 0x7A: return"Solbourne Computer";
case 0xFB: return"Allied-Signal";
case 0x7C: return"Dialog Semiconductor";
case 0xFD: return"Media Vision";
case 0xFE: return"Numonyx Corporation";
case 0x7F01: return"Cirrus Logic";
case 0x7F02: return"National Instruments";
case 0x7F04: return"Alcatel Mietec";
case 0x7F07: return"JTAG Technologies";
case 0x7F08: return"Loral";
case 0x7F0B: return"Bestlink Systems";
case 0x7F0D: return"GENNUM";
case 0x7F0E: return"VideoLogic";
case 0x7F10: return"Chip Express";
case 0x7F13: return"TCSI";
case 0x7F15: return"Hughes Aircraft";
case 0x7F16: return"Lanstar Semiconductor";
case 0x7F19: return"Music Semi";
case 0x7F1A: return"Ericsson Components";
case 0x7F1C: return"Eon Silicon Devices";
case 0x7F1F: return"Integ.Memories Tech.";
case 0x7F20: return"Corollary Inc.";
case 0x7F23: return"EIV(Switzerland)";
case 0x7F25: return"Zarlink(formerly Mitel)";
case 0x7F26: return"Clearpoint";
case 0x7F29: return"Vanguard";
case 0x7F2A: return"Hagiwara Sys-Com";
case 0x7F2C: return"Celestica";
case 0x7F2F: return"Rohm Company Ltd.";
case 0x7F31: return"Libit Signal Processing";
case 0x7F32: return"Enhanced Memories Inc.";
case 0x7F34: return"Adaptec Inc.";
case 0x7F37: return"AMIC Technology";
case 0x7F38: return"Adobe Systems";
case 0x7F3B: return"Newport Digital";
case 0x7F3D: return"T Square";
case 0x7F3E: return"Seiko Epson";
case 0x7F40: return"Viking Components";
case 0x7F43: return"Suwa Electronics";
case 0x7F45: return"Micron CMS";
case 0x7F46: return"American Computer &Digital Components Inc";
case 0x7F49: return"CPU Design";
case 0x7F4A: return"Price Point";
case 0x7F4C: return"Tellabs";
case 0x7F4F: return"Transcend Information";
case 0x7F51: return"CKD Corporation Ltd.";
case 0x7F52: return"Capital Instruments, Inc.";
case 0x7F54: return"Linvex Technology";
case 0x7F57: return"Dynamem, Inc.";
case 0x7F58: return"NERA ASA";
case 0x7F5B: return"Acorn Computers";
case 0x7F5D: return"Oak Technology, Inc.";
case 0x7F5E: return"Itec Memory";
case 0x7F61: return"Wintec Industries";
case 0x7F62: return"Super PC Memory";
case 0x7F64: return"Galvantech";
case 0x7F67: return"GateField";
case 0x7F68: return"Integrated Memory System";
case 0x7F6B: return"Goldenram";
case 0x7F6D: return"Cimaron Communications";
case 0x7F6E: return"Nippon Steel Semi.Corp.";
case 0x7F70: return"AMCC";
case 0x7F73: return"Digital Microwave";
case 0x7F75: return"MIMOS Semiconductor";
case 0x7F76: return"Advanced Fibre";
case 0x7F79: return"Acbel Polytech Inc.";
case 0x7F7A: return"Apacer Technology";
case 0x7F7C: return"FOXCONN";
case 0x7F83: return"ILC Data Device";
case 0x7F85: return"Micro Linear";
case 0x7F86: return"Univ.Of NC";
case 0x7F89: return"Nchip";
case 0x7F8A: return"Galileo Tech";
case 0x7F8C: return"Graychip";
case 0x7F8F: return"Robert Bosch";
case 0x7F91: return"DATARAM";
case 0x7F92: return"United Microelec Corp.";
case 0x7F94: return"Smart Modular";
case 0x7F97: return"Qlogic";
case 0x7F98: return"Kingston";
case 0x7F9B: return"SpaSE";
case 0x7F9D: return"Programmable Micro Corp";
case 0x7F9E: return"DoD";
case 0x7FA1: return"Dallas Semiconductor";
case 0x7FA2: return"Omnivision";
case 0x7FA4: return"Novatel Wireless";
case 0x7FA7: return"Cabletron";
case 0x7FA8: return"Silicon Technology";
case 0x7FAB: return"Vantis";
case 0x7FAD: return"Century";
case 0x7FAE: return"Hal Computers";
case 0x7FB0: return"Juniper Networks";
case 0x7FB3: return"Tundra Semiconductor";
case 0x7FB5: return"LightSpeed Semi.";
case 0x7FB6: return"ZSP Corp.";
case 0x7FB9: return"Dynachip";
case 0x7FBA: return"PNY Electronics";
case 0x7FBC: return"MMC Networks";
case 0x7FBF: return"Broadcom";
case 0x7FC1: return"V3 Semiconductor";
case 0x7FC2: return"Flextronics(formerly Orbit)";
case 0x7FC4: return"Transmeta";
case 0x7FC7: return"Enhance 3000 Inc";
case 0x7FC8: return"Tower Semiconductor";
case 0x7FCB: return"Maxim Integrated Product";
case 0x7FCD: return"Centaur Technology";
case 0x7FCE: return"Unigen Corporation";
case 0x7FD0: return"Memory Card Technology";
case 0x7FD3: return"Aica Kogyo, Ltd.";
case 0x7FD5: return"MSC Vertriebs GmbH";
case 0x7FD6: return"AKM Company, Ltd.";
case 0x7FD9: return"GSI Technology";
case 0x7FDA: return"Dane-Elec (C Memory)";
case 0x7FDC: return"Lara Technology";
case 0x7FDF: return"Tanisys Technology";
case 0x7FE0: return"Truevision";
case 0x7FE3: return"MGV Memory";
case 0x7FE5: return"Gadzoox Networks";
case 0x7FE6: return"Multi Dimensional Cons.";
case 0x7FE9: return"Triscend";
case 0x7FEA: return"XaQti";
case 0x7FEC: return"Clear Logic";
case 0x7FEF: return"Advantage Memory";
case 0x7FF1: return"LeCroy";
case 0x7FF2: return"Yamaha Corporation";
case 0x7FF4: return"NetLogic Microsystems";
case 0x7FF7: return"BF Goodrich Data.";
case 0x7FF8: return"Epigram";
case 0x7FFB: return"Admor Memory";
case 0x7FFD: return"Quadratics Superconductor";
case 0x7FFE: return"3COM";
#endregion JEDEC
case 0x0100: return "Digital Equipment Corporation";
case 0x0101: return "3Com Corporation";
case 0x0102: return "Megahertz Corporation";
case 0x0104: return "Socket Communications";
case 0x0105: return "TDK Corporation";
case 0x0108: return "Standard Microsystems Corporation";
case 0x0109: return "Motorola Corporation";
case 0x010b: return "National Instruments";
case 0x0115: return "US Robotics Corporation";
case 0x0121: return "Olicom";
case 0x0126: return "Proxim";
case 0x0128: return "Megahertz Corporation";
case 0x012F: return "Adaptec Corporation";
case 0x0137: return "Quatech";
case 0x0138: return "Compaq";
case 0x0140: return "Ositech";
case 0x0143: return "D-Link";
case 0x0149: return "Netgear";
case 0x014D: return "Simple Technology";
case 0x0156: return "Lucent Technologies";
case 0x015F: return "Aironet Wireless Communications";
case 0x016B: return "Ericsson";
case 0x016C: return "Psion";
case 0x0183: return "Compaq";
case 0x0186: return "Kingston";
case 0x0192: return "Sierra Wireless";
case 0x0194: return "Dayna Corporation";
case 0x01a6: return "Raytheon";
case 0x01BF: return "Belkin";
case 0x01EB: return "Bay Networks";
case 0x0200: return "Farallon Communications";
case 0x021B: return "Telecom Device";
case 0x023D: return "Nokia Communications";
case 0x0250: return "Samsung";
case 0x0264: return "Anycom";
case 0x0268: return "Alvarion Ltd.";
case 0x026C: return "Symbol";
case 0x026F: return "BUFFALO";
case 0x0274: return "The Linksys Group";
case 0x0288: return "NEC Infrontia";
case 0x028A: return "I-O DATA";
case 0x02AA: return "Asustek Computer";
case 0x02AC: return "Siemens";
case 0x02D2: return "Microsoft Corporation";
case 0x02DF: return "AmbiCom Inc";
case 0x0a02: return "BreezeCOM";
case 0x10CD: return "NewMedia";
case 0x1668: return "ACTIONTEC";
case 0x3401: return "Lasat Communications A/S";
case 0x4E01: return "Lexar Media";
case 0x5241: return "Archos";
case 0x890F: return "Dual";
case 0x8A01: return "Compex Corporation";
case 0xC001: return "Contec";
case 0xC00B: return "MACNICA";
case 0xC00C: return "Roland";
case 0xC00F: return "Corega K.K.";
case 0xC012: return "Hagiwara SYS-COM";
case 0xC015: return "RATOC System Inc.";
case 0xC020: return "NextCom K.K.";
case 0xC250: return "EMTAC Technology Corporation";
case 0xD601: return "Elsa";
default: return $"Unknown vendor id 0x{id:X4}";
case 0x0100: return"Digital Equipment Corporation";
case 0x0101: return"3Com Corporation";
case 0x0102: return"Megahertz Corporation";
case 0x0104: return"Socket Communications";
case 0x0105: return"TDK Corporation";
case 0x0108: return"Standard Microsystems Corporation";
case 0x0109: return"Motorola Corporation";
case 0x010b: return"National Instruments";
case 0x0115: return"US Robotics Corporation";
case 0x0121: return"Olicom";
case 0x0126: return"Proxim";
case 0x0128: return"Megahertz Corporation";
case 0x012F: return"Adaptec Corporation";
case 0x0137: return"Quatech";
case 0x0138: return"Compaq";
case 0x0140: return"Ositech";
case 0x0143: return"D-Link";
case 0x0149: return"Netgear";
case 0x014D: return"Simple Technology";
case 0x0156: return"Lucent Technologies";
case 0x015F: return"Aironet Wireless Communications";
case 0x016B: return"Ericsson";
case 0x016C: return"Psion";
case 0x0183: return"Compaq";
case 0x0186: return"Kingston";
case 0x0192: return"Sierra Wireless";
case 0x0194: return"Dayna Corporation";
case 0x01a6: return"Raytheon";
case 0x01BF: return"Belkin";
case 0x01EB: return"Bay Networks";
case 0x0200: return"Farallon Communications";
case 0x021B: return"Telecom Device";
case 0x023D: return"Nokia Communications";
case 0x0250: return"Samsung";
case 0x0264: return"Anycom";
case 0x0268: return"Alvarion Ltd.";
case 0x026C: return"Symbol";
case 0x026F: return"BUFFALO";
case 0x0274: return"The Linksys Group";
case 0x0288: return"NEC Infrontia";
case 0x028A: return"I-O DATA";
case 0x02AA: return"Asustek Computer";
case 0x02AC: return"Siemens";
case 0x02D2: return"Microsoft Corporation";
case 0x02DF: return"AmbiCom Inc";
case 0x0a02: return"BreezeCOM";
case 0x10CD: return"NewMedia";
case 0x1668: return"ACTIONTEC";
case 0x3401: return"Lasat Communications A/S";
case 0x4E01: return"Lexar Media";
case 0x5241: return"Archos";
case 0x890F: return"Dual";
case 0x8A01: return"Compex Corporation";
case 0xC001: return"Contec";
case 0xC00B: return"MACNICA";
case 0xC00C: return"Roland";
case 0xC00F: return"Corega K.K.";
case 0xC012: return"Hagiwara SYS-COM";
case 0xC015: return"RATOC System Inc.";
case 0xC020: return"NextCom K.K.";
case 0xC250: return"EMTAC Technology Corporation";
case 0xD601: return"Elsa";
default: return$"Unknown vendor id 0x{id:X4}";
}
}
}

View File

@@ -35,33 +35,16 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class DiscStructureCapabilities
{
public struct Capability
{
/// <summary>
/// READ/SEND DISC STRUCTURE format code
/// </summary>
public byte FormatCode;
/// <summary>
/// Supported in SEND DISC STRUCTURE
/// </summary>
public bool SDS;
/// <summary>
/// Supported in READ DISC STRUCTURE
/// </summary>
public bool RDS;
}
public static Capability[] Decode(byte[] response)
{
ushort len = (ushort)((response[0] << 8) + response[1]);
if(len + 2 != response.Length) return null;
if(len + 2 != response.Length)
return null;
List<Capability> caps = new List<Capability>();
@@ -69,17 +52,27 @@ namespace DiscImageChef.Decoders.SCSI
while(offset < response.Length)
{
Capability cap = new Capability
var cap = new Capability
{
FormatCode = response[offset],
SDS = (response[offset + 1] & 0x80) == 0x80,
RDS = (response[offset + 1] & 0x40) == 0x40
FormatCode = response[offset], SDS = (response[offset + 1] & 0x80) == 0x80,
RDS = (response[offset + 1] & 0x40) == 0x40
};
caps.Add(cap);
offset += 4;
}
return caps.ToArray();
}
public struct Capability
{
/// <summary>READ/SEND DISC STRUCTURE format code</summary>
public byte FormatCode;
/// <summary>Supported in SEND DISC STRUCTURE</summary>
public bool SDS;
/// <summary>Supported in READ DISC STRUCTURE</summary>
public bool RDS;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -36,290 +36,115 @@ namespace DiscImageChef.Decoders.SCSI
{
public enum PeripheralQualifiers : byte
{
/// <summary>
/// Peripheral qualifier: Device is connected and supported
/// </summary>
Supported = 0x00,
/// <summary>
/// Peripheral qualifier: Device is supported but not connected
/// </summary>
Unconnected = 0x01,
/// <summary>
/// Peripheral qualifier: Reserved value
/// </summary>
Reserved = 0x02,
/// <summary>
/// Peripheral qualifier: Device is connected but unsupported
/// </summary>
Unsupported = 0x03,
/// <summary>
/// Peripheral qualifier: Vendor values: 0x04, 0x05, 0x06 and 0x07
/// </summary>
/// <summary>Peripheral qualifier: Device is connected and supported</summary>
Supported = 0x00, /// <summary>Peripheral qualifier: Device is supported but not connected</summary>
Unconnected = 0x01, /// <summary>Peripheral qualifier: Reserved value</summary>
Reserved = 0x02, /// <summary>Peripheral qualifier: Device is connected but unsupported</summary>
Unsupported = 0x03, /// <summary>Peripheral qualifier: Vendor values: 0x04, 0x05, 0x06 and 0x07</summary>
VendorMask = 0x04
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum PeripheralDeviceTypes : byte
{
/// <summary>
/// Direct-access device
/// </summary>
DirectAccess = 0x00,
/// <summary>
/// Sequential-access device
/// </summary>
SequentialAccess = 0x01,
/// <summary>
/// Printer device
/// </summary>
PrinterDevice = 0x02,
/// <summary>
/// Processor device
/// </summary>
ProcessorDevice = 0x03,
/// <summary>
/// Write-once device
/// </summary>
WriteOnceDevice = 0x04,
/// <summary>
/// CD-ROM/DVD/etc device
/// </summary>
MultiMediaDevice = 0x05,
/// <summary>
/// Scanner device
/// </summary>
ScannerDevice = 0x06,
/// <summary>
/// Optical memory device
/// </summary>
OpticalDevice = 0x07,
/// <summary>
/// Medium change device
/// </summary>
MediumChangerDevice = 0x08,
/// <summary>
/// Communications device
/// </summary>
CommsDevice = 0x09,
/// <summary>
/// Graphics arts pre-press device (defined in ASC IT8)
/// </summary>
PrePressDevice1 = 0x0A,
/// <summary>
/// Graphics arts pre-press device (defined in ASC IT8)
/// </summary>
PrePressDevice2 = 0x0B,
/// <summary>
/// Array controller device
/// </summary>
ArrayControllerDevice = 0x0C,
/// <summary>
/// Enclosure services device
/// </summary>
EnclosureServiceDevice = 0x0D,
/// <summary>
/// Simplified direct-access device
/// </summary>
SimplifiedDevice = 0x0E,
/// <summary>
/// Optical card reader/writer device
/// </summary>
OCRWDevice = 0x0F,
/// <summary>
/// Bridging Expanders
/// </summary>
BridgingExpander = 0x10,
/// <summary>
/// Object-based Storage Device
/// </summary>
ObjectDevice = 0x11,
/// <summary>
/// Automation/Drive Interface
/// </summary>
ADCDevice = 0x12,
/// <summary>
/// Security Manager Device
/// </summary>
SCSISecurityManagerDevice = 0x13,
/// <summary>
/// Host managed zoned block device
/// </summary>
SCSIZonedBlockDevice = 0x14,
/// <summary>
/// Well known logical unit
/// </summary>
WellKnownDevice = 0x1E,
/// <summary>
/// Unknown or no device type
/// </summary>
/// <summary>Direct-access device</summary>
DirectAccess = 0x00, /// <summary>Sequential-access device</summary>
SequentialAccess = 0x01, /// <summary>Printer device</summary>
PrinterDevice = 0x02, /// <summary>Processor device</summary>
ProcessorDevice = 0x03, /// <summary>Write-once device</summary>
WriteOnceDevice = 0x04, /// <summary>CD-ROM/DVD/etc device</summary>
MultiMediaDevice = 0x05, /// <summary>Scanner device</summary>
ScannerDevice = 0x06, /// <summary>Optical memory device</summary>
OpticalDevice = 0x07, /// <summary>Medium change device</summary>
MediumChangerDevice = 0x08, /// <summary>Communications device</summary>
CommsDevice = 0x09, /// <summary>Graphics arts pre-press device (defined in ASC IT8)</summary>
PrePressDevice1 = 0x0A, /// <summary>Graphics arts pre-press device (defined in ASC IT8)</summary>
PrePressDevice2 = 0x0B, /// <summary>Array controller device</summary>
ArrayControllerDevice = 0x0C, /// <summary>Enclosure services device</summary>
EnclosureServiceDevice = 0x0D, /// <summary>Simplified direct-access device</summary>
SimplifiedDevice = 0x0E, /// <summary>Optical card reader/writer device</summary>
OCRWDevice = 0x0F, /// <summary>Bridging Expanders</summary>
BridgingExpander = 0x10, /// <summary>Object-based Storage Device</summary>
ObjectDevice = 0x11, /// <summary>Automation/Drive Interface</summary>
ADCDevice = 0x12, /// <summary>Security Manager Device</summary>
SCSISecurityManagerDevice = 0x13, /// <summary>Host managed zoned block device</summary>
SCSIZonedBlockDevice = 0x14, /// <summary>Well known logical unit</summary>
WellKnownDevice = 0x1E, /// <summary>Unknown or no device type</summary>
UnknownDevice = 0x1F
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ANSIVersions : byte
{
/// <summary>
/// Device does not claim conformance to any ANSI version
/// </summary>
ANSINoVersion = 0x00,
/// <summary>
/// Device complies with ANSI X3.131:1986
/// </summary>
ANSI1986Version = 0x01,
/// <summary>
/// Device complies with ANSI X3.131:1994
/// </summary>
ANSI1994Version = 0x02,
/// <summary>
/// Device complies with ANSI X3.301:1997
/// </summary>
ANSI1997Version = 0x03,
/// <summary>
/// Device complies with ANSI X3.351:2001
/// </summary>
ANSI2001Version = 0x04,
/// <summary>
/// Device complies with ANSI X3.408:2005.
/// </summary>
ANSI2005Version = 0x05,
/// <summary>
/// Device complies with SPC-4
/// </summary>
/// <summary>Device does not claim conformance to any ANSI version</summary>
ANSINoVersion = 0x00, /// <summary>Device complies with ANSI X3.131:1986</summary>
ANSI1986Version = 0x01, /// <summary>Device complies with ANSI X3.131:1994</summary>
ANSI1994Version = 0x02, /// <summary>Device complies with ANSI X3.301:1997</summary>
ANSI1997Version = 0x03, /// <summary>Device complies with ANSI X3.351:2001</summary>
ANSI2001Version = 0x04, /// <summary>Device complies with ANSI X3.408:2005.</summary>
ANSI2005Version = 0x05, /// <summary>Device complies with SPC-4</summary>
ANSI2008Version = 0x06
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ECMAVersions : byte
{
/// <summary>
/// Device does not claim conformance to any ECMA version
/// </summary>
ECMANoVersion = 0x00,
/// <summary>
/// Device complies with a ECMA-111 standard
/// </summary>
/// <summary>Device does not claim conformance to any ECMA version</summary>
ECMANoVersion = 0x00, /// <summary>Device complies with a ECMA-111 standard</summary>
ECMA111 = 0x01
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ISOVersions : byte
{
/// <summary>
/// Device does not claim conformance to any ISO/IEC version
/// </summary>
ISONoVersion = 0x00,
/// <summary>
/// Device complies with ISO/IEC 9316:1995
/// </summary>
/// <summary>Device does not claim conformance to any ISO/IEC version</summary>
ISONoVersion = 0x00, /// <summary>Device complies with ISO/IEC 9316:1995</summary>
ISO1995Version = 0x02
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum SPIClocking : byte
{
/// <summary>
/// Supports only ST
/// </summary>
ST = 0x00,
/// <summary>
/// Supports only DT
/// </summary>
DT = 0x01,
/// <summary>
/// Reserved value
/// </summary>
Reserved = 0x02,
/// <summary>
/// Supports ST and DT
/// </summary>
/// <summary>Supports only ST</summary>
ST = 0x00, /// <summary>Supports only DT</summary>
DT = 0x01, /// <summary>Reserved value</summary>
Reserved = 0x02, /// <summary>Supports ST and DT</summary>
STandDT = 0x03
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum TGPSValues : byte
{
/// <summary>
/// Assymetrical access not supported
/// </summary>
NotSupported = 0x00,
/// <summary>
/// Only implicit assymetrical access is supported
/// </summary>
OnlyImplicit = 0x01,
/// <summary>
/// Only explicit assymetrical access is supported
/// </summary>
OnlyExplicit = 0x02,
/// <summary>
/// Both implicit and explicit assymetrical access are supported
/// </summary>
/// <summary>Assymetrical access not supported</summary>
NotSupported = 0x00, /// <summary>Only implicit assymetrical access is supported</summary>
OnlyImplicit = 0x01, /// <summary>Only explicit assymetrical access is supported</summary>
OnlyExplicit = 0x02, /// <summary>Both implicit and explicit assymetrical access are supported</summary>
Both = 0x03
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ProtocolIdentifiers : byte
{
/// <summary>
/// Fibre Channel
/// </summary>
FibreChannel = 0,
/// <summary>
/// Parallel SCSI
/// </summary>
SCSI = 1,
/// <summary>
/// SSA
/// </summary>
SSA = 2,
/// <summary>
/// IEEE-1394
/// </summary>
Firewire = 3,
/// <summary>
/// SCSI Remote Direct Memory Access Protocol
/// </summary>
RDMAP = 4,
/// <summary>
/// Internet SCSI
/// </summary>
iSCSI = 5,
/// <summary>
/// Serial SCSI
/// </summary>
SAS = 6,
/// <summary>
/// Automation/Drive Interface Transport Protocol
/// </summary>
ADT = 7,
/// <summary>
/// AT Attachment Interface (ATA/ATAPI)
/// </summary>
ATA = 8,
/// <summary>
/// USB Attached SCSI
/// </summary>
UAS = 9,
/// <summary>
/// SCSI over PCI Express
/// </summary>
SCSIe = 10,
/// <summary>
/// PCI Express
/// </summary>
PCIe = 11,
/// <summary>
/// No specific protocol
/// </summary>
/// <summary>Fibre Channel</summary>
FibreChannel = 0, /// <summary>Parallel SCSI</summary>
SCSI = 1, /// <summary>SSA</summary>
SSA = 2, /// <summary>IEEE-1394</summary>
Firewire = 3, /// <summary>SCSI Remote Direct Memory Access Protocol</summary>
RDMAP = 4, /// <summary>Internet SCSI</summary>
iSCSI = 5, /// <summary>Serial SCSI</summary>
SAS = 6, /// <summary>Automation/Drive Interface Transport Protocol</summary>
ADT = 7, /// <summary>AT Attachment Interface (ATA/ATAPI)</summary>
ATA = 8, /// <summary>USB Attached SCSI</summary>
UAS = 9, /// <summary>SCSI over PCI Express</summary>
SCSIe = 10, /// <summary>PCI Express</summary>
PCIe = 11, /// <summary>No specific protocol</summary>
NoProtocol = 15
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ScsiDefinitions : byte
{
Current = 0,
SCSI1 = 1,
CCS = 2,
SCSI2 = 3,
SCSI3 = 4
Current = 0, SCSI1 = 1, CCS = 2,
SCSI2 = 3, SCSI3 = 4
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,195 +37,20 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI.MMC
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class AACS
{
public struct AACSVolumeIdentifier
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// AACS volume identifier data
/// </summary>
public byte[] VolumeIdentifier;
}
public struct AACSMediaSerialNumber
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// AACS media serial number
/// </summary>
public byte[] MediaSerialNumber;
}
public struct AACSMediaIdentifier
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// AACS media identifier data
/// </summary>
public byte[] MediaIdentifier;
}
public struct AACSMediaKeyBlock
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved;
/// <summary>
/// Byte 3
/// Number of MKB packs available to transfer
/// </summary>
public byte TotalPacks;
/// <summary>
/// Bytes 4 to end
/// AACS media key block packs
/// </summary>
public byte[] MediaKeyBlockPacks;
}
public struct AACSDataKeys
{
/// <summary>
/// Bytes 0 to 1
/// Data length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to end
/// AACS data keys
/// </summary>
public byte[] DataKeys;
}
public struct AACSLBAExtentsResponse
{
/// <summary>
/// Bytes 0 to 1
/// Data Length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved;
/// <summary>
/// Byte 3
/// Number of LBA extents the drive can store.
/// if(MaxLBAExtents == 0 &amp;&amp; DataLength > 2), 256 extents can be stored
/// </summary>
public byte MaxLBAExtents;
/// <summary>
/// Bytes 4 to end
/// LBA Extents
/// </summary>
public AACSLBAExtent[] Extents;
}
public struct AACSLBAExtent
{
/// <summary>
/// Bytes 0 to 7
/// Reserved
/// </summary>
public byte[] Reserved;
/// <summary>
/// Bytes 8 to 11
/// Start LBA of extent
/// </summary>
public uint StartLBA;
/// <summary>
/// Bytes 12 to 15
/// Extent length
/// </summary>
public uint LBACount;
}
public static AACSVolumeIdentifier? DecodeAACSVolumeIdentifier(byte[] AACSVIResponse)
{
if(AACSVIResponse == null) return null;
if(AACSVIResponse == null)
return null;
AACSVolumeIdentifier decoded = new AACSVolumeIdentifier();
var decoded = new AACSVolumeIdentifier();
decoded.VolumeIdentifier = new byte[AACSVIResponse.Length - 4];
@@ -239,16 +64,20 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSVolumeIdentifier(AACSVolumeIdentifier? AACSVIResponse)
{
if(AACSVIResponse == null) return null;
if(AACSVIResponse == null)
return null;
AACSVolumeIdentifier response = AACSVIResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
sb.AppendFormat("AACS Volume Identifier in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VolumeIdentifier, 80));
@@ -258,14 +87,16 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSVolumeIdentifier(byte[] AACSVIResponse)
{
AACSVolumeIdentifier? decoded = DecodeAACSVolumeIdentifier(AACSVIResponse);
return PrettifyAACSVolumeIdentifier(decoded);
}
public static AACSMediaSerialNumber? DecodeAACSMediaSerialNumber(byte[] AACSMSNResponse)
{
if(AACSMSNResponse == null) return null;
if(AACSMSNResponse == null)
return null;
AACSMediaSerialNumber decoded = new AACSMediaSerialNumber();
var decoded = new AACSMediaSerialNumber();
decoded.MediaSerialNumber = new byte[AACSMSNResponse.Length - 4];
@@ -279,16 +110,20 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSMediaSerialNumber(AACSMediaSerialNumber? AACSMSNResponse)
{
if(AACSMSNResponse == null) return null;
if(AACSMSNResponse == null)
return null;
AACSMediaSerialNumber response = AACSMSNResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
sb.AppendFormat("AACS Media Serial Number in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaSerialNumber, 80));
@@ -298,14 +133,16 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSMediaSerialNumber(byte[] AACSMSNResponse)
{
AACSMediaSerialNumber? decoded = DecodeAACSMediaSerialNumber(AACSMSNResponse);
return PrettifyAACSMediaSerialNumber(decoded);
}
public static AACSMediaIdentifier? DecodeAACSMediaIdentifier(byte[] AACSMIResponse)
{
if(AACSMIResponse == null) return null;
if(AACSMIResponse == null)
return null;
AACSMediaIdentifier decoded = new AACSMediaIdentifier();
var decoded = new AACSMediaIdentifier();
decoded.MediaIdentifier = new byte[AACSMIResponse.Length - 4];
@@ -319,16 +156,20 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSMediaIdentifier(AACSMediaIdentifier? AACSMIResponse)
{
if(AACSMIResponse == null) return null;
if(AACSMIResponse == null)
return null;
AACSMediaIdentifier response = AACSMIResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
sb.AppendFormat("AACS Media Identifier in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaIdentifier, 80));
@@ -338,14 +179,16 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSMediaIdentifier(byte[] AACSMIResponse)
{
AACSMediaIdentifier? decoded = DecodeAACSMediaIdentifier(AACSMIResponse);
return PrettifyAACSMediaIdentifier(decoded);
}
public static AACSMediaKeyBlock? DecodeAACSMediaKeyBlock(byte[] AACSMKBResponse)
{
if(AACSMKBResponse == null) return null;
if(AACSMKBResponse == null)
return null;
AACSMediaKeyBlock decoded = new AACSMediaKeyBlock();
var decoded = new AACSMediaKeyBlock();
decoded.MediaKeyBlockPacks = new byte[AACSMKBResponse.Length - 4];
@@ -359,17 +202,20 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSMediaKeyBlock(AACSMediaKeyBlock? AACSMKBResponse)
{
if(AACSMKBResponse == null) return null;
if(AACSMKBResponse == null)
return null;
AACSMediaKeyBlock response = AACSMKBResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved != 0)
sb.AppendFormat("Reserved = 0x{0:X2}", response.Reserved).AppendLine();
#endif
sb.AppendFormat("Total number of media key blocks available to transfer {0}", response.TotalPacks).
AppendLine();
#if DEBUG
if(response.Reserved != 0) sb.AppendFormat("Reserved = 0x{0:X2}", response.Reserved).AppendLine();
#endif
sb.AppendFormat("Total number of media key blocks available to transfer {0}", response.TotalPacks)
.AppendLine();
sb.AppendFormat("AACS Media Key Blocks in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaKeyBlockPacks, 80));
@@ -379,14 +225,16 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSMediaKeyBlock(byte[] AACSMKBResponse)
{
AACSMediaKeyBlock? decoded = DecodeAACSMediaKeyBlock(AACSMKBResponse);
return PrettifyAACSMediaKeyBlock(decoded);
}
public static AACSDataKeys? DecodeAACSDataKeys(byte[] AACSDKResponse)
{
if(AACSDKResponse == null) return null;
if(AACSDKResponse == null)
return null;
AACSDataKeys decoded = new AACSDataKeys();
var decoded = new AACSDataKeys();
decoded.DataKeys = new byte[AACSDKResponse.Length - 4];
@@ -400,16 +248,20 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSDataKeys(AACSDataKeys? AACSDKResponse)
{
if(AACSDKResponse == null) return null;
if(AACSDKResponse == null)
return null;
AACSDataKeys response = AACSDKResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
#endif
sb.AppendFormat("AACS Data Keys in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.DataKeys, 80));
@@ -419,21 +271,24 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSDataKeys(byte[] AACSDKResponse)
{
AACSDataKeys? decoded = DecodeAACSDataKeys(AACSDKResponse);
return PrettifyAACSDataKeys(decoded);
}
public static AACSLBAExtentsResponse? DecodeAACSLBAExtents(byte[] AACSLBAExtsResponse)
{
if(AACSLBAExtsResponse == null) return null;
if(AACSLBAExtsResponse == null)
return null;
AACSLBAExtentsResponse decoded = new AACSLBAExtentsResponse
var decoded = new AACSLBAExtentsResponse
{
DataLength = BigEndianBitConverter.ToUInt16(AACSLBAExtsResponse, 0),
Reserved = AACSLBAExtsResponse[2],
MaxLBAExtents = AACSLBAExtsResponse[3]
};
if((AACSLBAExtsResponse.Length - 4) % 16 != 0) return decoded;
if((AACSLBAExtsResponse.Length - 4) % 16 != 0)
return decoded;
decoded.Extents = new AACSLBAExtent[(AACSLBAExtsResponse.Length - 4) / 16];
@@ -450,17 +305,18 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSLBAExtents(AACSLBAExtentsResponse? AACSLBAExtsResponse)
{
if(AACSLBAExtsResponse == null) return null;
if(AACSLBAExtsResponse == null)
return null;
AACSLBAExtentsResponse response = AACSLBAExtsResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
if(response.MaxLBAExtents == 0)
sb.AppendLine(response.DataLength > 2
? "Drive can store 256 LBA Extents"
sb.AppendLine(response.DataLength > 2 ? "Drive can store 256 LBA Extents"
: "Drive cannot store LBA Extents");
else sb.AppendFormat("Drive can store {0} LBA Extents", response.MaxLBAExtents).AppendLine();
else
sb.AppendFormat("Drive can store {0} LBA Extents", response.MaxLBAExtents).AppendLine();
for(int i = 0; i < response.Extents.Length; i++)
sb.AppendFormat("LBA Extent {0} starts at LBA {1} and goes for {2} sectors", i,
@@ -472,7 +328,93 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyAACSLBAExtents(byte[] AACSLBAExtsResponse)
{
AACSLBAExtentsResponse? decoded = DecodeAACSLBAExtents(AACSLBAExtsResponse);
return PrettifyAACSLBAExtents(decoded);
}
public struct AACSVolumeIdentifier
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to end AACS volume identifier data</summary>
public byte[] VolumeIdentifier;
}
public struct AACSMediaSerialNumber
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to end AACS media serial number</summary>
public byte[] MediaSerialNumber;
}
public struct AACSMediaIdentifier
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to end AACS media identifier data</summary>
public byte[] MediaIdentifier;
}
public struct AACSMediaKeyBlock
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved;
/// <summary>Byte 3 Number of MKB packs available to transfer</summary>
public byte TotalPacks;
/// <summary>Bytes 4 to end AACS media key block packs</summary>
public byte[] MediaKeyBlockPacks;
}
public struct AACSDataKeys
{
/// <summary>Bytes 0 to 1 Data length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to end AACS data keys</summary>
public byte[] DataKeys;
}
public struct AACSLBAExtentsResponse
{
/// <summary>Bytes 0 to 1 Data Length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved;
/// <summary>
/// Byte 3 Number of LBA extents the drive can store. if(MaxLBAExtents == 0 &amp;&amp; DataLength > 2), 256
/// extents can be stored
/// </summary>
public byte MaxLBAExtents;
/// <summary>Bytes 4 to end LBA Extents</summary>
public AACSLBAExtent[] Extents;
}
public struct AACSLBAExtent
{
/// <summary>Bytes 0 to 7 Reserved</summary>
public byte[] Reserved;
/// <summary>Bytes 8 to 11 Start LBA of extent</summary>
public uint StartLBA;
/// <summary>Bytes 12 to 15 Extent length</summary>
public uint LBACount;
}
}
}

View File

@@ -37,59 +37,23 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI.MMC
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class CPRM
{
public struct CPRMMediaKeyBlock
{
/// <summary>
/// Bytes 0 to 1
/// Data Length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved;
/// <summary>
/// Byte 3
/// Number of MKB packs available to transfer
/// </summary>
public byte TotalPacks;
/// <summary>
/// Byte 4
/// MKB Packs
/// </summary>
public byte[] MKBPackData;
}
public static CPRMMediaKeyBlock? DecodeCPRMMediaKeyBlock(byte[] CPRMMKBResponse)
{
if(CPRMMKBResponse == null) return null;
if(CPRMMKBResponse == null)
return null;
CPRMMediaKeyBlock decoded = new CPRMMediaKeyBlock
var decoded = new CPRMMediaKeyBlock
{
MKBPackData = new byte[CPRMMKBResponse.Length - 4],
DataLength = BigEndianBitConverter.ToUInt16(CPRMMKBResponse, 0),
Reserved = CPRMMKBResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(CPRMMKBResponse, 0), Reserved = CPRMMKBResponse[2],
TotalPacks = CPRMMKBResponse[3]
};
@@ -100,17 +64,20 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyCPRMMediaKeyBlock(CPRMMediaKeyBlock? CPRMMKBResponse)
{
if(CPRMMKBResponse == null) return null;
if(CPRMMKBResponse == null)
return null;
CPRMMediaKeyBlock response = CPRMMKBResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
#if DEBUG
if(response.Reserved != 0)
sb.AppendFormat("Reserved = 0x{0:X2}", response.Reserved).AppendLine();
#endif
sb.AppendFormat("Total number of CPRM Media Key Blocks available to transfer: {0}", response.TotalPacks).
AppendLine();
#if DEBUG
if(response.Reserved != 0) sb.AppendFormat("Reserved = 0x{0:X2}", response.Reserved).AppendLine();
#endif
sb.AppendFormat("Total number of CPRM Media Key Blocks available to transfer: {0}", response.TotalPacks)
.AppendLine();
sb.AppendFormat("CPRM Media Key Blocks in hex follows:");
sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MKBPackData, 80));
@@ -120,7 +87,20 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyCPRMMediaKeyBlock(byte[] CPRMMKBResponse)
{
CPRMMediaKeyBlock? decoded = DecodeCPRMMediaKeyBlock(CPRMMKBResponse);
return PrettifyCPRMMediaKeyBlock(decoded);
}
public struct CPRMMediaKeyBlock
{
/// <summary>Bytes 0 to 1 Data Length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved;
/// <summary>Byte 3 Number of MKB packs available to transfer</summary>
public byte TotalPacks;
/// <summary>Byte 4 MKB Packs</summary>
public byte[] MKBPackData;
}
}
}

View File

@@ -37,257 +37,29 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI.MMC
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class DiscInformation
{
public struct StandardDiscInformation
{
/// <summary>
/// Bytes 0 to 1
/// 32 + OPCTablesNumber*8
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2, bits 7 to 5
/// 000b
/// </summary>
public byte DataType;
/// <summary>
/// Byte 2, bit 4
/// If set, disc is erasable
/// </summary>
public bool Erasable;
/// <summary>
/// Byte 2, bits 3 to 2
/// Status of last session
/// </summary>
public byte LastSessionStatus;
/// <summary>
/// Byte 2, bits 1 to 0
/// Status of disc
/// </summary>
public byte DiscStatus;
/// <summary>
/// Byte 3
/// Number of logical track that contains LBA 0
/// </summary>
public byte FirstTrackNumber;
/// <summary>
/// Byte 9 (MSB) and byte 4 (LSB)
/// Number of sessions
/// </summary>
public ushort Sessions;
/// <summary>
/// Byte 10 (MSB) and byte 5 (LSB)
/// Number of first track in last session
/// </summary>
public ushort FirstTrackLastSession;
/// <summary>
/// Byte 11 (MSB) and byte 6 (LSB)
/// Number of last track in last session
/// </summary>
public ushort LastTrackLastSession;
/// <summary>
/// Byte 7, bit 7
/// If set, DiscIdentification is valid
/// </summary>
public bool DID_V;
/// <summary>
/// Byte 7, bit 6
/// If set, DiscBarcode is valid
/// </summary>
public bool DBC_V;
/// <summary>
/// Byte 7, bit 5
/// If set, disc is unrestricted
/// </summary>
public bool URU;
/// <summary>
/// Byte 7, bit 4
/// If set DiscApplicationCode is valid
/// </summary>
public bool DAC_V;
/// <summary>
/// Byte 7, bit 3
/// Reserved
/// </summary>
public bool Reserved;
/// <summary>
/// Byte 7, bit 2
/// Copy of dirty bit from MRW status
/// </summary>
public bool Dbit;
/// <summary>
/// Byte 7, bits 1 to 0
/// Background format status
/// </summary>
public byte BGFormatStatus;
/// <summary>
/// Byte 8
/// Disc type code
/// </summary>
public byte DiscType;
/// <summary>
/// Bytes 12 to 15
/// Disc identification number from PMA
/// </summary>
public uint DiscIdentification;
/// <summary>
/// Bytes 16 to 19
/// Last Session Lead-in Start Address (MSF for CD, LBA for others)
/// </summary>
public uint LastSessionLeadInStartLBA;
/// <summary>
/// Bytes 20 to 23
/// Last Possible Lead-out Start Address (MSF for CD, LBA for others)
/// </summary>
public uint LastPossibleLeadOutStartLBA;
/// <summary>
/// Bytes 24 to 31
/// Disc barcode
/// </summary>
public ulong DiscBarcode;
/// <summary>
/// Byte 32
/// Disc application code
/// </summary>
public byte DiscApplicationCode;
/// <summary>
/// Byte 33
/// How many OPC tables are
/// </summary>
public byte OPCTablesNumber;
/// <summary>
/// Bytes 34 to end
/// OPC tables (8 bytes each)
/// </summary>
public OPCTable[] OPCTables;
}
public struct OPCTable
{
/// <summary>
/// Bytes 0 to 1
/// kilobytes/sec this OPC table applies to
/// </summary>
public ushort Speed;
/// <summary>
/// Bytes 2 to 7
/// OPC values
/// </summary>
public byte[] OPCValues;
}
public struct TrackResourcesInformation
{
/// <summary>
/// Bytes 0 to 1
/// 10
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2, bits 7 to 5
/// 001b
/// </summary>
public byte DataType;
/// <summary>
/// Byte 2, bits 4 to 0
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 5
/// Maximum possible number of the tracks on the disc
/// </summary>
public ushort MaxTracks;
/// <summary>
/// Bytes 6 to 7
/// Number of the assigned tracks on the disc
/// </summary>
public ushort AssignedTracks;
/// <summary>
/// Bytes 8 to 9
/// Maximum possible number of appendable tracks on the disc
/// </summary>
public ushort MaxAppendableTracks;
/// <summary>
/// Bytes 10 to 11
/// Current number of appendable tracks on the disc
/// </summary>
public ushort AppendableTracks;
}
public struct POWResourcesInformation
{
/// <summary>
/// Bytes 0 to 1
/// 14
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2, bits 7 to 5
/// 010b
/// </summary>
public byte DataType;
/// <summary>
/// Byte 2, bits 4 to 0
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Bytes 4 to 7
/// Remaining POW replacements
/// </summary>
public uint RemainingPOWReplacements;
/// <summary>
/// Bytes 8 to 11
/// Remaining POW reallocation map entries
/// </summary>
public uint RemainingPOWReallocation;
/// <summary>
/// Bytes 12 to 15
/// Number of remaining POW updates
/// </summary>
public uint RemainingPOWUpdates;
}
public static StandardDiscInformation? Decode000b(byte[] response)
{
if(response.Length < 34) return null;
if(response.Length < 34)
return null;
if((response[2] & 0xE0) != 0) return null;
if((response[2] & 0xE0) != 0)
return null;
StandardDiscInformation decoded =
new StandardDiscInformation {DataLength = (ushort)((response[0] << 8) + response[1])};
var decoded = new StandardDiscInformation
{
DataLength = (ushort)((response[0] << 8) + response[1])
};
if(decoded.DataLength + 2 != response.Length) return null;
if(decoded.DataLength + 2 != response.Length)
return null;
decoded.DataType = (byte)((response[2] & 0xE0) >> 5);
decoded.Erasable |= (response[2] & 0x10) == 0x10;
@@ -308,8 +80,10 @@ namespace DiscImageChef.Decoders.SCSI.MMC
decoded.DiscIdentification =
(uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]);
decoded.LastSessionLeadInStartLBA =
(uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]);
decoded.LastPossibleLeadOutStartLBA =
(uint)((response[20] << 24) + (response[21] << 16) + (response[22] << 8) + response[23]);
@@ -321,9 +95,12 @@ namespace DiscImageChef.Decoders.SCSI.MMC
decoded.DiscApplicationCode = response[32];
decoded.OPCTablesNumber = response[33];
if(decoded.OPCTablesNumber <= 0 || response.Length != decoded.OPCTablesNumber * 8 + 34) return decoded;
if(decoded.OPCTablesNumber <= 0 ||
response.Length != decoded.OPCTablesNumber * 8 + 34)
return decoded;
decoded.OPCTables = new OPCTable[decoded.OPCTablesNumber];
for(int i = 0; i < decoded.OPCTablesNumber; i++)
{
decoded.OPCTables[i].Speed = (ushort)((response[34 + i * 8 + 0] << 16) + response[34 + i * 8 + 1]);
@@ -336,30 +113,37 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string Prettify000b(StandardDiscInformation? information)
{
if(!information.HasValue) return null;
if(!information.HasValue)
return null;
StandardDiscInformation decoded = information.Value;
if(decoded.DataType != 0) return null;
if(decoded.DataType != 0)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
switch(decoded.DiscType)
{
case 0x00:
sb.AppendLine("Disc type declared as CD-DA or CD-ROM");
break;
case 0x10:
sb.AppendLine("Disc type declared as CD-i");
break;
case 0x20:
sb.AppendLine("Disc type declared as CD-ROM XA");
break;
case 0xFF:
sb.AppendLine("Disc type is undefined");
break;
default:
sb.AppendFormat("Unknown disc type {0:X2}h", decoded.DiscType).AppendLine();
break;
}
@@ -367,30 +151,38 @@ namespace DiscImageChef.Decoders.SCSI.MMC
{
case 0:
sb.AppendLine("Disc is empty");
break;
case 1:
sb.AppendLine("Disc is incomplete");
break;
case 2:
sb.AppendLine("Disc is finalized");
break;
}
if(decoded.Erasable) sb.AppendLine("Disc is erasable");
if(decoded.Erasable)
sb.AppendLine("Disc is erasable");
switch(decoded.LastSessionStatus)
{
case 0:
sb.AppendLine("Last session is empty");
break;
case 1:
sb.AppendLine("Last session is incomplete");
break;
case 2:
sb.AppendLine("Last session is damaged");
break;
case 3:
sb.AppendLine("Last session is complete");
break;
}
@@ -398,26 +190,31 @@ namespace DiscImageChef.Decoders.SCSI.MMC
{
case 1:
sb.AppendLine("Media was being formatted in the background but it is stopped and incomplete");
break;
case 2:
sb.AppendLine("Media is currently being formatted in the background");
break;
case 3:
sb.AppendLine("Media background formatting has completed");
break;
}
if(decoded.Dbit) sb.AppendLine("MRW is dirty");
if(decoded.Dbit)
sb.AppendLine("MRW is dirty");
sb.AppendFormat("First track on disc is track {0}", decoded.FirstTrackNumber).AppendLine();
sb.AppendFormat("Disc has {0} sessions", decoded.Sessions).AppendLine();
sb.AppendFormat("First track in last session is track {0}", decoded.FirstTrackLastSession).AppendLine();
sb.AppendFormat("Last track in last session is track {0}", decoded.LastTrackLastSession).AppendLine();
sb.AppendFormat("Last session Lead-In address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}",
decoded.LastSessionLeadInStartLBA, (decoded.LastSessionLeadInStartLBA & 0xFF0000) >> 16,
(decoded.LastSessionLeadInStartLBA & 0xFF00) >> 8,
decoded.LastSessionLeadInStartLBA & 0xFF)
.AppendLine();
decoded.LastSessionLeadInStartLBA & 0xFF).AppendLine();
sb.AppendFormat("Last possible Lead-Out address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}",
decoded.LastPossibleLeadOutStartLBA, (decoded.LastPossibleLeadOutStartLBA & 0xFF0000) >> 16,
(decoded.LastPossibleLeadOutStartLBA & 0xFF00) >> 8,
@@ -425,11 +222,17 @@ namespace DiscImageChef.Decoders.SCSI.MMC
sb.AppendLine(decoded.URU ? "Disc is defined for unrestricted use" : "Disc is defined for restricted use");
if(decoded.DID_V) sb.AppendFormat("Disc ID: {0:X6}", decoded.DiscIdentification & 0x00FFFFFF).AppendLine();
if(decoded.DBC_V) sb.AppendFormat("Disc barcode: {0:X16}", decoded.DiscBarcode).AppendLine();
if(decoded.DAC_V) sb.AppendFormat("Disc application code: {0}", decoded.DiscApplicationCode).AppendLine();
if(decoded.DID_V)
sb.AppendFormat("Disc ID: {0:X6}", decoded.DiscIdentification & 0x00FFFFFF).AppendLine();
if(decoded.OPCTables == null) return sb.ToString();
if(decoded.DBC_V)
sb.AppendFormat("Disc barcode: {0:X16}", decoded.DiscBarcode).AppendLine();
if(decoded.DAC_V)
sb.AppendFormat("Disc application code: {0}", decoded.DiscApplicationCode).AppendLine();
if(decoded.OPCTables == null)
return sb.ToString();
foreach(OPCTable table in decoded.OPCTables)
sb.AppendFormat("OPC values for {0}Kbit/sec.: {1}, {2}, {3}, {4}, {5}, {6}", table.Speed,
@@ -441,14 +244,19 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static TrackResourcesInformation? Decode001b(byte[] response)
{
if(response.Length != 12) return null;
if(response.Length != 12)
return null;
if((response[2] & 0xE0) != 0x20) return null;
if((response[2] & 0xE0) != 0x20)
return null;
TrackResourcesInformation decoded =
new TrackResourcesInformation {DataLength = (ushort)((response[0] << 8) + response[1])};
var decoded = new TrackResourcesInformation
{
DataLength = (ushort)((response[0] << 8) + response[1])
};
if(decoded.DataLength + 2 != response.Length) return null;
if(decoded.DataLength + 2 != response.Length)
return null;
decoded.DataType = (byte)((response[2] & 0xE0) >> 5);
decoded.MaxTracks = (ushort)((response[4] << 8) + response[5]);
@@ -461,18 +269,22 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string Prettify001b(TrackResourcesInformation? information)
{
if(!information.HasValue) return null;
if(!information.HasValue)
return null;
TrackResourcesInformation decoded = information.Value;
if(decoded.DataType != 1) return null;
if(decoded.DataType != 1)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendFormat("{0} maximum possible tracks on the disc", decoded.MaxTracks).AppendLine();
sb.AppendFormat("{0} assigned tracks on the disc", decoded.AssignedTracks).AppendLine();
sb.AppendFormat("{0} maximum possible appendable tracks on the disc", decoded.AppendableTracks)
.AppendLine();
sb.AppendFormat("{0} maximum possible appendable tracks on the disc", decoded.AppendableTracks).
AppendLine();
sb.AppendFormat("{0} current appendable tracks on the disc", decoded.MaxAppendableTracks).AppendLine();
return sb.ToString();
@@ -480,20 +292,28 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static POWResourcesInformation? Decode010b(byte[] response)
{
if(response.Length != 16) return null;
if(response.Length != 16)
return null;
if((response[2] & 0xE0) != 0x40) return null;
if((response[2] & 0xE0) != 0x40)
return null;
POWResourcesInformation decoded =
new POWResourcesInformation {DataLength = (ushort)((response[0] << 8) + response[1])};
var decoded = new POWResourcesInformation
{
DataLength = (ushort)((response[0] << 8) + response[1])
};
if(decoded.DataLength + 2 != response.Length) return null;
if(decoded.DataLength + 2 != response.Length)
return null;
decoded.DataType = (byte)((response[2] & 0xE0) >> 5);
decoded.RemainingPOWReplacements =
(ushort)((response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7]);
decoded.RemainingPOWReallocation =
(ushort)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]);
decoded.RemainingPOWUpdates =
(ushort)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]);
@@ -502,17 +322,21 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string Prettify010b(POWResourcesInformation? information)
{
if(!information.HasValue) return null;
if(!information.HasValue)
return null;
POWResourcesInformation decoded = information.Value;
if(decoded.DataType != 1) return null;
if(decoded.DataType != 1)
return null;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendFormat("{0} remaining POW replacements", decoded.RemainingPOWReplacements).AppendLine();
sb.AppendFormat("{0} remaining POW reallocation map entries", decoded.RemainingPOWReallocation)
.AppendLine();
sb.AppendFormat("{0} remaining POW reallocation map entries", decoded.RemainingPOWReallocation).
AppendLine();
sb.AppendFormat("{0} remaining POW updates", decoded.RemainingPOWUpdates).AppendLine();
return sb.ToString();
@@ -520,9 +344,11 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string Prettify(byte[] response)
{
if(response == null) return null;
if(response == null)
return null;
if(response.Length < 12) return null;
if(response.Length < 12)
return null;
switch(response[2] & 0xE0)
{
@@ -533,5 +359,103 @@ namespace DiscImageChef.Decoders.SCSI.MMC
return null;
}
public struct StandardDiscInformation
{
/// <summary>Bytes 0 to 1 32 + OPCTablesNumber*8</summary>
public ushort DataLength;
/// <summary>Byte 2, bits 7 to 5 000b</summary>
public byte DataType;
/// <summary>Byte 2, bit 4 If set, disc is erasable</summary>
public bool Erasable;
/// <summary>Byte 2, bits 3 to 2 Status of last session</summary>
public byte LastSessionStatus;
/// <summary>Byte 2, bits 1 to 0 Status of disc</summary>
public byte DiscStatus;
/// <summary>Byte 3 Number of logical track that contains LBA 0</summary>
public byte FirstTrackNumber;
/// <summary>Byte 9 (MSB) and byte 4 (LSB) Number of sessions</summary>
public ushort Sessions;
/// <summary>Byte 10 (MSB) and byte 5 (LSB) Number of first track in last session</summary>
public ushort FirstTrackLastSession;
/// <summary>Byte 11 (MSB) and byte 6 (LSB) Number of last track in last session</summary>
public ushort LastTrackLastSession;
/// <summary>Byte 7, bit 7 If set, DiscIdentification is valid</summary>
public bool DID_V;
/// <summary>Byte 7, bit 6 If set, DiscBarcode is valid</summary>
public bool DBC_V;
/// <summary>Byte 7, bit 5 If set, disc is unrestricted</summary>
public bool URU;
/// <summary>Byte 7, bit 4 If set DiscApplicationCode is valid</summary>
public bool DAC_V;
/// <summary>Byte 7, bit 3 Reserved</summary>
public bool Reserved;
/// <summary>Byte 7, bit 2 Copy of dirty bit from MRW status</summary>
public bool Dbit;
/// <summary>Byte 7, bits 1 to 0 Background format status</summary>
public byte BGFormatStatus;
/// <summary>Byte 8 Disc type code</summary>
public byte DiscType;
/// <summary>Bytes 12 to 15 Disc identification number from PMA</summary>
public uint DiscIdentification;
/// <summary>Bytes 16 to 19 Last Session Lead-in Start Address (MSF for CD, LBA for others)</summary>
public uint LastSessionLeadInStartLBA;
/// <summary>Bytes 20 to 23 Last Possible Lead-out Start Address (MSF for CD, LBA for others)</summary>
public uint LastPossibleLeadOutStartLBA;
/// <summary>Bytes 24 to 31 Disc barcode</summary>
public ulong DiscBarcode;
/// <summary>Byte 32 Disc application code</summary>
public byte DiscApplicationCode;
/// <summary>Byte 33 How many OPC tables are</summary>
public byte OPCTablesNumber;
/// <summary>Bytes 34 to end OPC tables (8 bytes each)</summary>
public OPCTable[] OPCTables;
}
public struct OPCTable
{
/// <summary>Bytes 0 to 1 kilobytes/sec this OPC table applies to</summary>
public ushort Speed;
/// <summary>Bytes 2 to 7 OPC values</summary>
public byte[] OPCValues;
}
public struct TrackResourcesInformation
{
/// <summary>Bytes 0 to 1 10</summary>
public ushort DataLength;
/// <summary>Byte 2, bits 7 to 5 001b</summary>
public byte DataType;
/// <summary>Byte 2, bits 4 to 0 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 5 Maximum possible number of the tracks on the disc</summary>
public ushort MaxTracks;
/// <summary>Bytes 6 to 7 Number of the assigned tracks on the disc</summary>
public ushort AssignedTracks;
/// <summary>Bytes 8 to 9 Maximum possible number of appendable tracks on the disc</summary>
public ushort MaxAppendableTracks;
/// <summary>Bytes 10 to 11 Current number of appendable tracks on the disc</summary>
public ushort AppendableTracks;
}
public struct POWResourcesInformation
{
/// <summary>Bytes 0 to 1 14</summary>
public ushort DataLength;
/// <summary>Byte 2, bits 7 to 5 010b</summary>
public byte DataType;
/// <summary>Byte 2, bits 4 to 0 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Bytes 4 to 7 Remaining POW replacements</summary>
public uint RemainingPOWReplacements;
/// <summary>Bytes 8 to 11 Remaining POW reallocation map entries</summary>
public uint RemainingPOWReallocation;
/// <summary>Bytes 12 to 15 Number of remaining POW updates</summary>
public uint RemainingPOWUpdates;
}
}
}

View File

@@ -34,56 +34,38 @@ using System.Diagnostics.CodeAnalysis;
namespace DiscImageChef.Decoders.SCSI.MMC
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")]
public enum FormatLayerTypeCodes : ushort
{
CDLayer = 0x0008,
DVDLayer = 0x0010,
BDLayer = 0x0040,
CDLayer = 0x0008, DVDLayer = 0x0010, BDLayer = 0x0040,
HDDVDLayer = 0x0050
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")]
public enum SessionStatusCodes : byte
{
Empty = 0x00,
Incomplete = 0x01,
ReservedOrDamaged = 0x02,
Complete = 0x03
Empty = 0x00, Incomplete = 0x01, ReservedOrDamaged = 0x02,
Complete = 0x03
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")]
public enum DiscStatusCodes : byte
{
Empty = 0x00,
Incomplete = 0x01,
Finalized = 0x02,
Others = 0x03
Empty = 0x00, Incomplete = 0x01, Finalized = 0x02,
Others = 0x03
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")]
public enum BGFormatStatusCodes : byte
{
NoFormattable = 0x00,
IncompleteBackgroundFormat = 0x01,
BackgroundFormatInProgress = 0x02,
FormatComplete = 0x03
NoFormattable = 0x00, IncompleteBackgroundFormat = 0x01, BackgroundFormatInProgress = 0x02,
FormatComplete = 0x03
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")]
public enum DiscTypeCodes : byte
{
/// <summary>
/// Also valid for CD-DA, DVD and BD
/// </summary>
CDROM = 0x00,
CDi = 0x10,
CDROMXA = 0x20,
Undefined = 0xFF
/// <summary>Also valid for CD-DA, DVD and BD</summary>
CDROM = 0x00, CDi = 0x10, CDROMXA = 0x20, Undefined = 0xFF
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -36,90 +36,29 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI.MMC
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class Hybrid
{
public struct RecognizedFormatLayers
{
/// <summary>
/// Bytes 0 to 1
/// Data Length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Byte 4
/// Number of format layers in hybrid disc identified by drive
/// </summary>
public byte NumberOfLayers;
/// <summary>
/// Byte 5, bits 7 to 6
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Byte 5, bits 5 to 4
/// Layer no. used when disc is inserted
/// </summary>
public byte DefaultFormatLayer;
/// <summary>
/// Byte 5, bits 3 to 2
/// Reserved
/// </summary>
public byte Reserved4;
/// <summary>
/// Byte 5, bits 1 to 0
/// Layer no. currently in use
/// </summary>
public byte OnlineFormatLayer;
/// <summary>
/// Bytes 6 to end
/// Recognized format layers
/// </summary>
public ushort[] FormatLayers;
}
public static RecognizedFormatLayers? DecodeFormatLayers(byte[] FormatLayersResponse)
{
if(FormatLayersResponse == null) return null;
if(FormatLayersResponse == null)
return null;
if(FormatLayersResponse.Length < 8) return null;
if(FormatLayersResponse.Length < 8)
return null;
RecognizedFormatLayers decoded = new RecognizedFormatLayers
var decoded = new RecognizedFormatLayers
{
DataLength = BigEndianBitConverter.ToUInt16(FormatLayersResponse, 0),
Reserved1 = FormatLayersResponse[2],
Reserved2 = FormatLayersResponse[3],
NumberOfLayers = FormatLayersResponse[4],
Reserved3 = (byte)((FormatLayersResponse[5] & 0xC0) >> 6),
DefaultFormatLayer = (byte)((FormatLayersResponse[5] & 0x30) >> 4),
Reserved4 = (byte)((FormatLayersResponse[5] & 0x0C) >> 2),
Reserved1 = FormatLayersResponse[2], Reserved2 = FormatLayersResponse[3],
NumberOfLayers = FormatLayersResponse[4], Reserved3 = (byte)((FormatLayersResponse[5] & 0xC0) >> 6),
DefaultFormatLayer = (byte)((FormatLayersResponse[5] & 0x30) >> 4),
Reserved4 = (byte)((FormatLayersResponse[5] & 0x0C) >> 2),
OnlineFormatLayer = (byte)(FormatLayersResponse[5] & 0x03),
FormatLayers = new ushort[(FormatLayersResponse.Length - 6) / 2]
};
@@ -132,55 +71,81 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyFormatLayers(RecognizedFormatLayers? FormatLayersResponse)
{
if(FormatLayersResponse == null) return null;
if(FormatLayersResponse == null)
return null;
RecognizedFormatLayers response = FormatLayersResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendFormat("{0} format layers recognized", response.NumberOfLayers);
for(int i = 0; i < response.FormatLayers.Length; i++)
switch(response.FormatLayers[i])
{
case (ushort)FormatLayerTypeCodes.BDLayer:
case(ushort)FormatLayerTypeCodes.BDLayer:
{
sb.AppendFormat("Layer {0} is of type Blu-ray", i).AppendLine();
if(response.DefaultFormatLayer == i) sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i) sb.AppendLine("This is the layer actually in use.");
if(response.DefaultFormatLayer == i)
sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i)
sb.AppendLine("This is the layer actually in use.");
break;
}
case (ushort)FormatLayerTypeCodes.CDLayer:
case(ushort)FormatLayerTypeCodes.CDLayer:
{
sb.AppendFormat("Layer {0} is of type CD", i).AppendLine();
if(response.DefaultFormatLayer == i) sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i) sb.AppendLine("This is the layer actually in use.");
if(response.DefaultFormatLayer == i)
sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i)
sb.AppendLine("This is the layer actually in use.");
break;
}
case (ushort)FormatLayerTypeCodes.DVDLayer:
case(ushort)FormatLayerTypeCodes.DVDLayer:
{
sb.AppendFormat("Layer {0} is of type DVD", i).AppendLine();
if(response.DefaultFormatLayer == i) sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i) sb.AppendLine("This is the layer actually in use.");
if(response.DefaultFormatLayer == i)
sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i)
sb.AppendLine("This is the layer actually in use.");
break;
}
case (ushort)FormatLayerTypeCodes.HDDVDLayer:
case(ushort)FormatLayerTypeCodes.HDDVDLayer:
{
sb.AppendFormat("Layer {0} is of type HD DVD", i).AppendLine();
if(response.DefaultFormatLayer == i) sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i) sb.AppendLine("This is the layer actually in use.");
if(response.DefaultFormatLayer == i)
sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i)
sb.AppendLine("This is the layer actually in use.");
break;
}
default:
{
sb.AppendFormat("Layer {0} is of unknown type 0x{1:X4}", i, response.FormatLayers[i])
.AppendLine();
if(response.DefaultFormatLayer == i) sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i) sb.AppendLine("This is the layer actually in use.");
sb.AppendFormat("Layer {0} is of unknown type 0x{1:X4}", i, response.FormatLayers[i]).
AppendLine();
if(response.DefaultFormatLayer == i)
sb.AppendLine("This is the default layer.");
if(response.OnlineFormatLayer == i)
sb.AppendLine("This is the layer actually in use.");
break;
}
}
@@ -191,7 +156,30 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyFormatLayers(byte[] FormatLayersResponse)
{
RecognizedFormatLayers? decoded = DecodeFormatLayers(FormatLayersResponse);
return PrettifyFormatLayers(decoded);
}
public struct RecognizedFormatLayers
{
/// <summary>Bytes 0 to 1 Data Length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Byte 4 Number of format layers in hybrid disc identified by drive</summary>
public byte NumberOfLayers;
/// <summary>Byte 5, bits 7 to 6 Reserved</summary>
public byte Reserved3;
/// <summary>Byte 5, bits 5 to 4 Layer no. used when disc is inserted</summary>
public byte DefaultFormatLayer;
/// <summary>Byte 5, bits 3 to 2 Reserved</summary>
public byte Reserved4;
/// <summary>Byte 5, bits 1 to 0 Layer no. currently in use</summary>
public byte OnlineFormatLayer;
/// <summary>Bytes 6 to end Recognized format layers</summary>
public ushort[] FormatLayers;
}
}
}

View File

@@ -37,101 +37,29 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI.MMC
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
/// Information from the following standards: ANSI X3.304-1997 T10/1048-D revision 9.0 T10/1048-D revision 10a
/// T10/1228-D revision 7.0c T10/1228-D revision 11a T10/1363-D revision 10g T10/1545-D revision 1d T10/1545-D revision
/// 5 T10/1545-D revision 5a T10/1675-D revision 2c T10/1675-D revision 4 T10/1836-D revision 2g
/// </summary>
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static class WriteProtect
{
public struct WriteProtectionStatus
{
/// <summary>
/// Bytes 0 to 1
/// Data Length
/// </summary>
public ushort DataLength;
/// <summary>
/// Byte 2
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Byte 4, bits 7 to 4
/// Reserved
/// </summary>
public byte Reserved3;
/// <summary>
/// Byte 4, bit 3
/// Writing inhibited by media specific reason
/// </summary>
public bool MSWI;
/// <summary>
/// Byte 4, bit 2
/// Cartridge sets write protection
/// </summary>
public bool CWP;
/// <summary>
/// Byte 4, bit 1
/// Media surface sets write protection
/// </summary>
public bool PWP;
/// <summary>
/// Byte 4, bit 0
/// Software write protection until power down
/// </summary>
public bool SWPP;
/// <summary>
/// Byte 5
/// Reserved
/// </summary>
public byte Reserved4;
/// <summary>
/// Byte 6
/// Reserved
/// </summary>
public byte Reserved5;
/// <summary>
/// Byte 7
/// Reserved
/// </summary>
public byte Reserved6;
}
public static WriteProtectionStatus? DecodeWriteProtectionStatus(byte[] WPSResponse)
{
if(WPSResponse == null) return null;
if(WPSResponse == null)
return null;
WriteProtectionStatus decoded = new WriteProtectionStatus
var decoded = new WriteProtectionStatus
{
DataLength = BigEndianBitConverter.ToUInt16(WPSResponse, 0),
Reserved1 = WPSResponse[2],
DataLength = BigEndianBitConverter.ToUInt16(WPSResponse, 0), Reserved1 = WPSResponse[2],
Reserved2 = WPSResponse[3],
Reserved3 = (byte)((WPSResponse[4] & 0xF0) >> 4),
MSWI = Convert.ToBoolean(WPSResponse[4] & 0x08),
CWP = Convert.ToBoolean(WPSResponse[4] & 0x04),
PWP = Convert.ToBoolean(WPSResponse[4] & 0x02),
SWPP = Convert.ToBoolean(WPSResponse[4] & 0x01),
Reserved4 = WPSResponse[5],
Reserved5 = WPSResponse[6],
Reserved4 = WPSResponse[5], Reserved5 = WPSResponse[6],
Reserved6 = WPSResponse[7]
};
@@ -140,25 +68,44 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyWriteProtectionStatus(WriteProtectionStatus? WPSResponse)
{
if(WPSResponse == null) return null;
if(WPSResponse == null)
return null;
WriteProtectionStatus response = WPSResponse.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
if(response.MSWI) sb.AppendLine("Writing inhibited by media specific reason");
if(response.CWP) sb.AppendLine("Cartridge sets write protection");
if(response.PWP) sb.AppendLine("Media surface sets write protection");
if(response.SWPP) sb.AppendLine("Software write protection is set until power down");
if(response.MSWI)
sb.AppendLine("Writing inhibited by media specific reason");
#if DEBUG
if(response.Reserved1 != 0) sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0) sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0) sb.AppendFormat("Reserved3 = 0x{0:X2}", response.Reserved3).AppendLine();
if(response.Reserved4 != 0) sb.AppendFormat("Reserved4 = 0x{0:X2}", response.Reserved4).AppendLine();
if(response.Reserved5 != 0) sb.AppendFormat("Reserved5 = 0x{0:X2}", response.Reserved5).AppendLine();
if(response.Reserved6 != 0) sb.AppendFormat("Reserved6 = 0x{0:X2}", response.Reserved6).AppendLine();
#endif
if(response.CWP)
sb.AppendLine("Cartridge sets write protection");
if(response.PWP)
sb.AppendLine("Media surface sets write protection");
if(response.SWPP)
sb.AppendLine("Software write protection is set until power down");
#if DEBUG
if(response.Reserved1 != 0)
sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine();
if(response.Reserved2 != 0)
sb.AppendFormat("Reserved2 = 0x{0:X2}", response.Reserved2).AppendLine();
if(response.Reserved3 != 0)
sb.AppendFormat("Reserved3 = 0x{0:X2}", response.Reserved3).AppendLine();
if(response.Reserved4 != 0)
sb.AppendFormat("Reserved4 = 0x{0:X2}", response.Reserved4).AppendLine();
if(response.Reserved5 != 0)
sb.AppendFormat("Reserved5 = 0x{0:X2}", response.Reserved5).AppendLine();
if(response.Reserved6 != 0)
sb.AppendFormat("Reserved6 = 0x{0:X2}", response.Reserved6).AppendLine();
#endif
return sb.ToString();
}
@@ -166,7 +113,34 @@ namespace DiscImageChef.Decoders.SCSI.MMC
public static string PrettifyWriteProtectionStatus(byte[] WPSResponse)
{
WriteProtectionStatus? decoded = DecodeWriteProtectionStatus(WPSResponse);
return PrettifyWriteProtectionStatus(decoded);
}
public struct WriteProtectionStatus
{
/// <summary>Bytes 0 to 1 Data Length</summary>
public ushort DataLength;
/// <summary>Byte 2 Reserved</summary>
public byte Reserved1;
/// <summary>Byte 3 Reserved</summary>
public byte Reserved2;
/// <summary>Byte 4, bits 7 to 4 Reserved</summary>
public byte Reserved3;
/// <summary>Byte 4, bit 3 Writing inhibited by media specific reason</summary>
public bool MSWI;
/// <summary>Byte 4, bit 2 Cartridge sets write protection</summary>
public bool CWP;
/// <summary>Byte 4, bit 1 Media surface sets write protection</summary>
public bool PWP;
/// <summary>Byte 4, bit 0 Software write protection until power down</summary>
public bool SWPP;
/// <summary>Byte 5 Reserved</summary>
public byte Reserved4;
/// <summary>Byte 6 Reserved</summary>
public byte Reserved5;
/// <summary>Byte 7 Reserved</summary>
public byte Reserved6;
}
}
}

View File

@@ -35,52 +35,41 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x00: Drive Operation Mode page
/// <summary>
/// Drive Operation Mode page
/// Page code 0x00
/// 4 bytes in INF-8070
/// </summary>
/// <summary>Drive Operation Mode page Page code 0x00 4 bytes in INF-8070</summary>
public struct ModePage_00_SFF
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Select LUN Mode
/// </summary>
/// <summary>Select LUN Mode</summary>
public bool SLM;
/// <summary>
/// Select LUN for rewritable
/// </summary>
/// <summary>Select LUN for rewritable</summary>
public bool SLR;
/// <summary>
/// Disable verify for WRITE
/// </summary>
/// <summary>Disable verify for WRITE</summary>
public bool DVW;
/// <summary>
/// Disable deferred error
/// </summary>
/// <summary>Disable deferred error</summary>
public bool DDE;
}
public static ModePage_00_SFF? DecodeModePage_00_SFF(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x00) return null;
if((pageResponse?[0] & 0x3F) != 0x00)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 4) return null;
if(pageResponse.Length < 4)
return null;
ModePage_00_SFF decoded = new ModePage_00_SFF();
var decoded = new ModePage_00_SFF();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -98,19 +87,25 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_00_SFF(ModePage_00_SFF? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_00_SFF page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Drive Operation Mode page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.DVW) sb.AppendLine("\tVerifying after writing is disabled");
if(page.DDE) sb.AppendLine("\tDrive will abort when a writing error is detected");
if(page.DVW)
sb.AppendLine("\tVerifying after writing is disabled");
if(!page.SLM) return sb.ToString();
if(page.DDE)
sb.AppendLine("\tDrive will abort when a writing error is detected");
if(!page.SLM)
return sb.ToString();
sb.Append("\tDrive has two LUNs with rewritable being ");
sb.AppendLine(page.SLR ? "LUN 1" : "LUN 0");

View File

@@ -35,159 +35,10 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x01: Read-write error recovery page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x01
/// 12 bytes in SCSI-2, SBC-1, SBC-2
/// </summary>
public struct ModePage_01
{
/// <summary>
/// Parameters can be saved
/// </summary>
public bool PS;
/// <summary>
/// Automatic Write Reallocation Enabled
/// </summary>
public bool AWRE;
/// <summary>
/// Automatic Read Reallocation Enabled
/// </summary>
public bool ARRE;
/// <summary>
/// Transfer block
/// </summary>
public bool TB;
/// <summary>
/// Read continuous
/// </summary>
public bool RC;
/// <summary>
/// Enable early recovery
/// </summary>
public bool EER;
/// <summary>
/// Post error reporting
/// </summary>
public bool PER;
/// <summary>
/// Disable transfer on error
/// </summary>
public bool DTE;
/// <summary>
/// Disable correction
/// </summary>
public bool DCR;
/// <summary>
/// How many times to retry a read operation
/// </summary>
public byte ReadRetryCount;
/// <summary>
/// How many bits of largest data burst error is maximum to apply error correction on it
/// </summary>
public byte CorrectionSpan;
/// <summary>
/// Offset to move the heads
/// </summary>
public sbyte HeadOffsetCount;
/// <summary>
/// Incremental position to which the recovered data strobe shall be adjusted
/// </summary>
public sbyte DataStrobeOffsetCount;
/// <summary>
/// How many times to retry a write operation
/// </summary>
public byte WriteRetryCount;
/// <summary>
/// Maximum time in ms to use in data error recovery procedures
/// </summary>
public ushort RecoveryTimeLimit;
/// <summary>
/// Logical block provisioning error reporting is enabled
/// </summary>
public bool LBPERE;
}
public static ModePage_01? DecodeModePage_01(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x3F) != 0x01) return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse.Length < 8) return null;
ModePage_01 decoded = new ModePage_01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.AWRE |= (pageResponse[2] & 0x80) == 0x80;
decoded.ARRE |= (pageResponse[2] & 0x40) == 0x40;
decoded.TB |= (pageResponse[2] & 0x20) == 0x20;
decoded.RC |= (pageResponse[2] & 0x10) == 0x10;
decoded.EER |= (pageResponse[2] & 0x08) == 0x08;
decoded.PER |= (pageResponse[2] & 0x04) == 0x04;
decoded.DTE |= (pageResponse[2] & 0x02) == 0x02;
decoded.DCR |= (pageResponse[2] & 0x01) == 0x01;
decoded.ReadRetryCount = pageResponse[3];
decoded.CorrectionSpan = pageResponse[4];
decoded.HeadOffsetCount = (sbyte)pageResponse[5];
decoded.DataStrobeOffsetCount = (sbyte)pageResponse[6];
if(pageResponse.Length < 12) return decoded;
decoded.WriteRetryCount = pageResponse[8];
decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.LBPERE |= (pageResponse[7] & 0x80) == 0x80;
return decoded;
}
public static string PrettifyModePage_01(byte[] pageResponse) =>
PrettifyModePage_01(DecodeModePage_01(pageResponse));
public static string PrettifyModePage_01(ModePage_01? modePage)
{
if(!modePage.HasValue) return null;
ModePage_01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
sb.AppendLine("SCSI Read-write error recovery page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.AWRE) sb.AppendLine("\tAutomatic write reallocation is enabled");
if(page.ARRE) sb.AppendLine("\tAutomatic read reallocation is enabled");
if(page.TB)
sb.AppendLine("\tData not recovered within limits shall be transferred back before a CHECK CONDITION");
if(page.RC)
sb.AppendLine("\tDrive will transfer the entire requested length without delaying to perform error recovery");
if(page.EER) sb.AppendLine("\tDrive will use the most expedient form of error recovery first");
if(page.PER) sb.AppendLine("\tDrive shall report recovered errors");
if(page.DTE) sb.AppendLine("\tTransfer will be terminated upon error detection");
if(page.DCR) sb.AppendLine("\tError correction is disabled");
if(page.ReadRetryCount > 0)
sb.AppendFormat("\tDrive will repeat read operations {0} times", page.ReadRetryCount).AppendLine();
if(page.WriteRetryCount > 0)
sb.AppendFormat("\tDrive will repeat write operations {0} times", page.WriteRetryCount).AppendLine();
if(page.RecoveryTimeLimit > 0)
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit)
.AppendLine();
if(page.LBPERE) sb.AppendLine("Logical block provisioning error reporting is enabled");
return sb.ToString();
}
#endregion Mode Page 0x01: Read-write error recovery page
public static byte[] EncodeModePage_01(ModePage_01 page)
{
byte[] pg = new byte[8];
@@ -195,15 +46,32 @@ namespace DiscImageChef.Decoders.SCSI
pg[0] = 0x01;
pg[1] = 6;
if(page.PS) pg[0] += 0x80;
if(page.AWRE) pg[2] += 0x80;
if(page.ARRE) pg[2] += 0x40;
if(page.TB) pg[2] += 0x20;
if(page.RC) pg[2] += 0x10;
if(page.EER) pg[2] += 0x08;
if(page.PER) pg[2] += 0x04;
if(page.DTE) pg[2] += 0x02;
if(page.DCR) pg[2] += 0x01;
if(page.PS)
pg[0] += 0x80;
if(page.AWRE)
pg[2] += 0x80;
if(page.ARRE)
pg[2] += 0x40;
if(page.TB)
pg[2] += 0x20;
if(page.RC)
pg[2] += 0x10;
if(page.EER)
pg[2] += 0x08;
if(page.PER)
pg[2] += 0x04;
if(page.DTE)
pg[2] += 0x02;
if(page.DCR)
pg[2] += 0x01;
pg[3] = page.ReadRetryCount;
pg[4] = page.CorrectionSpan;
@@ -220,5 +88,142 @@ namespace DiscImageChef.Decoders.SCSI
return pg;
}
#region Mode Page 0x01: Read-write error recovery page
/// <summary>Disconnect-reconnect page Page code 0x01 12 bytes in SCSI-2, SBC-1, SBC-2</summary>
public struct ModePage_01
{
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>Automatic Write Reallocation Enabled</summary>
public bool AWRE;
/// <summary>Automatic Read Reallocation Enabled</summary>
public bool ARRE;
/// <summary>Transfer block</summary>
public bool TB;
/// <summary>Read continuous</summary>
public bool RC;
/// <summary>Enable early recovery</summary>
public bool EER;
/// <summary>Post error reporting</summary>
public bool PER;
/// <summary>Disable transfer on error</summary>
public bool DTE;
/// <summary>Disable correction</summary>
public bool DCR;
/// <summary>How many times to retry a read operation</summary>
public byte ReadRetryCount;
/// <summary>How many bits of largest data burst error is maximum to apply error correction on it</summary>
public byte CorrectionSpan;
/// <summary>Offset to move the heads</summary>
public sbyte HeadOffsetCount;
/// <summary>Incremental position to which the recovered data strobe shall be adjusted</summary>
public sbyte DataStrobeOffsetCount;
/// <summary>How many times to retry a write operation</summary>
public byte WriteRetryCount;
/// <summary>Maximum time in ms to use in data error recovery procedures</summary>
public ushort RecoveryTimeLimit;
/// <summary>Logical block provisioning error reporting is enabled</summary>
public bool LBPERE;
}
public static ModePage_01? DecodeModePage_01(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x01)
return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8)
return null;
var decoded = new ModePage_01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.AWRE |= (pageResponse[2] & 0x80) == 0x80;
decoded.ARRE |= (pageResponse[2] & 0x40) == 0x40;
decoded.TB |= (pageResponse[2] & 0x20) == 0x20;
decoded.RC |= (pageResponse[2] & 0x10) == 0x10;
decoded.EER |= (pageResponse[2] & 0x08) == 0x08;
decoded.PER |= (pageResponse[2] & 0x04) == 0x04;
decoded.DTE |= (pageResponse[2] & 0x02) == 0x02;
decoded.DCR |= (pageResponse[2] & 0x01) == 0x01;
decoded.ReadRetryCount = pageResponse[3];
decoded.CorrectionSpan = pageResponse[4];
decoded.HeadOffsetCount = (sbyte)pageResponse[5];
decoded.DataStrobeOffsetCount = (sbyte)pageResponse[6];
if(pageResponse.Length < 12)
return decoded;
decoded.WriteRetryCount = pageResponse[8];
decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.LBPERE |= (pageResponse[7] & 0x80) == 0x80;
return decoded;
}
public static string PrettifyModePage_01(byte[] pageResponse) =>
PrettifyModePage_01(DecodeModePage_01(pageResponse));
public static string PrettifyModePage_01(ModePage_01? modePage)
{
if(!modePage.HasValue)
return null;
ModePage_01 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Read-write error recovery page:");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.AWRE)
sb.AppendLine("\tAutomatic write reallocation is enabled");
if(page.ARRE)
sb.AppendLine("\tAutomatic read reallocation is enabled");
if(page.TB)
sb.AppendLine("\tData not recovered within limits shall be transferred back before a CHECK CONDITION");
if(page.RC)
sb.AppendLine("\tDrive will transfer the entire requested length without delaying to perform error recovery");
if(page.EER)
sb.AppendLine("\tDrive will use the most expedient form of error recovery first");
if(page.PER)
sb.AppendLine("\tDrive shall report recovered errors");
if(page.DTE)
sb.AppendLine("\tTransfer will be terminated upon error detection");
if(page.DCR)
sb.AppendLine("\tError correction is disabled");
if(page.ReadRetryCount > 0)
sb.AppendFormat("\tDrive will repeat read operations {0} times", page.ReadRetryCount).AppendLine();
if(page.WriteRetryCount > 0)
sb.AppendFormat("\tDrive will repeat write operations {0} times", page.WriteRetryCount).AppendLine();
if(page.RecoveryTimeLimit > 0)
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit).
AppendLine();
if(page.LBPERE)
sb.AppendLine("Logical block provisioning error reporting is enabled");
return sb.ToString();
}
#endregion Mode Page 0x01: Read-write error recovery page
}
}

View File

@@ -35,59 +35,73 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
public static byte[] EncodeModePage_01_MMC(ModePage_01_MMC page)
{
byte[] pg = new byte[12];
pg[0] = 0x01;
pg[1] = 10;
if(page.PS)
pg[0] += 0x80;
pg[2] = page.Parameter;
pg[3] = page.ReadRetryCount;
// This is from a newer version of SCSI unknown what happen for drives expecting an 8 byte page
pg[8] = page.WriteRetryCount;
pg[10] = (byte)((page.RecoveryTimeLimit & 0xFF00) << 8);
pg[11] = (byte)(page.RecoveryTimeLimit & 0xFF);
return pg;
}
#region Mode Page 0x01: Read error recovery page for MultiMedia Devices
/// <summary>
/// Read error recovery page for MultiMedia Devices
/// Page code 0x01
/// 8 bytes in SCSI-2, MMC-1
/// 12 bytes in MMC-2, MMC-3
/// Read error recovery page for MultiMedia Devices Page code 0x01 8 bytes in SCSI-2, MMC-1 12 bytes in MMC-2,
/// MMC-3
/// </summary>
public struct ModePage_01_MMC
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Error recovery parameter
/// </summary>
/// <summary>Error recovery parameter</summary>
public byte Parameter;
/// <summary>
/// How many times to retry a read operation
/// </summary>
/// <summary>How many times to retry a read operation</summary>
public byte ReadRetryCount;
/// <summary>
/// How many times to retry a write operation
/// </summary>
/// <summary>How many times to retry a write operation</summary>
public byte WriteRetryCount;
/// <summary>
/// Maximum time in ms to use in data error recovery procedures
/// </summary>
/// <summary>Maximum time in ms to use in data error recovery procedures</summary>
public ushort RecoveryTimeLimit;
}
public static ModePage_01_MMC? DecodeModePage_01_MMC(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x01) return null;
if((pageResponse?[0] & 0x3F) != 0x01)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_01_MMC decoded = new ModePage_01_MMC();
var decoded = new ModePage_01_MMC();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Parameter = pageResponse[2];
decoded.ReadRetryCount = pageResponse[3];
if(pageResponse.Length < 12) return decoded;
if(pageResponse.Length < 12)
return decoded;
decoded.WriteRetryCount = pageResponse[8];
decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
@@ -100,14 +114,17 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_01_MMC(ModePage_01_MMC? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_01_MMC page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Read error recovery page for MultiMedia Devices:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.ReadRetryCount > 0)
sb.AppendFormat("\tDrive will repeat read operations {0} times", page.ReadRetryCount).AppendLine();
@@ -121,8 +138,10 @@ namespace DiscImageChef.Decoders.SCSI
string UnrecCIRCAbort = "\tUnrecovered CIRC errors will return CHECK CONDITION.";
string UnrecECCNotAbort = "\tUnrecovered ECC errors will not abort the transfer.";
string UnrecCIRCNotAbort = "\tUnrecovered CIRC errors will not abort the transfer.";
string UnrecECCAbortData =
"\tUnrecovered ECC errors will return CHECK CONDITION and the uncorrected data.";
string UnrecCIRCAbortData =
"\tUnrecovered CIRC errors will return CHECK CONDITION and the uncorrected data.";
@@ -130,51 +149,67 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0x00:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbort);
break;
case 0x01:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbort);
break;
case 0x04:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbort);
break;
case 0x05:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbort);
break;
case 0x06:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbort);
break;
case 0x07:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbort);
break;
case 0x10:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCNotAbort);
break;
case 0x11:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCNotAbort);
break;
case 0x14:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCNotAbort);
break;
case 0x15:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCNotAbort);
break;
case 0x20:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbortData);
break;
case 0x21:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbortData);
break;
case 0x24:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbortData);
break;
case 0x25:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbortData);
break;
case 0x26:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbortData);
break;
case 0x27:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbortData);
break;
case 0x30: goto case 0x10;
case 0x31: goto case 0x11;
@@ -182,37 +217,19 @@ namespace DiscImageChef.Decoders.SCSI
case 0x35: goto case 0x15;
default:
sb.AppendFormat("Unknown recovery parameter 0x{0:X2}", page.Parameter).AppendLine();
break;
}
if(page.WriteRetryCount > 0)
sb.AppendFormat("\tDrive will repeat write operations {0} times", page.WriteRetryCount).AppendLine();
if(page.RecoveryTimeLimit > 0)
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit)
.AppendLine();
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit).
AppendLine();
return sb.ToString();
}
#endregion Mode Page 0x01: Read error recovery page for MultiMedia Devices
public static byte[] EncodeModePage_01_MMC(ModePage_01_MMC page)
{
byte[] pg = new byte[12];
pg[0] = 0x01;
pg[1] = 10;
if(page.PS) pg[0] += 0x80;
pg[2] = page.Parameter;
pg[3] = page.ReadRetryCount;
// This is from a newer version of SCSI unknown what happen for drives expecting an 8 byte page
pg[8] = page.WriteRetryCount;
pg[10] = (byte)((page.RecoveryTimeLimit & 0xFF00) << 8);
pg[11] = (byte)(page.RecoveryTimeLimit & 0xFF);
return pg;
}
}
}

View File

@@ -35,82 +35,59 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x02: Disconnect-reconnect page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x02
/// 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3, SPC-4, SPC-5
/// </summary>
/// <summary>Disconnect-reconnect page Page code 0x02 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3, SPC-4, SPC-5</summary>
public struct ModePage_02
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// How full should be the buffer prior to attempting a reselection
/// </summary>
/// <summary>How full should be the buffer prior to attempting a reselection</summary>
public byte BufferFullRatio;
/// <summary>
/// How empty should be the buffer prior to attempting a reselection
/// </summary>
/// <summary>How empty should be the buffer prior to attempting a reselection</summary>
public byte BufferEmptyRatio;
/// <summary>
/// Max. time in 100 µs increments that the target is permitted to assert BSY without a REQ/ACK
/// </summary>
/// <summary>Max. time in 100 µs increments that the target is permitted to assert BSY without a REQ/ACK</summary>
public ushort BusInactivityLimit;
/// <summary>
/// Min. time in 100 µs increments to wait after releasing the bus before attempting reselection
/// </summary>
/// <summary>Min. time in 100 µs increments to wait after releasing the bus before attempting reselection</summary>
public ushort DisconnectTimeLimit;
/// <summary>
/// Max. time in 100 µs increments allowed to use the bus before disconnecting, if granted the privilege and not
/// restricted by <see cref="DTDC" />
/// </summary>
public ushort ConnectTimeLimit;
/// <summary>
/// Maximum amount of data before disconnecting in 512 bytes increments
/// </summary>
/// <summary>Maximum amount of data before disconnecting in 512 bytes increments</summary>
public ushort MaxBurstSize;
/// <summary>
/// Data transfer disconnect control
/// </summary>
/// <summary>Data transfer disconnect control</summary>
public byte DTDC;
/// <summary>
/// Target shall not transfer data for a command during the same interconnect tenancy
/// </summary>
/// <summary>Target shall not transfer data for a command during the same interconnect tenancy</summary>
public bool DIMM;
/// <summary>
/// Wether to use fair or unfair arbitration when requesting an interconnect tenancy
/// </summary>
/// <summary>Wether to use fair or unfair arbitration when requesting an interconnect tenancy</summary>
public byte FairArbitration;
/// <summary>
/// Max. ammount of data in 512 bytes increments that may be transferred for a command along with the command
/// </summary>
/// <summary>Max. ammount of data in 512 bytes increments that may be transferred for a command along with the command</summary>
public ushort FirstBurstSize;
/// <summary>
/// Target is allowed to re-order the data transfer
/// </summary>
/// <summary>Target is allowed to re-order the data transfer</summary>
public bool EMDP;
}
public static ModePage_02? DecodeModePage_02(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x02) return null;
if((pageResponse?[0] & 0x3F) != 0x02)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 12) return null;
if(pageResponse.Length < 12)
return null;
ModePage_02 decoded = new ModePage_02();
var decoded = new ModePage_02();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.BufferFullRatio = pageResponse[2];
@@ -128,7 +105,8 @@ namespace DiscImageChef.Decoders.SCSI
decoded.DTDC = (byte)(pageResponse[12] & 0x07);
}
if(pageResponse.Length >= 16) decoded.FirstBurstSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
if(pageResponse.Length >= 16)
decoded.FirstBurstSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
return decoded;
}
@@ -138,55 +116,70 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_02(ModePage_02? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_02 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_02 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Disconnect-Reconnect mode page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.BufferFullRatio > 0)
sb.AppendFormat("\t{0} ratio of buffer that shall be full prior to attempting a reselection",
page.BufferFullRatio).AppendLine();
if(page.BufferEmptyRatio > 0)
sb.AppendFormat("\t{0} ratio of buffer that shall be empty prior to attempting a reselection",
page.BufferEmptyRatio).AppendLine();
if(page.BusInactivityLimit > 0)
sb.AppendFormat("\t{0} µs maximum permitted to assert BSY without a REQ/ACK handshake",
page.BusInactivityLimit * 100).AppendLine();
if(page.DisconnectTimeLimit > 0)
sb.AppendFormat("\t{0} µs maximum permitted wait after releasing the bus before attempting reselection",
page.DisconnectTimeLimit * 100).AppendLine();
if(page.ConnectTimeLimit > 0)
sb
.AppendFormat("\t{0} µs allowed to use the bus before disconnecting, if granted the privilege and not restricted",
sb.
AppendFormat("\t{0} µs allowed to use the bus before disconnecting, if granted the privilege and not restricted",
page.ConnectTimeLimit * 100).AppendLine();
if(page.MaxBurstSize > 0)
sb.AppendFormat("\t{0} bytes maximum can be transferred before disconnecting", page.MaxBurstSize * 512)
.AppendLine();
sb.AppendFormat("\t{0} bytes maximum can be transferred before disconnecting", page.MaxBurstSize * 512).
AppendLine();
if(page.FirstBurstSize > 0)
sb
.AppendFormat("\t{0} bytes maximum can be transferred for a command along with the disconnect command",
sb.
AppendFormat("\t{0} bytes maximum can be transferred for a command along with the disconnect command",
page.FirstBurstSize * 512).AppendLine();
if(page.DIMM)
sb.AppendLine("\tTarget shall not transfer data for a command during the same interconnect tenancy");
if(page.EMDP) sb.AppendLine("\tTarget is allowed to re-order the data transfer");
if(page.EMDP)
sb.AppendLine("\tTarget is allowed to re-order the data transfer");
switch(page.DTDC)
{
case 0:
sb.AppendLine("\tData transfer disconnect control is not used");
break;
case 1:
sb.AppendLine("\tAll data for a command shall be transferred within a single interconnect tenancy");
break;
case 3:
sb.AppendLine("\tAll data and the response for a command shall be transferred within a single interconnect tenancy");
break;
default:
sb.AppendFormat("\tReserved data transfer disconnect control value {0}", page.DTDC).AppendLine();
break;
}

View File

@@ -35,89 +35,62 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x03: Format device page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x03
/// 24 bytes in SCSI-2, SBC-1
/// </summary>
/// <summary>Disconnect-reconnect page Page code 0x03 24 bytes in SCSI-2, SBC-1</summary>
public struct ModePage_03
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors
/// </summary>
/// <summary>Tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors</summary>
public ushort TracksPerZone;
/// <summary>
/// Number of sectors per zone that shall be reserved for defect handling
/// </summary>
/// <summary>Number of sectors per zone that shall be reserved for defect handling</summary>
public ushort AltSectorsPerZone;
/// <summary>
/// Number of tracks per zone that shall be reserved for defect handling
/// </summary>
/// <summary>Number of tracks per zone that shall be reserved for defect handling</summary>
public ushort AltTracksPerZone;
/// <summary>
/// Number of tracks per LUN that shall be reserved for defect handling
/// </summary>
/// <summary>Number of tracks per LUN that shall be reserved for defect handling</summary>
public ushort AltTracksPerLun;
/// <summary>
/// Number of physical sectors per track
/// </summary>
/// <summary>Number of physical sectors per track</summary>
public ushort SectorsPerTrack;
/// <summary>
/// Bytes per physical sector
/// </summary>
/// <summary>Bytes per physical sector</summary>
public ushort BytesPerSector;
/// <summary>
/// Interleave value, target dependent
/// </summary>
/// <summary>Interleave value, target dependent</summary>
public ushort Interleave;
/// <summary>
/// Sectors between last block of one track and first block of the next
/// </summary>
/// <summary>Sectors between last block of one track and first block of the next</summary>
public ushort TrackSkew;
/// <summary>
/// Sectors between last block of a cylinder and first block of the next one
/// </summary>
/// <summary>Sectors between last block of a cylinder and first block of the next one</summary>
public ushort CylinderSkew;
/// <summary>
/// Soft-sectored
/// </summary>
/// <summary>Soft-sectored</summary>
public bool SSEC;
/// <summary>
/// Hard-sectored
/// </summary>
/// <summary>Hard-sectored</summary>
public bool HSEC;
/// <summary>
/// Removable
/// </summary>
/// <summary>Removable</summary>
public bool RMB;
/// <summary>
/// If set, address are allocated progressively in a surface before going to the next.
/// Otherwise, it goes by cylinders
/// If set, address are allocated progressively in a surface before going to the next. Otherwise, it goes by
/// cylinders
/// </summary>
public bool SURF;
}
public static ModePage_03? DecodeModePage_03(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x03) return null;
if((pageResponse?[0] & 0x3F) != 0x03)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 24) return null;
if(pageResponse.Length < 24)
return null;
ModePage_03 decoded = new ModePage_03();
var decoded = new ModePage_03();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.TracksPerZone = (ushort)((pageResponse[2] << 8) + pageResponse[3]);
@@ -142,34 +115,49 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_03(ModePage_03? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_03 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_03 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Format device page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb
.AppendFormat("\t{0} tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors",
sb.
AppendFormat("\t{0} tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors",
page.TracksPerZone).AppendLine();
sb.AppendFormat("\t{0} sectors per zone that shall be reserved for defect handling", page.AltSectorsPerZone)
.AppendLine();
sb.AppendFormat("\t{0} tracks per zone that shall be reserved for defect handling", page.AltTracksPerZone)
.AppendLine();
sb.AppendFormat("\t{0} tracks per LUN that shall be reserved for defect handling", page.AltTracksPerLun)
.AppendLine();
sb.AppendFormat("\t{0} sectors per zone that shall be reserved for defect handling",
page.AltSectorsPerZone).AppendLine();
sb.AppendFormat("\t{0} tracks per zone that shall be reserved for defect handling", page.AltTracksPerZone).
AppendLine();
sb.AppendFormat("\t{0} tracks per LUN that shall be reserved for defect handling", page.AltTracksPerLun).
AppendLine();
sb.AppendFormat("\t{0} physical sectors per track", page.SectorsPerTrack).AppendLine();
sb.AppendFormat("\t{0} Bytes per physical sector", page.BytesPerSector).AppendLine();
sb.AppendFormat("\tTarget-dependent interleave value is {0}", page.Interleave).AppendLine();
sb.AppendFormat("\t{0} sectors between last block of one track and first block of the next", page.TrackSkew)
.AppendLine();
sb.AppendFormat("\t{0} sectors between last block of one track and first block of the next",
page.TrackSkew).AppendLine();
sb.AppendFormat("\t{0} sectors between last block of a cylinder and first block of the next one",
page.CylinderSkew).AppendLine();
if(page.SSEC) sb.AppendLine("\tDrive supports soft-sectoring format");
if(page.HSEC) sb.AppendLine("\tDrive supports hard-sectoring format");
if(page.RMB) sb.AppendLine("\tDrive media is removable");
if(page.SSEC)
sb.AppendLine("\tDrive supports soft-sectoring format");
if(page.HSEC)
sb.AppendLine("\tDrive supports hard-sectoring format");
if(page.RMB)
sb.AppendLine("\tDrive media is removable");
sb.AppendLine(page.SURF
? "\tSector addressing is progressively incremented in one surface before going to the next"
: "\tSector addressing is progressively incremented in one cylinder before going to the next");

View File

@@ -35,81 +35,63 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x04: Rigid disk drive geometry page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x04
/// 24 bytes in SCSI-2, SBC-1
/// </summary>
/// <summary>Disconnect-reconnect page Page code 0x04 24 bytes in SCSI-2, SBC-1</summary>
public struct ModePage_04
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Cylinders used for data storage
/// </summary>
/// <summary>Cylinders used for data storage</summary>
public uint Cylinders;
/// <summary>
/// Heads for reading and/or writing
/// </summary>
/// <summary>Heads for reading and/or writing</summary>
public byte Heads;
/// <summary>
/// Cylinder where write precompensation starts
/// </summary>
/// <summary>Cylinder where write precompensation starts</summary>
public uint WritePrecompCylinder;
/// <summary>
/// Cylinder where write current reduction starts
/// </summary>
/// <summary>Cylinder where write current reduction starts</summary>
public uint WriteReduceCylinder;
/// <summary>
/// Step rate in 100 ns units
/// </summary>
/// <summary>Step rate in 100 ns units</summary>
public ushort DriveStepRate;
/// <summary>
/// Cylinder where the heads park
/// </summary>
/// <summary>Cylinder where the heads park</summary>
public int LandingCylinder;
/// <summary>
/// Rotational position locking
/// </summary>
/// <summary>Rotational position locking</summary>
public byte RPL;
/// <summary>
/// Rotational skew to apply when synchronized
/// </summary>
/// <summary>Rotational skew to apply when synchronized</summary>
public byte RotationalOffset;
/// <summary>
/// Medium speed in rpm
/// </summary>
/// <summary>Medium speed in rpm</summary>
public ushort MediumRotationRate;
}
public static ModePage_04? DecodeModePage_04(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x04) return null;
if((pageResponse?[0] & 0x3F) != 0x04)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 20) return null;
if(pageResponse.Length < 20)
return null;
ModePage_04 decoded = new ModePage_04();
var decoded = new ModePage_04();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Cylinders = (uint)((pageResponse[2] << 16) + (pageResponse[3] << 8) + pageResponse[4]);
decoded.Heads = pageResponse[5];
decoded.WritePrecompCylinder = (uint)((pageResponse[6] << 16) + (pageResponse[7] << 8) + pageResponse[8]);
decoded.WriteReduceCylinder =
(uint)((pageResponse[9] << 16) + (pageResponse[10] << 8) + pageResponse[11]);
decoded.DriveStepRate =
(ushort)((pageResponse[12] << 8) + pageResponse[13]);
decoded.LandingCylinder = (pageResponse[14] << 16) + (pageResponse[15] << 8) + pageResponse[16];
decoded.RPL = (byte)(pageResponse[17] & 0x03);
decoded.RotationalOffset = pageResponse[18];
@@ -125,23 +107,28 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_04(ModePage_04? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_04 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_04 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Rigid disk drive geometry page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\t{0} heads", page.Heads).AppendLine();
sb.AppendFormat("\t{0} cylinders", page.Cylinders).AppendLine();
if(page.WritePrecompCylinder < page.Cylinders)
sb.AppendFormat("\tWrite pre-compensation starts at cylinder {0}", page.WritePrecompCylinder)
.AppendLine();
sb.AppendFormat("\tWrite pre-compensation starts at cylinder {0}", page.WritePrecompCylinder).
AppendLine();
if(page.WriteReduceCylinder < page.Cylinders)
sb.AppendFormat("\tWrite current reduction starts at cylinder {0}", page.WriteReduceCylinder)
.AppendLine();
sb.AppendFormat("\tWrite current reduction starts at cylinder {0}", page.WriteReduceCylinder).
AppendLine();
if(page.DriveStepRate > 0)
sb.AppendFormat("\tDrive steps in {0} ns", (uint)page.DriveStepRate * 100).AppendLine();
@@ -154,15 +141,19 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tSpindle synchronization is disable or unsupported");
break;
case 1:
sb.AppendLine("\tTarget operates as a synchronized-spindle slave");
break;
case 2:
sb.AppendLine("\tTarget operates as a synchronized-spindle master");
break;
case 3:
sb.AppendLine("\tTarget operates as a synchronized-spindle master control");
break;
}

View File

@@ -35,137 +35,87 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x05: Flexible disk page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x05
/// 32 bytes in SCSI-2, SBC-1
/// </summary>
/// <summary>Disconnect-reconnect page Page code 0x05 32 bytes in SCSI-2, SBC-1</summary>
public struct ModePage_05
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Data rate of peripheral device on kbit/s
/// </summary>
/// <summary>Data rate of peripheral device on kbit/s</summary>
public ushort TransferRate;
/// <summary>
/// Heads for reading and/or writing
/// </summary>
/// <summary>Heads for reading and/or writing</summary>
public byte Heads;
/// <summary>
/// Sectors per revolution per head
/// </summary>
/// <summary>Sectors per revolution per head</summary>
public byte SectorsPerTrack;
/// <summary>
/// Bytes of data per sector
/// </summary>
/// <summary>Bytes of data per sector</summary>
public ushort BytesPerSector;
/// <summary>
/// Cylinders used for data storage
/// </summary>
/// <summary>Cylinders used for data storage</summary>
public ushort Cylinders;
/// <summary>
/// Cylinder where write precompensation starts
/// </summary>
/// <summary>Cylinder where write precompensation starts</summary>
public ushort WritePrecompCylinder;
/// <summary>
/// Cylinder where write current reduction starts
/// </summary>
/// <summary>Cylinder where write current reduction starts</summary>
public ushort WriteReduceCylinder;
/// <summary>
/// Step rate in 100 μs units
/// </summary>
/// <summary>Step rate in 100 μs units</summary>
public ushort DriveStepRate;
/// <summary>
/// Width of step pulse in μs
/// </summary>
/// <summary>Width of step pulse in μs</summary>
public byte DriveStepPulse;
/// <summary>
/// Head settle time in 100 μs units
/// </summary>
/// <summary>Head settle time in 100 μs units</summary>
public ushort HeadSettleDelay;
/// <summary>
/// If <see cref="TRDY" /> is <c>true</c>, specified in 1/10s of a
/// second the time waiting for read status before aborting medium
/// access. Otherwise, indicates time to way before medimum access
/// after motor on signal is asserted.
/// If <see cref="TRDY" /> is <c>true</c>, specified in 1/10s of a second the time waiting for read status before
/// aborting medium access. Otherwise, indicates time to way before medimum access after motor on signal is asserted.
/// </summary>
public byte MotorOnDelay;
/// <summary>
/// Time in 1/10s of a second to wait before releasing the motor on
/// signal after an idle condition. 0xFF means to never release the
/// signal
/// Time in 1/10s of a second to wait before releasing the motor on signal after an idle condition. 0xFF means to
/// never release the signal
/// </summary>
public byte MotorOffDelay;
/// <summary>
/// Specifies if a signal indicates that the medium is ready to be accessed
/// </summary>
/// <summary>Specifies if a signal indicates that the medium is ready to be accessed</summary>
public bool TRDY;
/// <summary>
/// If <c>true</c> sectors start with one. Otherwise, they start with zero.
/// </summary>
/// <summary>If <c>true</c> sectors start with one. Otherwise, they start with zero.</summary>
public bool SSN;
/// <summary>
/// If <c>true</c> specifies that motor on shall remain released.
/// </summary>
/// <summary>If <c>true</c> specifies that motor on shall remain released.</summary>
public bool MO;
/// <summary>
/// Number of additional step pulses per cylinder.
/// </summary>
/// <summary>Number of additional step pulses per cylinder.</summary>
public byte SPC;
/// <summary>
/// Write compensation value
/// </summary>
/// <summary>Write compensation value</summary>
public byte WriteCompensation;
/// <summary>
/// Head loading time in ms.
/// </summary>
/// <summary>Head loading time in ms.</summary>
public byte HeadLoadDelay;
/// <summary>
/// Head unloading time in ms.
/// </summary>
/// <summary>Head unloading time in ms.</summary>
public byte HeadUnloadDelay;
/// <summary>
/// Description of shugart's bus pin 34 usage
/// </summary>
/// <summary>Description of shugart's bus pin 34 usage</summary>
public byte Pin34;
/// <summary>
/// Description of shugart's bus pin 2 usage
/// </summary>
/// <summary>Description of shugart's bus pin 2 usage</summary>
public byte Pin2;
/// <summary>
/// Description of shugart's bus pin 4 usage
/// </summary>
/// <summary>Description of shugart's bus pin 4 usage</summary>
public byte Pin4;
/// <summary>
/// Description of shugart's bus pin 1 usage
/// </summary>
/// <summary>Description of shugart's bus pin 1 usage</summary>
public byte Pin1;
/// <summary>
/// Medium speed in rpm
/// </summary>
/// <summary>Medium speed in rpm</summary>
public ushort MediumRotationRate;
}
public static ModePage_05? DecodeModePage_05(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x05) return null;
if((pageResponse?[0] & 0x3F) != 0x05)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 32) return null;
if(pageResponse.Length < 32)
return null;
ModePage_05 decoded = new ModePage_05();
var decoded = new ModePage_05();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.TransferRate = (ushort)((pageResponse[2] << 8) + pageResponse[3]);
@@ -201,57 +151,73 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_05(ModePage_05? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_05 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_05 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Flexible disk page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\tTransfer rate: {0} kbit/s", page.TransferRate).AppendLine();
sb.AppendFormat("\t{0} heads", page.Heads).AppendLine();
sb.AppendFormat("\t{0} cylinders", page.Cylinders).AppendLine();
sb.AppendFormat("\t{0} sectors per track", page.SectorsPerTrack).AppendLine();
sb.AppendFormat("\t{0} bytes per sector", page.BytesPerSector).AppendLine();
if(page.WritePrecompCylinder < page.Cylinders)
sb.AppendFormat("\tWrite pre-compensation starts at cylinder {0}", page.WritePrecompCylinder)
.AppendLine();
sb.AppendFormat("\tWrite pre-compensation starts at cylinder {0}", page.WritePrecompCylinder).
AppendLine();
if(page.WriteReduceCylinder < page.Cylinders)
sb.AppendFormat("\tWrite current reduction starts at cylinder {0}", page.WriteReduceCylinder)
.AppendLine();
sb.AppendFormat("\tWrite current reduction starts at cylinder {0}", page.WriteReduceCylinder).
AppendLine();
if(page.DriveStepRate > 0)
sb.AppendFormat("\tDrive steps in {0} μs", (uint)page.DriveStepRate * 100).AppendLine();
if(page.DriveStepPulse > 0)
sb.AppendFormat("\tEach step pulse is {0} ms", page.DriveStepPulse).AppendLine();
if(page.HeadSettleDelay > 0)
sb.AppendFormat("\tHeads settles in {0} μs", (uint)page.HeadSettleDelay * 100).AppendLine();
if(!page.TRDY)
sb
.AppendFormat("\tTarget shall wait {0} seconds before attempting to access the medium after motor on is asserted",
sb.
AppendFormat("\tTarget shall wait {0} seconds before attempting to access the medium after motor on is asserted",
(double)page.MotorOnDelay * 10).AppendLine();
else
sb
.AppendFormat("\tTarget shall wait {0} seconds after drive is ready before aborting medium access attemps",
sb.
AppendFormat("\tTarget shall wait {0} seconds after drive is ready before aborting medium access attemps",
(double)page.MotorOnDelay * 10).AppendLine();
if(page.MotorOffDelay != 0xFF)
sb
.AppendFormat("\tTarget shall wait {0} seconds before releasing the motor on signal after becoming idle",
sb.
AppendFormat("\tTarget shall wait {0} seconds before releasing the motor on signal after becoming idle",
(double)page.MotorOffDelay * 10).AppendLine();
else sb.AppendLine("\tTarget shall never release the motor on signal");
else
sb.AppendLine("\tTarget shall never release the motor on signal");
if(page.TRDY) sb.AppendLine("\tThere is a drive ready signal");
if(page.SSN) sb.AppendLine("\tSectors start at 1");
if(page.MO) sb.AppendLine("\tThe motor on signal shall remain released");
if(page.TRDY)
sb.AppendLine("\tThere is a drive ready signal");
if(page.SSN)
sb.AppendLine("\tSectors start at 1");
if(page.MO)
sb.AppendLine("\tThe motor on signal shall remain released");
sb.AppendFormat("\tDrive needs to do {0} step pulses per cylinder", page.SPC + 1).AppendLine();
if(page.WriteCompensation > 0)
sb.AppendFormat("\tWrite pre-compensation is {0}", page.WriteCompensation).AppendLine();
if(page.HeadLoadDelay > 0) sb.AppendFormat("\tHead takes {0} ms to load", page.HeadLoadDelay).AppendLine();
if(page.HeadLoadDelay > 0)
sb.AppendFormat("\tHead takes {0} ms to load", page.HeadLoadDelay).AppendLine();
if(page.HeadUnloadDelay > 0)
sb.AppendFormat("\tHead takes {0} ms to unload", page.HeadUnloadDelay).AppendLine();
@@ -262,18 +228,22 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tPin 34 is unconnected");
break;
case 1:
sb.Append("\tPin 34 indicates drive is ready when active ");
sb.Append((page.Pin34 & 0x08) == 0x08 ? "high" : "low");
break;
case 2:
sb.Append("\tPin 34 indicates disk has changed when active ");
sb.Append((page.Pin34 & 0x08) == 0x08 ? "high" : "low");
break;
default:
sb.AppendFormat("\tPin 34 indicates unknown function {0} when active ", page.Pin34 & 0x07);
sb.Append((page.Pin34 & 0x08) == 0x08 ? "high" : "low");
break;
}
@@ -281,22 +251,27 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tPin 4 is unconnected");
break;
case 1:
sb.Append("\tPin 4 indicates drive is in use when active ");
sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low");
break;
case 2:
sb.Append("\tPin 4 indicates eject when active ");
sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low");
break;
case 3:
sb.Append("\tPin 4 indicates head load when active ");
sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low");
break;
default:
sb.AppendFormat("\tPin 4 indicates unknown function {0} when active ", page.Pin4 & 0x07);
sb.Append((page.Pin4 & 0x08) == 0x08 ? "high" : "low");
break;
}
@@ -304,10 +279,12 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tPin 2 is unconnected");
break;
default:
sb.AppendFormat("\tPin 2 indicates unknown function {0} when active ", page.Pin2 & 0x07);
sb.Append((page.Pin2 & 0x08) == 0x08 ? "high" : "low");
break;
}
@@ -315,14 +292,17 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tPin 1 is unconnected");
break;
case 1:
sb.Append("\tPin 1 indicates disk change reset when active ");
sb.Append((page.Pin1 & 0x08) == 0x08 ? "high" : "low");
break;
default:
sb.AppendFormat("\tPin 1 indicates unknown function {0} when active ", page.Pin1 & 0x07);
sb.Append((page.Pin1 & 0x08) == 0x08 ? "high" : "low");
break;
}

View File

@@ -35,40 +35,35 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x06: Optical memory page
/// <summary>
/// Optical memory page
/// Page code 0x06
/// 4 bytes in SCSI-2
/// </summary>
/// <summary>Optical memory page Page code 0x06 4 bytes in SCSI-2</summary>
public struct ModePage_06
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Report updated block read
/// </summary>
/// <summary>Report updated block read</summary>
public bool RUBR;
}
public static ModePage_06? DecodeModePage_06(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x06) return null;
if((pageResponse?[0] & 0x3F) != 0x06)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 4) return null;
if(pageResponse.Length < 4)
return null;
ModePage_06 decoded = new ModePage_06();
var decoded = new ModePage_06();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.RUBR |= (pageResponse[2] & 0x01) == 0x01;
@@ -81,15 +76,19 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_06(ModePage_06? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_06 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_06 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI optical memory:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.RUBR) sb.AppendLine("\tOn reading an updated block drive will return RECOVERED ERROR");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.RUBR)
sb.AppendLine("\tOn reading an updated block drive will return RECOVERED ERROR");
return sb.ToString();
}

View File

@@ -35,65 +35,47 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static partial class Modes
{
#region Mode Page 0x07: Verify error recovery page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x07
/// 12 bytes in SCSI-2, SBC-1, SBC-2
/// </summary>
/// <summary>Disconnect-reconnect page Page code 0x07 12 bytes in SCSI-2, SBC-1, SBC-2</summary>
public struct ModePage_07
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Enable early recovery
/// </summary>
/// <summary>Enable early recovery</summary>
public bool EER;
/// <summary>
/// Post error reporting
/// </summary>
/// <summary>Post error reporting</summary>
public bool PER;
/// <summary>
/// Disable transfer on error
/// </summary>
/// <summary>Disable transfer on error</summary>
public bool DTE;
/// <summary>
/// Disable correction
/// </summary>
/// <summary>Disable correction</summary>
public bool DCR;
/// <summary>
/// How many times to retry a verify operation
/// </summary>
/// <summary>How many times to retry a verify operation</summary>
public byte VerifyRetryCount;
/// <summary>
/// How many bits of largest data burst error is maximum to apply error correction on it
/// </summary>
/// <summary>How many bits of largest data burst error is maximum to apply error correction on it</summary>
public byte CorrectionSpan;
/// <summary>
/// Maximum time in ms to use in data error recovery procedures
/// </summary>
/// <summary>Maximum time in ms to use in data error recovery procedures</summary>
public ushort RecoveryTimeLimit;
}
public static ModePage_07? DecodeModePage_07(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x07) return null;
if((pageResponse?[0] & 0x3F) != 0x07)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 12) return null;
if(pageResponse.Length < 12)
return null;
ModePage_07 decoded = new ModePage_07();
var decoded = new ModePage_07();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.EER |= (pageResponse[2] & 0x08) == 0x08;
@@ -113,24 +95,35 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_07(ModePage_07? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_07 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_07 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Verify error recovery page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.EER)
sb.AppendLine("\tDrive will use the most expedient form of error recovery first");
if(page.PER)
sb.AppendLine("\tDrive shall report recovered errors");
if(page.DTE)
sb.AppendLine("\tTransfer will be terminated upon error detection");
if(page.DCR)
sb.AppendLine("\tError correction is disabled");
if(page.EER) sb.AppendLine("\tDrive will use the most expedient form of error recovery first");
if(page.PER) sb.AppendLine("\tDrive shall report recovered errors");
if(page.DTE) sb.AppendLine("\tTransfer will be terminated upon error detection");
if(page.DCR) sb.AppendLine("\tError correction is disabled");
if(page.VerifyRetryCount > 0)
sb.AppendFormat("\tDrive will repeat verify operations {0} times", page.VerifyRetryCount).AppendLine();
if(page.RecoveryTimeLimit > 0)
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit)
.AppendLine();
sb.AppendFormat("\tDrive will employ a maximum of {0} ms to recover data", page.RecoveryTimeLimit).
AppendLine();
return sb.ToString();
}

View File

@@ -35,44 +35,37 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x07: Verify error recovery page for MultiMedia Devices
/// <summary>
/// Verify error recovery page for MultiMedia Devices
/// Page code 0x07
/// 8 bytes in SCSI-2, MMC-1
/// </summary>
/// <summary>Verify error recovery page for MultiMedia Devices Page code 0x07 8 bytes in SCSI-2, MMC-1</summary>
public struct ModePage_07_MMC
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Error recovery parameter
/// </summary>
/// <summary>Error recovery parameter</summary>
public byte Parameter;
/// <summary>
/// How many times to retry a verify operation
/// </summary>
/// <summary>How many times to retry a verify operation</summary>
public byte VerifyRetryCount;
}
public static ModePage_07_MMC? DecodeModePage_07_MMC(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x07) return null;
if((pageResponse?[0] & 0x3F) != 0x07)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_07_MMC decoded = new ModePage_07_MMC();
var decoded = new ModePage_07_MMC();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Parameter = pageResponse[2];
@@ -86,14 +79,17 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_07_MMC(ModePage_07_MMC? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_07_MMC page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Verify error recovery page for MultiMedia Devices:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.VerifyRetryCount > 0)
sb.AppendFormat("\tDrive will repeat verify operations {0} times", page.VerifyRetryCount).AppendLine();
@@ -107,8 +103,10 @@ namespace DiscImageChef.Decoders.SCSI
string UnrecCIRCAbort = "\tUnrecovered CIRC errors will return CHECK CONDITION.";
string UnrecECCNotAbort = "\tUnrecovered ECC errors will not abort the transfer.";
string UnrecCIRCNotAbort = "\tUnrecovered CIRC errors will not abort the transfer.";
string UnrecECCAbortData =
"\tUnrecovered ECC errors will return CHECK CONDITION and the uncorrected data.";
string UnrecCIRCAbortData =
"\tUnrecovered CIRC errors will return CHECK CONDITION and the uncorrected data.";
@@ -116,51 +114,67 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0x00:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbort);
break;
case 0x01:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbort);
break;
case 0x04:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbort);
break;
case 0x05:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbort);
break;
case 0x06:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbort);
break;
case 0x07:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbort);
break;
case 0x10:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCNotAbort);
break;
case 0x11:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCNotAbort);
break;
case 0x14:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCNotAbort);
break;
case 0x15:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCNotAbort);
break;
case 0x20:
sb.AppendLine(AllUsed + RecoveredNotReported + UnrecECCAbortData);
break;
case 0x21:
sb.AppendLine(CIRCRetriesUsed + RecoveredNotReported + UnrecCIRCAbortData);
break;
case 0x24:
sb.AppendLine(AllUsed + RecoveredReported + UnrecECCAbortData);
break;
case 0x25:
sb.AppendLine(CIRCRetriesUsed + RecoveredReported + UnrecCIRCAbortData);
break;
case 0x26:
sb.AppendLine(AllUsed + RecoveredAbort + UnrecECCAbortData);
break;
case 0x27:
sb.AppendLine(RetriesUsed + RecoveredAbort + UnrecCIRCAbortData);
break;
case 0x30: goto case 0x10;
case 0x31: goto case 0x11;
@@ -168,6 +182,7 @@ namespace DiscImageChef.Decoders.SCSI
case 0x35: goto case 0x15;
default:
sb.AppendFormat("Unknown recovery parameter 0x{0:X2}", page.Parameter).AppendLine();
break;
}

View File

@@ -35,104 +35,56 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x08: Caching page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x08
/// 12 bytes in SCSI-2
/// 20 bytes in SBC-1, SBC-2, SBC-3
/// </summary>
/// <summary>Disconnect-reconnect page Page code 0x08 12 bytes in SCSI-2 20 bytes in SBC-1, SBC-2, SBC-3</summary>
public struct ModePage_08
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// <c>true</c> if write cache is enabled
/// </summary>
/// <summary><c>true</c> if write cache is enabled</summary>
public bool WCE;
/// <summary>
/// Multiplication factor
/// </summary>
/// <summary>Multiplication factor</summary>
public bool MF;
/// <summary>
/// <c>true</c> if read cache is enabled
/// </summary>
/// <summary><c>true</c> if read cache is enabled</summary>
public bool RCD;
/// <summary>
/// Advices on reading-cache retention priority
/// </summary>
/// <summary>Advices on reading-cache retention priority</summary>
public byte DemandReadRetentionPrio;
/// <summary>
/// Advices on writing-cache retention priority
/// </summary>
/// <summary>Advices on writing-cache retention priority</summary>
public byte WriteRetentionPriority;
/// <summary>
/// If requested read blocks are more than this, no pre-fetch is done
/// </summary>
/// <summary>If requested read blocks are more than this, no pre-fetch is done</summary>
public ushort DisablePreFetch;
/// <summary>
/// Minimum pre-fetch
/// </summary>
/// <summary>Minimum pre-fetch</summary>
public ushort MinimumPreFetch;
/// <summary>
/// Maximum pre-fetch
/// </summary>
/// <summary>Maximum pre-fetch</summary>
public ushort MaximumPreFetch;
/// <summary>
/// Upper limit on maximum pre-fetch value
/// </summary>
/// <summary>Upper limit on maximum pre-fetch value</summary>
public ushort MaximumPreFetchCeiling;
/// <summary>
/// Manual cache controlling
/// </summary>
/// <summary>Manual cache controlling</summary>
public bool IC;
/// <summary>
/// Abort pre-fetch
/// </summary>
/// <summary>Abort pre-fetch</summary>
public bool ABPF;
/// <summary>
/// Caching analysis permitted
/// </summary>
/// <summary>Caching analysis permitted</summary>
public bool CAP;
/// <summary>
/// Pre-fetch over discontinuities
/// </summary>
/// <summary>Pre-fetch over discontinuities</summary>
public bool Disc;
/// <summary>
/// <see cref="CacheSegmentSize" /> is to be used to control caching segmentation
/// </summary>
/// <summary><see cref="CacheSegmentSize" /> is to be used to control caching segmentation</summary>
public bool Size;
/// <summary>
/// Force sequential write
/// </summary>
/// <summary>Force sequential write</summary>
public bool FSW;
/// <summary>
/// Logical block cache segment size
/// </summary>
/// <summary>Logical block cache segment size</summary>
public bool LBCSS;
/// <summary>
/// Disable read-ahead
/// </summary>
/// <summary>Disable read-ahead</summary>
public bool DRA;
/// <summary>
/// How many segments should the cache be divided upon
/// </summary>
/// <summary>How many segments should the cache be divided upon</summary>
public byte CacheSegments;
/// <summary>
/// How many bytes should the cache be divided upon
/// </summary>
/// <summary>How many bytes should the cache be divided upon</summary>
public ushort CacheSegmentSize;
/// <summary>
/// How many bytes should be used as a buffer when all other cached data cannot be evicted
/// </summary>
/// <summary>How many bytes should be used as a buffer when all other cached data cannot be evicted</summary>
public uint NonCacheSegmentSize;
public bool NV_DIS;
@@ -140,15 +92,19 @@ namespace DiscImageChef.Decoders.SCSI
public static ModePage_08? DecodeModePage_08(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x08) return null;
if((pageResponse?[0] & 0x3F) != 0x08)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 12) return null;
if(pageResponse.Length < 12)
return null;
ModePage_08 decoded = new ModePage_08();
var decoded = new ModePage_08();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.WCE |= (pageResponse[2] & 0x04) == 0x04;
@@ -162,7 +118,8 @@ namespace DiscImageChef.Decoders.SCSI
decoded.MaximumPreFetch = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.MaximumPreFetchCeiling = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
if(pageResponse.Length < 20) return decoded;
if(pageResponse.Length < 20)
return decoded;
decoded.IC |= (pageResponse[2] & 0x80) == 0x80;
decoded.ABPF |= (pageResponse[2] & 0x40) == 0x40;
@@ -188,31 +145,41 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_08(ModePage_08? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_08 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_08 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Caching mode page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.RCD) sb.AppendLine("\tRead-cache is enabled");
if(page.WCE) sb.AppendLine("\tWrite-cache is enabled");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.RCD)
sb.AppendLine("\tRead-cache is enabled");
if(page.WCE)
sb.AppendLine("\tWrite-cache is enabled");
switch(page.DemandReadRetentionPrio)
{
case 0:
sb.AppendLine("\tDrive does not distinguish between cached read data");
break;
case 1:
sb.AppendLine("\tData put by READ commands should be evicted from cache sooner than data put in read cache by other means");
break;
case 0xF:
sb.AppendLine("\tData put by READ commands should not be evicted if there is data cached by other means that can be evicted");
break;
default:
sb.AppendFormat("\tUnknown demand read retention priority value {0}", page.DemandReadRetentionPrio)
.AppendLine();
sb.AppendFormat("\tUnknown demand read retention priority value {0}", page.DemandReadRetentionPrio).
AppendLine();
break;
}
@@ -220,61 +187,76 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tDrive does not distinguish between cached write data");
break;
case 1:
sb.AppendLine("\tData put by WRITE commands should be evicted from cache sooner than data put in write cache by other means");
break;
case 0xF:
sb.AppendLine("\tData put by WRITE commands should not be evicted if there is data cached by other means that can be evicted");
break;
default:
sb.AppendFormat("\tUnknown demand write retention priority value {0}", page.DemandReadRetentionPrio)
.AppendLine();
sb.AppendFormat("\tUnknown demand write retention priority value {0}",
page.DemandReadRetentionPrio).AppendLine();
break;
}
if(page.DRA) sb.AppendLine("\tRead-ahead is disabled");
if(page.DRA)
sb.AppendLine("\tRead-ahead is disabled");
else
{
if(page.MF) sb.AppendLine("\tPre-fetch values indicate a block multiplier");
if(page.MF)
sb.AppendLine("\tPre-fetch values indicate a block multiplier");
if(page.DisablePreFetch == 0) sb.AppendLine("\tNo pre-fetch will be done");
if(page.DisablePreFetch == 0)
sb.AppendLine("\tNo pre-fetch will be done");
else
{
sb.AppendFormat("\tPre-fetch will be done for READ commands of {0} blocks or less",
page.DisablePreFetch).AppendLine();
if(page.MinimumPreFetch > 0)
sb.AppendFormat("At least {0} blocks will be always pre-fetched", page.MinimumPreFetch)
.AppendLine();
sb.AppendFormat("At least {0} blocks will be always pre-fetched", page.MinimumPreFetch).
AppendLine();
if(page.MaximumPreFetch > 0)
sb.AppendFormat("\tA maximum of {0} blocks will be pre-fetched", page.MaximumPreFetch)
.AppendLine();
sb.AppendFormat("\tA maximum of {0} blocks will be pre-fetched", page.MaximumPreFetch).
AppendLine();
if(page.MaximumPreFetchCeiling > 0)
sb
.AppendFormat("\tA maximum of {0} blocks will be pre-fetched even if it is commanded to pre-fetch more",
sb.
AppendFormat("\tA maximum of {0} blocks will be pre-fetched even if it is commanded to pre-fetch more",
page.MaximumPreFetchCeiling).AppendLine();
if(page.IC)
sb.AppendLine("\tDevice should use number of cache segments or cache segment size for caching");
if(page.ABPF) sb.AppendLine("\tPre-fetch should be aborted upong receiving a new command");
if(page.CAP) sb.AppendLine("\tCaching analysis is permitted");
if(page.ABPF)
sb.AppendLine("\tPre-fetch should be aborted upong receiving a new command");
if(page.CAP)
sb.AppendLine("\tCaching analysis is permitted");
if(page.Disc)
sb.AppendLine("\tPre-fetch can continue across discontinuities (such as cylinders or tracks)");
}
}
if(page.FSW) sb.AppendLine("\tDrive should not reorder the sequence of write commands to be faster");
if(page.FSW)
sb.AppendLine("\tDrive should not reorder the sequence of write commands to be faster");
if(page.Size)
{
if(page.CacheSegmentSize > 0)
if(page.LBCSS)
sb.AppendFormat("\tDrive cache segments should be {0} blocks long", page.CacheSegmentSize)
.AppendLine();
sb.AppendFormat("\tDrive cache segments should be {0} blocks long", page.CacheSegmentSize).
AppendLine();
else
sb.AppendFormat("\tDrive cache segments should be {0} bytes long", page.CacheSegmentSize)
.AppendLine();
sb.AppendFormat("\tDrive cache segments should be {0} bytes long", page.CacheSegmentSize).
AppendLine();
}
else
{
@@ -283,11 +265,12 @@ namespace DiscImageChef.Decoders.SCSI
}
if(page.NonCacheSegmentSize > 0)
sb
.AppendFormat("\tDrive shall allocate {0} bytes to buffer even when all cached data cannot be evicted",
sb.
AppendFormat("\tDrive shall allocate {0} bytes to buffer even when all cached data cannot be evicted",
page.NonCacheSegmentSize).AppendLine();
if(page.NV_DIS) sb.AppendLine("\tNon-Volatile cache is disabled");
if(page.NV_DIS)
sb.AppendLine("\tNon-Volatile cache is disabled");
return sb.ToString();
}

View File

@@ -35,147 +35,95 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x0A: Control mode page
/// <summary>
/// Control mode page
/// Page code 0x0A
/// 8 bytes in SCSI-2
/// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5
/// </summary>
/// <summary>Control mode page Page code 0x0A 8 bytes in SCSI-2 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5</summary>
public struct ModePage_0A
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// If set, target shall report log exception conditions
/// </summary>
/// <summary>If set, target shall report log exception conditions</summary>
public bool RLEC;
/// <summary>
/// Queue algorithm modifier
/// </summary>
/// <summary>Queue algorithm modifier</summary>
public byte QueueAlgorithm;
/// <summary>
/// If set all remaining suspended I/O processes shall be aborted after the contingent allegiance condition or extended
/// contingent allegiance condition
/// If set all remaining suspended I/O processes shall be aborted after the contingent allegiance condition or
/// extended contingent allegiance condition
/// </summary>
public byte QErr;
/// <summary>
/// Tagged queuing is disabled
/// </summary>
/// <summary>Tagged queuing is disabled</summary>
public bool DQue;
/// <summary>
/// Extended Contingent Allegiance is enabled
/// </summary>
/// <summary>Extended Contingent Allegiance is enabled</summary>
public bool EECA;
/// <summary>
/// Target may issue an asynchronous event notification upon completing its initialization
/// </summary>
/// <summary>Target may issue an asynchronous event notification upon completing its initialization</summary>
public bool RAENP;
/// <summary>
/// Target may issue an asynchronous event notification instead of a unit attention condition
/// </summary>
/// <summary>Target may issue an asynchronous event notification instead of a unit attention condition</summary>
public bool UAAENP;
/// <summary>
/// Target may issue an asynchronous event notification instead of a deferred error
/// </summary>
/// <summary>Target may issue an asynchronous event notification instead of a deferred error</summary>
public bool EAENP;
/// <summary>
/// Minimum time in ms after initialization before attempting asynchronous event notifications
/// </summary>
/// <summary>Minimum time in ms after initialization before attempting asynchronous event notifications</summary>
public ushort ReadyAENHoldOffPeriod;
/// <summary>
/// Global logging target save disabled
/// </summary>
/// <summary>Global logging target save disabled</summary>
public bool GLTSD;
/// <summary>
/// CHECK CONDITION should be reported rather than a long busy condition
/// </summary>
/// <summary>CHECK CONDITION should be reported rather than a long busy condition</summary>
public bool RAC;
/// <summary>
/// Software write protect is active
/// </summary>
/// <summary>Software write protect is active</summary>
public bool SWP;
/// <summary>
/// Maximum time in 100 ms units allowed to remain busy. 0xFFFF == unlimited.
/// </summary>
/// <summary>Maximum time in 100 ms units allowed to remain busy. 0xFFFF == unlimited.</summary>
public ushort BusyTimeoutPeriod;
/// <summary>
/// Task set type
/// </summary>
/// <summary>Task set type</summary>
public byte TST;
/// <summary>
/// Tasks aborted by other initiator's actions should be terminated with TASK ABORTED
/// </summary>
/// <summary>Tasks aborted by other initiator's actions should be terminated with TASK ABORTED</summary>
public bool TAS;
/// <summary>
/// Action to be taken when a medium is inserted
/// </summary>
/// <summary>Action to be taken when a medium is inserted</summary>
public byte AutoloadMode;
/// <summary>
/// Time in seconds to complete an extended self-test
/// </summary>
/// <summary>Time in seconds to complete an extended self-test</summary>
public byte ExtendedSelfTestCompletionTime;
/// <summary>
/// All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate
/// </summary>
/// <summary>All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate</summary>
public bool TMF_ONLY;
/// <summary>
/// Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK
/// CONDITION
/// </summary>
public bool D_SENSE;
/// <summary>
/// Unit attention interlocks control
/// </summary>
/// <summary>Unit attention interlocks control</summary>
public byte UA_INTLCK_CTRL;
/// <summary>
/// LOGICAL BLOCK APPLICATION TAG should not be modified
/// </summary>
/// <summary>LOGICAL BLOCK APPLICATION TAG should not be modified</summary>
public bool ATO;
/// <summary>
/// Protector information checking is disabled
/// </summary>
/// <summary>Protector information checking is disabled</summary>
public bool DPICZ;
/// <summary>
/// No unit attention on release
/// </summary>
/// <summary>No unit attention on release</summary>
public bool NUAR;
/// <summary>
/// Application Tag mode page is enabled
/// </summary>
/// <summary>Application Tag mode page is enabled</summary>
public bool ATMPE;
/// <summary>
/// Abort any write command without protection information
/// </summary>
/// <summary>Abort any write command without protection information</summary>
public bool RWWP;
/// <summary>
/// Supportes block lengths and protection information
/// </summary>
/// <summary>Supportes block lengths and protection information</summary>
public bool SBLP;
}
public static ModePage_0A? DecodeModePage_0A(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x0A) return null;
if((pageResponse?[0] & 0x3F) != 0x0A)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_0A decoded = new ModePage_0A();
var decoded = new ModePage_0A();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.RLEC |= (pageResponse[2] & 0x01) == 0x01;
@@ -191,7 +139,8 @@ namespace DiscImageChef.Decoders.SCSI
decoded.ReadyAENHoldOffPeriod = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
if(pageResponse.Length < 10) return decoded;
if(pageResponse.Length < 10)
return decoded;
// SPC-1
decoded.GLTSD |= (pageResponse[2] & 0x02) == 0x02;
@@ -228,49 +177,84 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_0A(ModePage_0A? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_0A page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_0A page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Control mode page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.RLEC) sb.AppendLine("\tIf set, target shall report log exception conditions");
if(page.DQue) sb.AppendLine("\tTagged queuing is disabled");
if(page.EECA) sb.AppendLine("\tExtended Contingent Allegiance is enabled");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.RLEC)
sb.AppendLine("\tIf set, target shall report log exception conditions");
if(page.DQue)
sb.AppendLine("\tTagged queuing is disabled");
if(page.EECA)
sb.AppendLine("\tExtended Contingent Allegiance is enabled");
if(page.RAENP)
sb.AppendLine("\tTarget may issue an asynchronous event notification upon completing its initialization");
if(page.UAAENP)
sb.AppendLine("\tTarget may issue an asynchronous event notification instead of a unit attention condition");
if(page.EAENP)
sb.AppendLine("\tTarget may issue an asynchronous event notification instead of a deferred error");
if(page.GLTSD) sb.AppendLine("\tGlobal logging target save disabled");
if(page.RAC) sb.AppendLine("\tCHECK CONDITION should be reported rather than a long busy condition");
if(page.SWP) sb.AppendLine("\tSoftware write protect is active");
if(page.GLTSD)
sb.AppendLine("\tGlobal logging target save disabled");
if(page.RAC)
sb.AppendLine("\tCHECK CONDITION should be reported rather than a long busy condition");
if(page.SWP)
sb.AppendLine("\tSoftware write protect is active");
if(page.TAS)
sb.AppendLine("\tTasks aborted by other initiator's actions should be terminated with TASK ABORTED");
if(page.TMF_ONLY)
sb.AppendLine("\tAll tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate");
if(page.D_SENSE)
sb.AppendLine("\tDevice shall return descriptor format sense data when returning sense data in the same transactions as a CHECK CONDITION");
if(page.ATO) sb.AppendLine("\tLOGICAL BLOCK APPLICATION TAG should not be modified");
if(page.DPICZ) sb.AppendLine("\tProtector information checking is disabled");
if(page.NUAR) sb.AppendLine("\tNo unit attention on release");
if(page.ATMPE) sb.AppendLine("\tApplication Tag mode page is enabled");
if(page.RWWP) sb.AppendLine("\tAbort any write command without protection information");
if(page.SBLP) sb.AppendLine("\tSupportes block lengths and protection information");
if(page.ATO)
sb.AppendLine("\tLOGICAL BLOCK APPLICATION TAG should not be modified");
if(page.DPICZ)
sb.AppendLine("\tProtector information checking is disabled");
if(page.NUAR)
sb.AppendLine("\tNo unit attention on release");
if(page.ATMPE)
sb.AppendLine("\tApplication Tag mode page is enabled");
if(page.RWWP)
sb.AppendLine("\tAbort any write command without protection information");
if(page.SBLP)
sb.AppendLine("\tSupportes block lengths and protection information");
switch(page.TST)
{
case 0:
sb.AppendLine("\tThe logical unit maintains one task set for all nexuses");
break;
case 1:
sb.AppendLine("\tThe logical unit maintains separate task sets for each nexus");
break;
default:
sb.AppendFormat("\tUnknown Task set type {0}", page.TST).AppendLine();
break;
}
@@ -278,12 +262,15 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tCommands should be sent strictly ordered");
break;
case 1:
sb.AppendLine("\tCommands can be reordered in any manner");
break;
default:
sb.AppendFormat("\tUnknown Queue Algorithm Modifier {0}", page.QueueAlgorithm).AppendLine();
break;
}
@@ -291,15 +278,19 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tIf ACA is established, the task set commands shall resume after it is cleared, otherwise they shall terminate with CHECK CONDITION");
break;
case 1:
sb.AppendLine("\tAll the affected commands in the task set shall be aborted when CHECK CONDITION is returned");
break;
case 3:
sb.AppendLine("\tAffected commands in the task set belonging with the CHECK CONDITION nexus shall be aborted");
break;
default:
sb.AppendLine("\tReserved QErr value 2 is set");
break;
}
@@ -307,15 +298,19 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tLUN shall clear unit attention condition reported in the same nexus");
break;
case 2:
sb.AppendLine("\tLUN shall not clear unit attention condition reported in the same nexus");
break;
case 3:
sb.AppendLine("\tLUN shall not clear unit attention condition reported in the same nexus and shall establish a unit attention condition for the initiator");
break;
default:
sb.AppendLine("\tReserved UA_INTLCK_CTRL value 1 is set");
break;
}
@@ -323,15 +318,19 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tOn medium insertion, it shall be loaded for full access");
break;
case 1:
sb.AppendLine("\tOn medium insertion, it shall be loaded for auxiliary memory access only");
break;
case 2:
sb.AppendLine("\tOn medium insertion, it shall not be loaded");
break;
default:
sb.AppendFormat("\tReserved autoload mode {0} set", page.AutoloadMode).AppendLine();
break;
}
@@ -343,8 +342,8 @@ namespace DiscImageChef.Decoders.SCSI
if(page.BusyTimeoutPeriod == 0xFFFF)
sb.AppendLine("\tThere is no limit on the maximum time that is allowed to remain busy");
else
sb.AppendFormat("\tA maximum of {0} ms are allowed to remain busy", page.BusyTimeoutPeriod * 100)
.AppendLine();
sb.AppendFormat("\tA maximum of {0} ms are allowed to remain busy", page.BusyTimeoutPeriod * 100).
AppendLine();
if(page.ExtendedSelfTestCompletionTime > 0)
sb.AppendFormat("\t{0} seconds to complete extended self-test", page.ExtendedSelfTestCompletionTime);
@@ -354,58 +353,44 @@ namespace DiscImageChef.Decoders.SCSI
#endregion Mode Page 0x0A: Control mode page
#region Mode Page 0x0A subpage 0x01: Control Extension mode page
/// <summary>
/// Control Extension mode page
/// Page code 0x0A
/// Subpage code 0x01
/// 32 bytes in SPC-3, SPC-4, SPC-5
/// </summary>
/// <summary>Control Extension mode page Page code 0x0A Subpage code 0x01 32 bytes in SPC-3, SPC-4, SPC-5</summary>
public struct ModePage_0A_S01
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Timestamp outside this standard
/// </summary>
/// <summary>Timestamp outside this standard</summary>
public bool TCMOS;
/// <summary>
/// SCSI precedence
/// </summary>
/// <summary>SCSI precedence</summary>
public bool SCSIP;
/// <summary>
/// Implicit Asymmetric Logical Unit Access Enabled
/// </summary>
/// <summary>Implicit Asymmetric Logical Unit Access Enabled</summary>
public bool IALUAE;
/// <summary>
/// Initial task priority
/// </summary>
/// <summary>Initial task priority</summary>
public byte InitialPriority;
/// <summary>
/// Device life control disabled
/// </summary>
/// <summary>Device life control disabled</summary>
public bool DLC;
/// <summary>
/// Maximum size of SENSE data in bytes
/// </summary>
/// <summary>Maximum size of SENSE data in bytes</summary>
public byte MaximumSenseLength;
}
public static ModePage_0A_S01? DecodeModePage_0A_S01(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) != 0x40) return null;
if((pageResponse?[0] & 0x40) != 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x0A) return null;
if((pageResponse[0] & 0x3F) != 0x0A)
return null;
if(pageResponse[1] != 0x01) return null;
if(pageResponse[1] != 0x01)
return null;
if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null;
if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length)
return null;
if(pageResponse.Length < 32) return null;
if(pageResponse.Length < 32)
return null;
ModePage_0A_S01 decoded = new ModePage_0A_S01();
var decoded = new ModePage_0A_S01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -423,29 +408,34 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_0A_S01(ModePage_0A_S01? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_0A_S01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Control extension page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.TCMOS)
{
sb.Append("\tTimestamp can be initialized by methods outside of the SCSI standards");
if(page.SCSIP) sb.Append(", but SCSI's SET TIMESTAMP shall take precedence over them");
if(page.SCSIP)
sb.Append(", but SCSI's SET TIMESTAMP shall take precedence over them");
sb.AppendLine();
}
if(page.IALUAE) sb.AppendLine("\tImplicit Asymmetric Logical Unit Access is enabled");
if(page.IALUAE)
sb.AppendLine("\tImplicit Asymmetric Logical Unit Access is enabled");
sb.AppendFormat("\tInitial priority is {0}", page.InitialPriority).AppendLine();
if(page.DLC) sb.AppendLine("\tDevice will not degrade performance to extend its life");
if(page.DLC)
sb.AppendLine("\tDevice will not degrade performance to extend its life");
if(page.MaximumSenseLength > 0)
sb.AppendFormat("\tMaximum sense data would be {0} bytes", page.MaximumSenseLength).AppendLine();

View File

@@ -35,22 +35,15 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x0B: Medium types supported page
/// <summary>
/// Disconnect-reconnect page
/// Page code 0x0B
/// 8 bytes in SCSI-2
/// </summary>
/// <summary>Disconnect-reconnect page Page code 0x0B 8 bytes in SCSI-2</summary>
public struct ModePage_0B
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public MediumTypes MediumType1;
public MediumTypes MediumType2;
@@ -60,15 +53,19 @@ namespace DiscImageChef.Decoders.SCSI
public static ModePage_0B? DecodeModePage_0B(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x0B) return null;
if((pageResponse?[0] & 0x3F) != 0x0B)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_0B decoded = new ModePage_0B();
var decoded = new ModePage_0B();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.MediumType1 = (MediumTypes)pageResponse[4];
@@ -84,27 +81,32 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_0B(ModePage_0B? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_0B page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_0B page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Medium types supported page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.MediumType1 != MediumTypes.Default)
sb.AppendFormat("Supported medium type one: {0}", GetMediumTypeDescription(page.MediumType1))
.AppendLine();
sb.AppendFormat("Supported medium type one: {0}", GetMediumTypeDescription(page.MediumType1)).
AppendLine();
if(page.MediumType2 != MediumTypes.Default)
sb.AppendFormat("Supported medium type two: {0}", GetMediumTypeDescription(page.MediumType2))
.AppendLine();
sb.AppendFormat("Supported medium type two: {0}", GetMediumTypeDescription(page.MediumType2)).
AppendLine();
if(page.MediumType3 != MediumTypes.Default)
sb.AppendFormat("Supported medium type three: {0}", GetMediumTypeDescription(page.MediumType3))
.AppendLine();
sb.AppendFormat("Supported medium type three: {0}", GetMediumTypeDescription(page.MediumType3)).
AppendLine();
if(page.MediumType4 != MediumTypes.Default)
sb.AppendFormat("Supported medium type four: {0}", GetMediumTypeDescription(page.MediumType4))
.AppendLine();
sb.AppendFormat("Supported medium type four: {0}", GetMediumTypeDescription(page.MediumType4)).
AppendLine();
return sb.ToString();
}

View File

@@ -35,48 +35,39 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x0D: CD-ROM parameteres page
/// <summary>
/// CD-ROM parameteres page
/// Page code 0x0D
/// 8 bytes in SCSI-2, MMC-1, MMC-2, MMC-3
/// </summary>
/// <summary>CD-ROM parameteres page Page code 0x0D 8 bytes in SCSI-2, MMC-1, MMC-2, MMC-3</summary>
public struct ModePage_0D
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Time the drive shall remain in hold track state after seek or read
/// </summary>
/// <summary>Time the drive shall remain in hold track state after seek or read</summary>
public byte InactivityTimerMultiplier;
/// <summary>
/// Seconds per Minute
/// </summary>
/// <summary>Seconds per Minute</summary>
public ushort SecondsPerMinute;
/// <summary>
/// Frames per Second
/// </summary>
/// <summary>Frames per Second</summary>
public ushort FramesPerSecond;
}
public static ModePage_0D? DecodeModePage_0D(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x0D) return null;
if((pageResponse?[0] & 0x3F) != 0x0D)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_0D decoded = new ModePage_0D();
var decoded = new ModePage_0D();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.InactivityTimerMultiplier = (byte)(pageResponse[3] & 0xF);
@@ -91,68 +82,88 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_0D(ModePage_0D? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_0D page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_0D page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI CD-ROM parameters page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.InactivityTimerMultiplier)
{
case 0:
sb.AppendLine("\tDrive will remain in track hold state a vendor-specified time after a seek or read");
break;
case 1:
sb.AppendLine("\tDrive will remain in track hold state 125 ms after a seek or read");
break;
case 2:
sb.AppendLine("\tDrive will remain in track hold state 250 ms after a seek or read");
break;
case 3:
sb.AppendLine("\tDrive will remain in track hold state 500 ms after a seek or read");
break;
case 4:
sb.AppendLine("\tDrive will remain in track hold state 1 second after a seek or read");
break;
case 5:
sb.AppendLine("\tDrive will remain in track hold state 2 seconds after a seek or read");
break;
case 6:
sb.AppendLine("\tDrive will remain in track hold state 4 seconds after a seek or read");
break;
case 7:
sb.AppendLine("\tDrive will remain in track hold state 8 seconds after a seek or read");
break;
case 8:
sb.AppendLine("\tDrive will remain in track hold state 16 seconds after a seek or read");
break;
case 9:
sb.AppendLine("\tDrive will remain in track hold state 32 seconds after a seek or read");
break;
case 10:
sb.AppendLine("\tDrive will remain in track hold state 1 minute after a seek or read");
break;
case 11:
sb.AppendLine("\tDrive will remain in track hold state 2 minutes after a seek or read");
break;
case 12:
sb.AppendLine("\tDrive will remain in track hold state 4 minutes after a seek or read");
break;
case 13:
sb.AppendLine("\tDrive will remain in track hold state 8 minutes after a seek or read");
break;
case 14:
sb.AppendLine("\tDrive will remain in track hold state 16 minutes after a seek or read");
break;
case 15:
sb.AppendLine("\tDrive will remain in track hold state 32 minutes after a seek or read");
break;
}
if(page.SecondsPerMinute > 0)
sb.AppendFormat("\tEach minute has {0} seconds", page.SecondsPerMinute).AppendLine();
if(page.FramesPerSecond > 0)
sb.AppendFormat("\tEach second has {0} frames", page.FramesPerSecond).AppendLine();

View File

@@ -35,88 +35,59 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x0E: CD-ROM audio control parameters page
/// <summary>
/// CD-ROM audio control parameters
/// Page code 0x0E
/// 16 bytes in SCSI-2, MMC-1, MMC-2, MMC-3
/// </summary>
/// <summary>CD-ROM audio control parameters Page code 0x0E 16 bytes in SCSI-2, MMC-1, MMC-2, MMC-3</summary>
public struct ModePage_0E
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Return status as soon as playback operation starts
/// </summary>
/// <summary>Return status as soon as playback operation starts</summary>
public bool Immed;
/// <summary>
/// Stop on track crossing
/// </summary>
/// <summary>Stop on track crossing</summary>
public bool SOTC;
/// <summary>
/// Indicates <see cref="BlocksPerSecondOfAudio" /> is valid
/// </summary>
/// <summary>Indicates <see cref="BlocksPerSecondOfAudio" /> is valid</summary>
public bool APRVal;
/// <summary>
/// Multiplier for <see cref="BlocksPerSecondOfAudio" />
/// </summary>
/// <summary>Multiplier for <see cref="BlocksPerSecondOfAudio" /></summary>
public byte LBAFormat;
/// <summary>
/// LBAs per second of audio
/// </summary>
/// <summary>LBAs per second of audio</summary>
public ushort BlocksPerSecondOfAudio;
/// <summary>
/// Channels output on this port
/// </summary>
/// <summary>Channels output on this port</summary>
public byte OutputPort0ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
/// <summary>Volume level for this port</summary>
public byte OutputPort0Volume;
/// <summary>
/// Channels output on this port
/// </summary>
/// <summary>Channels output on this port</summary>
public byte OutputPort1ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
/// <summary>Volume level for this port</summary>
public byte OutputPort1Volume;
/// <summary>
/// Channels output on this port
/// </summary>
/// <summary>Channels output on this port</summary>
public byte OutputPort2ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
/// <summary>Volume level for this port</summary>
public byte OutputPort2Volume;
/// <summary>
/// Channels output on this port
/// </summary>
/// <summary>Channels output on this port</summary>
public byte OutputPort3ChannelSelection;
/// <summary>
/// Volume level for this port
/// </summary>
/// <summary>Volume level for this port</summary>
public byte OutputPort3Volume;
}
public static ModePage_0E? DecodeModePage_0E(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x0E) return null;
if((pageResponse?[0] & 0x3F) != 0x0E)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 16) return null;
if(pageResponse.Length < 16)
return null;
ModePage_0E decoded = new ModePage_0E();
var decoded = new ModePage_0E();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.Immed |= (pageResponse[2] & 0x04) == 0x04;
@@ -141,24 +112,31 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_0E(ModePage_0E? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_0E page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_0E page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI CD-ROM audio control parameters page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
sb.AppendLine(page.Immed
? "\tDrive will return from playback command immediately"
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendLine(page.Immed ? "\tDrive will return from playback command immediately"
: "\tDrive will return from playback command when playback ends");
if(page.SOTC) sb.AppendLine("\tDrive will stop playback on track end");
if(page.SOTC)
sb.AppendLine("\tDrive will stop playback on track end");
if(page.APRVal)
{
double blocks;
if(page.LBAFormat == 8) blocks = page.BlocksPerSecondOfAudio * (1 / 256);
else blocks = page.BlocksPerSecondOfAudio;
if(page.LBAFormat == 8)
blocks = page.BlocksPerSecondOfAudio * (1 / 256);
else
blocks = page.BlocksPerSecondOfAudio;
sb.AppendFormat("\tThere are {0} blocks per each second of audio", blocks).AppendLine();
}
@@ -166,21 +144,32 @@ namespace DiscImageChef.Decoders.SCSI
if(page.OutputPort0ChannelSelection > 0)
{
sb.Append("\tOutput port 0 has channels ");
if((page.OutputPort0ChannelSelection & 0x01) == 0x01) sb.Append("0 ");
if((page.OutputPort0ChannelSelection & 0x02) == 0x02) sb.Append("1 ");
if((page.OutputPort0ChannelSelection & 0x04) == 0x04) sb.Append("2 ");
if((page.OutputPort0ChannelSelection & 0x08) == 0x08) sb.Append("3 ");
if((page.OutputPort0ChannelSelection & 0x01) == 0x01)
sb.Append("0 ");
if((page.OutputPort0ChannelSelection & 0x02) == 0x02)
sb.Append("1 ");
if((page.OutputPort0ChannelSelection & 0x04) == 0x04)
sb.Append("2 ");
if((page.OutputPort0ChannelSelection & 0x08) == 0x08)
sb.Append("3 ");
switch(page.OutputPort0Volume)
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort0Volume).AppendLine();
break;
}
}
@@ -188,21 +177,32 @@ namespace DiscImageChef.Decoders.SCSI
if(page.OutputPort1ChannelSelection > 0)
{
sb.Append("\tOutput port 1 has channels ");
if((page.OutputPort1ChannelSelection & 0x01) == 0x01) sb.Append("0 ");
if((page.OutputPort1ChannelSelection & 0x02) == 0x02) sb.Append("1 ");
if((page.OutputPort1ChannelSelection & 0x04) == 0x04) sb.Append("2 ");
if((page.OutputPort1ChannelSelection & 0x08) == 0x08) sb.Append("3 ");
if((page.OutputPort1ChannelSelection & 0x01) == 0x01)
sb.Append("0 ");
if((page.OutputPort1ChannelSelection & 0x02) == 0x02)
sb.Append("1 ");
if((page.OutputPort1ChannelSelection & 0x04) == 0x04)
sb.Append("2 ");
if((page.OutputPort1ChannelSelection & 0x08) == 0x08)
sb.Append("3 ");
switch(page.OutputPort1Volume)
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort1Volume).AppendLine();
break;
}
}
@@ -210,43 +210,66 @@ namespace DiscImageChef.Decoders.SCSI
if(page.OutputPort2ChannelSelection > 0)
{
sb.Append("\tOutput port 2 has channels ");
if((page.OutputPort2ChannelSelection & 0x01) == 0x01) sb.Append("0 ");
if((page.OutputPort2ChannelSelection & 0x02) == 0x02) sb.Append("1 ");
if((page.OutputPort2ChannelSelection & 0x04) == 0x04) sb.Append("2 ");
if((page.OutputPort2ChannelSelection & 0x08) == 0x08) sb.Append("3 ");
if((page.OutputPort2ChannelSelection & 0x01) == 0x01)
sb.Append("0 ");
if((page.OutputPort2ChannelSelection & 0x02) == 0x02)
sb.Append("1 ");
if((page.OutputPort2ChannelSelection & 0x04) == 0x04)
sb.Append("2 ");
if((page.OutputPort2ChannelSelection & 0x08) == 0x08)
sb.Append("3 ");
switch(page.OutputPort2Volume)
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort2Volume).AppendLine();
break;
}
}
if(page.OutputPort3ChannelSelection <= 0) return sb.ToString();
if(page.OutputPort3ChannelSelection <= 0)
return sb.ToString();
sb.Append("\tOutput port 3 has channels ");
if((page.OutputPort3ChannelSelection & 0x01) == 0x01) sb.Append("0 ");
if((page.OutputPort3ChannelSelection & 0x02) == 0x02) sb.Append("1 ");
if((page.OutputPort3ChannelSelection & 0x04) == 0x04) sb.Append("2 ");
if((page.OutputPort3ChannelSelection & 0x08) == 0x08) sb.Append("3 ");
if((page.OutputPort3ChannelSelection & 0x01) == 0x01)
sb.Append("0 ");
if((page.OutputPort3ChannelSelection & 0x02) == 0x02)
sb.Append("1 ");
if((page.OutputPort3ChannelSelection & 0x04) == 0x04)
sb.Append("2 ");
if((page.OutputPort3ChannelSelection & 0x08) == 0x08)
sb.Append("3 ");
switch(page.OutputPort3Volume)
{
case 0:
sb.AppendLine("muted");
break;
case 0xFF:
sb.AppendLine("at maximum volume");
break;
default:
sb.AppendFormat("at volume {0}", page.OutputPort3Volume).AppendLine();
break;
}

View File

@@ -35,60 +35,45 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x0F: Data compression page
/// <summary>
/// Data compression page
/// Page code 0x0F
/// 16 bytes in SSC-1, SSC-2, SSC-3
/// </summary>
/// <summary>Data compression page Page code 0x0F 16 bytes in SSC-1, SSC-2, SSC-3</summary>
public struct ModePage_0F
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Data compression enabled
/// </summary>
/// <summary>Data compression enabled</summary>
public bool DCE;
/// <summary>
/// Data compression capable
/// </summary>
/// <summary>Data compression capable</summary>
public bool DCC;
/// <summary>
/// Data decompression enabled
/// </summary>
/// <summary>Data decompression enabled</summary>
public bool DDE;
/// <summary>
/// Report exception on decompression
/// </summary>
/// <summary>Report exception on decompression</summary>
public byte RED;
/// <summary>
/// Compression algorithm
/// </summary>
/// <summary>Compression algorithm</summary>
public uint CompressionAlgo;
/// <summary>
/// Decompression algorithm
/// </summary>
/// <summary>Decompression algorithm</summary>
public uint DecompressionAlgo;
}
public static ModePage_0F? DecodeModePage_0F(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x0F) return null;
if((pageResponse?[0] & 0x3F) != 0x0F)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 16) return null;
if(pageResponse.Length < 16)
return null;
ModePage_0F decoded = new ModePage_0F();
var decoded = new ModePage_0F();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -99,6 +84,7 @@ namespace DiscImageChef.Decoders.SCSI
decoded.CompressionAlgo = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) +
(pageResponse[6] << 8) + pageResponse[7]);
decoded.DecompressionAlgo = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) +
(pageResponse[10] << 8) + pageResponse[11]);
@@ -110,43 +96,54 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_0F(ModePage_0F? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_0F page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_0F page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Data compression page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.DCC)
{
sb.AppendLine("\tDrive supports data compression");
if(page.DCE)
{
sb.Append("\tData compression is enabled with ");
switch(page.CompressionAlgo)
{
case 3:
sb.AppendLine("IBM ALDC with 512 byte buffer");
break;
case 4:
sb.AppendLine("IBM ALDC with 1024 byte buffer");
break;
case 5:
sb.AppendLine("IBM ALDC with 2048 byte buffer");
break;
case 0x10:
sb.AppendLine("IBM IDRC");
break;
case 0x20:
sb.AppendLine("DCLZ");
break;
case 0xFF:
sb.AppendLine("an unregistered compression algorithm");
break;
default:
sb.AppendFormat("an unknown algorithm coded {0}", page.CompressionAlgo).AppendLine();
break;
}
}
@@ -154,32 +151,42 @@ namespace DiscImageChef.Decoders.SCSI
if(page.DDE)
{
sb.AppendLine("\tData decompression is enabled");
if(page.DecompressionAlgo == 0) sb.AppendLine("\tLast data read was uncompressed");
if(page.DecompressionAlgo == 0)
sb.AppendLine("\tLast data read was uncompressed");
else
{
sb.Append("\tLast data read was compressed with ");
switch(page.CompressionAlgo)
{
case 3:
sb.AppendLine("IBM ALDC with 512 byte buffer");
break;
case 4:
sb.AppendLine("IBM ALDC with 1024 byte buffer");
break;
case 5:
sb.AppendLine("IBM ALDC with 2048 byte buffer");
break;
case 0x10:
sb.AppendLine("IBM IDRC");
break;
case 0x20:
sb.AppendLine("DCLZ");
break;
case 0xFF:
sb.AppendLine("an unregistered compression algorithm");
break;
default:
sb.AppendFormat("an unknown algorithm coded {0}", page.CompressionAlgo).AppendLine();
break;
}
}
@@ -187,7 +194,8 @@ namespace DiscImageChef.Decoders.SCSI
sb.AppendFormat("\tReport exception on compression is set to {0}", page.RED).AppendLine();
}
else sb.AppendLine("\tDrive does not support data compression");
else
sb.AppendLine("\tDrive does not support data compression");
return sb.ToString();
}

View File

@@ -35,66 +35,57 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x10: XOR control mode page
/// <summary>
/// XOR control mode page
/// Page code 0x10
/// 24 bytes in SBC-1, SBC-2
/// </summary>
/// <summary>XOR control mode page Page code 0x10 24 bytes in SBC-1, SBC-2</summary>
public struct ModePage_10
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Disables XOR operations
/// </summary>
/// <summary>Disables XOR operations</summary>
public bool XORDIS;
/// <summary>
/// Maximum transfer length in blocks for a XOR command
/// </summary>
/// <summary>Maximum transfer length in blocks for a XOR command</summary>
public uint MaxXorWrite;
/// <summary>
/// Maximum regenerate length in blocks
/// </summary>
/// <summary>Maximum regenerate length in blocks</summary>
public uint MaxRegenSize;
/// <summary>
/// Maximum transfer length in blocks for READ during a rebuild
/// </summary>
/// <summary>Maximum transfer length in blocks for READ during a rebuild</summary>
public uint MaxRebuildRead;
/// <summary>
/// Minimum time in ms between READs during a rebuild
/// </summary>
/// <summary>Minimum time in ms between READs during a rebuild</summary>
public ushort RebuildDelay;
}
public static ModePage_10? DecodeModePage_10(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x10) return null;
if((pageResponse?[0] & 0x3F) != 0x10)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 24) return null;
if(pageResponse.Length < 24)
return null;
ModePage_10 decoded = new ModePage_10();
var decoded = new ModePage_10();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.XORDIS |= (pageResponse[2] & 0x02) == 0x02;
decoded.MaxXorWrite = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) +
pageResponse[7]);
decoded.MaxRegenSize = (uint)((pageResponse[12] << 24) + (pageResponse[13] << 16) +
(pageResponse[14] << 8) + pageResponse[15]);
decoded.MaxRebuildRead = (uint)((pageResponse[16] << 24) + (pageResponse[17] << 16) +
(pageResponse[18] << 8) + pageResponse[19]);
decoded.RebuildDelay = (ushort)((pageResponse[22] << 8) + pageResponse[23]);
return decoded;
@@ -105,27 +96,33 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_10(ModePage_10? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_10 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_10 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI XOR control mode page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.XORDIS) sb.AppendLine("\tXOR operations are disabled");
if(page.XORDIS)
sb.AppendLine("\tXOR operations are disabled");
else
{
if(page.MaxXorWrite > 0)
sb.AppendFormat("\tDrive accepts a maximum of {0} blocks in a single XOR WRITE command",
page.MaxXorWrite).AppendLine();
if(page.MaxRegenSize > 0)
sb.AppendFormat("\tDrive accepts a maximum of {0} blocks in a REGENERATE command",
page.MaxRegenSize).AppendLine();
if(page.MaxRebuildRead > 0)
sb.AppendFormat("\tDrive accepts a maximum of {0} blocks in a READ command during rebuild",
page.MaxRebuildRead).AppendLine();
if(page.RebuildDelay > 0)
sb.AppendFormat("\tDrive needs a minimum of {0} ms between READ commands during rebuild",
page.RebuildDelay).AppendLine();

View File

@@ -35,146 +35,91 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x10: Device configuration page
/// <summary>
/// Device configuration page
/// Page code 0x10
/// 16 bytes in SCSI-2, SSC-1, SSC-2, SSC-3
/// </summary>
/// <summary>Device configuration page Page code 0x10 16 bytes in SCSI-2, SSC-1, SSC-2, SSC-3</summary>
public struct ModePage_10_SSC
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Used in mode select to change partition to one specified in <see cref="ActivePartition" />
/// </summary>
/// <summary>Used in mode select to change partition to one specified in <see cref="ActivePartition" /></summary>
public bool CAP;
/// <summary>
/// Used in mode select to change format to one specified in <see cref="ActiveFormat" />
/// </summary>
/// <summary>Used in mode select to change format to one specified in <see cref="ActiveFormat" /></summary>
public bool CAF;
/// <summary>
/// Active format, vendor-specific
/// </summary>
/// <summary>Active format, vendor-specific</summary>
public byte ActiveFormat;
/// <summary>
/// Current logical partition
/// </summary>
/// <summary>Current logical partition</summary>
public byte ActivePartition;
/// <summary>
/// How full the buffer shall be before writing to medium
/// </summary>
/// <summary>How full the buffer shall be before writing to medium</summary>
public byte WriteBufferFullRatio;
/// <summary>
/// How empty the buffer shall be before reading more data from the medium
/// </summary>
/// <summary>How empty the buffer shall be before reading more data from the medium</summary>
public byte ReadBufferEmptyRatio;
/// <summary>
/// Delay in 100 ms before buffered data is forcefully written to the medium even before buffer is full
/// </summary>
/// <summary>Delay in 100 ms before buffered data is forcefully written to the medium even before buffer is full</summary>
public ushort WriteDelayTime;
/// <summary>
/// Drive supports recovering data from buffer
/// </summary>
/// <summary>Drive supports recovering data from buffer</summary>
public bool DBR;
/// <summary>
/// Medium has block IDs
/// </summary>
/// <summary>Medium has block IDs</summary>
public bool BIS;
/// <summary>
/// Drive recognizes and reports setmarks
/// </summary>
/// <summary>Drive recognizes and reports setmarks</summary>
public bool RSmk;
/// <summary>
/// Drive selects best speed
/// </summary>
/// <summary>Drive selects best speed</summary>
public bool AVC;
/// <summary>
/// If drive should stop pre-reading on filemarks
/// </summary>
/// <summary>If drive should stop pre-reading on filemarks</summary>
public byte SOCF;
/// <summary>
/// If set, recovered buffer data is LIFO, otherwise, FIFO
/// </summary>
/// <summary>If set, recovered buffer data is LIFO, otherwise, FIFO</summary>
public bool RBO;
/// <summary>
/// Report early warnings
/// </summary>
/// <summary>Report early warnings</summary>
public bool REW;
/// <summary>
/// Inter-block gap
/// </summary>
/// <summary>Inter-block gap</summary>
public byte GapSize;
/// <summary>
/// End-of-Data format
/// </summary>
/// <summary>End-of-Data format</summary>
public byte EODDefined;
/// <summary>
/// EOD generation enabled
/// </summary>
/// <summary>EOD generation enabled</summary>
public bool EEG;
/// <summary>
/// Synchronize data to medium on early warning
/// </summary>
/// <summary>Synchronize data to medium on early warning</summary>
public bool SEW;
/// <summary>
/// Bytes to reduce buffer size on early warning
/// </summary>
/// <summary>Bytes to reduce buffer size on early warning</summary>
public uint BufferSizeEarlyWarning;
/// <summary>
/// Selected data compression algorithm
/// </summary>
/// <summary>Selected data compression algorithm</summary>
public byte SelectedCompression;
/// <summary>
/// Soft write protect
/// </summary>
/// <summary>Soft write protect</summary>
public bool SWP;
/// <summary>
/// Associated write protect
/// </summary>
/// <summary>Associated write protect</summary>
public bool ASOCWP;
/// <summary>
/// Persistent write protect
/// </summary>
/// <summary>Persistent write protect</summary>
public bool PERSWP;
/// <summary>
/// Permanent write protect
/// </summary>
/// <summary>Permanent write protect</summary>
public bool PRMWP;
public bool BAML;
public bool BAM;
public byte RewindOnReset;
/// <summary>
/// How drive shall respond to detection of compromised WORM medium integrity
/// </summary>
/// <summary>How drive shall respond to detection of compromised WORM medium integrity</summary>
public byte WTRE;
/// <summary>
/// Respond to commands only if a reservation exists
/// </summary>
/// <summary>Respond to commands only if a reservation exists</summary>
public bool OIR;
}
public static ModePage_10_SSC? DecodeModePage_10_SSC(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x10) return null;
if((pageResponse?[0] & 0x3F) != 0x10)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 16) return null;
if(pageResponse.Length < 16)
return null;
ModePage_10_SSC decoded = new ModePage_10_SSC();
var decoded = new ModePage_10_SSC();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.CAP |= (pageResponse[2] & 0x40) == 0x40;
@@ -193,8 +138,10 @@ namespace DiscImageChef.Decoders.SCSI
decoded.EEG |= (pageResponse[10] & 0x10) == 0x10;
decoded.SEW |= (pageResponse[10] & 0x08) == 0x08;
decoded.SOCF = (byte)((pageResponse[8] & 0x0C) >> 2);
decoded.BufferSizeEarlyWarning =
(uint)((pageResponse[11] << 16) + (pageResponse[12] << 8) + pageResponse[13]);
decoded.SelectedCompression = pageResponse[14];
decoded.SWP |= (pageResponse[10] & 0x04) == 0x04;
@@ -218,54 +165,70 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_10_SSC(ModePage_10_SSC? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_10_SSC page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Device configuration page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\tActive format: {0}", page.ActiveFormat).AppendLine();
sb.AppendFormat("\tActive partition: {0}", page.ActivePartition).AppendLine();
sb.AppendFormat("\tWrite buffer shall have a full ratio of {0} before being flushed to medium",
page.WriteBufferFullRatio).AppendLine();
sb.AppendFormat("\tRead buffer shall have an empty ratio of {0} before more data is read from medium",
page.ReadBufferEmptyRatio).AppendLine();
sb
.AppendFormat("\tDrive will delay {0} ms before buffered data is forcefully written to the medium even before buffer is full",
sb.
AppendFormat("\tDrive will delay {0} ms before buffered data is forcefully written to the medium even before buffer is full",
page.WriteDelayTime * 100).AppendLine();
if(page.DBR)
{
sb.AppendLine("\tDrive supports recovering data from buffer");
sb.AppendLine(page.RBO
? "\tRecovered buffer data comes in LIFO order"
sb.AppendLine(page.RBO ? "\tRecovered buffer data comes in LIFO order"
: "\tRecovered buffer data comes in FIFO order");
}
if(page.BIS) sb.AppendLine("\tMedium supports block IDs");
if(page.RSmk) sb.AppendLine("\tDrive reports setmarks");
if(page.BIS)
sb.AppendLine("\tMedium supports block IDs");
if(page.RSmk)
sb.AppendLine("\tDrive reports setmarks");
switch(page.SOCF)
{
case 0:
sb.AppendLine("\tDrive will pre-read until buffer is full");
break;
case 1:
sb.AppendLine("\tDrive will pre-read until one filemark is detected");
break;
case 2:
sb.AppendLine("\tDrive will pre-read until two filemark is detected");
break;
case 3:
sb.AppendLine("\tDrive will pre-read until three filemark is detected");
break;
}
if(page.REW)
{
sb.AppendLine("\tDrive reports early warnings");
if(page.SEW) sb.AppendLine("\tDrive will synchronize buffer to medium on early warnings");
if(page.SEW)
sb.AppendLine("\tDrive will synchronize buffer to medium on early warnings");
}
switch(page.GapSize)
@@ -273,6 +236,7 @@ namespace DiscImageChef.Decoders.SCSI
case 0: break;
case 1:
sb.AppendLine("\tInter-block gap is long enough to support update in place");
break;
case 2:
case 3:
@@ -288,46 +252,60 @@ namespace DiscImageChef.Decoders.SCSI
case 13:
case 14:
case 15:
sb.AppendFormat("\tInter-block gap is {0} times the device's defined gap size", page.GapSize)
.AppendLine();
sb.AppendFormat("\tInter-block gap is {0} times the device's defined gap size", page.GapSize).
AppendLine();
break;
default:
sb.AppendFormat("\tInter-block gap is unknown value {0}", page.GapSize).AppendLine();
break;
}
if(page.EEG) sb.AppendLine("\tDrive generates end-of-data");
if(page.EEG)
sb.AppendLine("\tDrive generates end-of-data");
switch(page.SelectedCompression)
{
case 0:
sb.AppendLine("\tDrive does not use compression");
break;
case 1:
sb.AppendLine("\tDrive uses default compression");
break;
default:
sb.AppendFormat("\tDrive uses unknown compression {0}", page.SelectedCompression).AppendLine();
break;
}
if(page.SWP) sb.AppendLine("\tSoftware write protect is enabled");
if(page.ASOCWP) sb.AppendLine("\tAssociated write protect is enabled");
if(page.PERSWP) sb.AppendLine("\tPersistent write protect is enabled");
if(page.PRMWP) sb.AppendLine("\tPermanent write protect is enabled");
if(page.SWP)
sb.AppendLine("\tSoftware write protect is enabled");
if(page.ASOCWP)
sb.AppendLine("\tAssociated write protect is enabled");
if(page.PERSWP)
sb.AppendLine("\tPersistent write protect is enabled");
if(page.PRMWP)
sb.AppendLine("\tPermanent write protect is enabled");
if(page.BAML)
sb.AppendLine(page.BAM
? "\tDrive operates using explicit address mode"
sb.AppendLine(page.BAM ? "\tDrive operates using explicit address mode"
: "\tDrive operates using implicit address mode");
switch(page.RewindOnReset)
{
case 1:
sb.AppendLine("\tDrive shall position to beginning of default data partition on reset");
break;
case 2:
sb.AppendLine("\tDrive shall maintain its position on reset");
break;
}
@@ -335,13 +313,16 @@ namespace DiscImageChef.Decoders.SCSI
{
case 1:
sb.AppendLine("\tDrive will do nothing on WORM tampered medium");
break;
case 2:
sb.AppendLine("\tDrive will return CHECK CONDITION on WORM tampered medium");
break;
}
if(page.OIR) sb.AppendLine("\tDrive will only respond to commands if it has received a reservation");
if(page.OIR)
sb.AppendLine("\tDrive will only respond to commands if it has received a reservation");
return sb.ToString();
}

View File

@@ -36,111 +36,71 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x11: Medium partition page (1)
public enum PartitionSizeUnitOfMeasures : byte
{
/// <summary>
/// Partition size is measures in bytes
/// </summary>
Bytes = 0,
/// <summary>
/// Partition size is measures in Kilobytes
/// </summary>
Kilobytes = 1,
/// <summary>
/// Partition size is measures in Megabytes
/// </summary>
Megabytes = 2,
/// <summary>
/// Partition size is 10eUNITS bytes
/// </summary>
/// <summary>Partition size is measures in bytes</summary>
Bytes = 0, /// <summary>Partition size is measures in Kilobytes</summary>
Kilobytes = 1, /// <summary>Partition size is measures in Megabytes</summary>
Megabytes = 2, /// <summary>Partition size is 10eUNITS bytes</summary>
Exponential = 3
}
public enum MediumFormatRecognitionValues : byte
{
/// <summary>
/// Logical unit is incapable of format or partition recognition
/// </summary>
Incapable = 0,
/// <summary>
/// Logical unit is capable of format recognition only
/// </summary>
FormatCapable = 1,
/// <summary>
/// Logical unit is capable of partition recognition only
/// </summary>
PartitionCapable = 2,
/// <summary>
/// Logical unit is capable of both format and partition recognition
/// </summary>
/// <summary>Logical unit is incapable of format or partition recognition</summary>
Incapable = 0, /// <summary>Logical unit is capable of format recognition only</summary>
FormatCapable = 1, /// <summary>Logical unit is capable of partition recognition only</summary>
PartitionCapable = 2, /// <summary>Logical unit is capable of both format and partition recognition</summary>
Capable = 3
}
/// <summary>
/// Medium partition page(1)
/// Page code 0x11
/// </summary>
/// <summary>Medium partition page(1) Page code 0x11</summary>
public struct ModePage_11
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Maximum number of additional partitions supported
/// </summary>
/// <summary>Maximum number of additional partitions supported</summary>
public byte MaxAdditionalPartitions;
/// <summary>
/// Number of additional partitions to be defined for a volume
/// </summary>
/// <summary>Number of additional partitions to be defined for a volume</summary>
public byte AdditionalPartitionsDefined;
/// <summary>
/// Device defines partitions based on its fixed definition
/// </summary>
/// <summary>Device defines partitions based on its fixed definition</summary>
public bool FDP;
/// <summary>
/// Device should divide medium according to the additional partitions defined field using sizes defined by device
/// </summary>
/// <summary>Device should divide medium according to the additional partitions defined field using sizes defined by device</summary>
public bool SDP;
/// <summary>
/// Initiator defines number and size of partitions
/// </summary>
/// <summary>Initiator defines number and size of partitions</summary>
public bool IDP;
/// <summary>
/// Defines the unit on which the partition sizes are defined
/// </summary>
/// <summary>Defines the unit on which the partition sizes are defined</summary>
public PartitionSizeUnitOfMeasures PSUM;
public bool POFM;
public bool CLEAR;
public bool ADDP;
/// <summary>
/// Defines the capabilities for the unit to recognize media partitions and format
/// </summary>
/// <summary>Defines the capabilities for the unit to recognize media partitions and format</summary>
public MediumFormatRecognitionValues MediumFormatRecognition;
public byte PartitionUnits;
/// <summary>
/// Array of partition sizes in units defined above
/// </summary>
/// <summary>Array of partition sizes in units defined above</summary>
public ushort[] PartitionSizes;
}
public static ModePage_11? DecodeModePage_11(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x11) return null;
if((pageResponse?[0] & 0x3F) != 0x11)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_11 decoded = new ModePage_11();
var decoded = new ModePage_11();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -171,30 +131,42 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_11(ModePage_11? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_11 page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_11 page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI medium partition page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\t{0} maximum additional partitions", page.MaxAdditionalPartitions).AppendLine();
sb.AppendFormat("\t{0} additional partitions defined", page.AdditionalPartitionsDefined).AppendLine();
if(page.FDP) sb.AppendLine("\tPartitions are fixed under device definitions");
if(page.SDP) sb.AppendLine("\tNumber of partitions can be defined but their size is defined by the device");
if(page.IDP) sb.AppendLine("\tNumber and size of partitions can be manually defined");
if(page.FDP)
sb.AppendLine("\tPartitions are fixed under device definitions");
if(page.SDP)
sb.AppendLine("\tNumber of partitions can be defined but their size is defined by the device");
if(page.IDP)
sb.AppendLine("\tNumber and size of partitions can be manually defined");
if(page.POFM)
sb.AppendLine("\tPartition parameters will not be applied until a FORMAT MEDIUM command is received");
if(!page.CLEAR && !page.ADDP)
if(!page.CLEAR &&
!page.ADDP)
sb.AppendLine("\tDevice may erase any or all partitions on MODE SELECT for partitioning");
else if(page.CLEAR && !page.ADDP)
else if(page.CLEAR &&
!page.ADDP)
sb.AppendLine("\tDevice shall erase all partitions on MODE SELECT for partitioning");
else if(!page.CLEAR)
sb.AppendLine("\tDevice shall not erase any partition on MODE SELECT for partitioning");
else sb.AppendLine("\tDevice shall erase all partitions differing on size on MODE SELECT for partitioning");
else
sb.AppendLine("\tDevice shall erase all partitions differing on size on MODE SELECT for partitioning");
string measure;
@@ -203,23 +175,29 @@ namespace DiscImageChef.Decoders.SCSI
case PartitionSizeUnitOfMeasures.Bytes:
sb.AppendLine("\tPartitions are defined in bytes");
measure = "bytes";
break;
case PartitionSizeUnitOfMeasures.Kilobytes:
sb.AppendLine("\tPartitions are defined in kilobytes");
measure = "kilobytes";
break;
case PartitionSizeUnitOfMeasures.Megabytes:
sb.AppendLine("\tPartitions are defined in megabytes");
measure = "megabytes";
break;
case PartitionSizeUnitOfMeasures.Exponential:
sb.AppendFormat("\tPartitions are defined in units of {0} bytes", Math.Pow(10, page.PartitionUnits))
.AppendLine();
sb.AppendFormat("\tPartitions are defined in units of {0} bytes",
Math.Pow(10, page.PartitionUnits)).AppendLine();
measure = $"units of {Math.Pow(10, page.PartitionUnits)} bytes";
break;
default:
sb.AppendFormat("\tUnknown partition size unit code {0}", (byte)page.PSUM).AppendLine();
measure = "units";
break;
}
@@ -227,19 +205,24 @@ namespace DiscImageChef.Decoders.SCSI
{
case MediumFormatRecognitionValues.Capable:
sb.AppendLine("\tDevice is capable of recognizing both medium partitions and format");
break;
case MediumFormatRecognitionValues.FormatCapable:
sb.AppendLine("\tDevice is capable of recognizing medium format");
break;
case MediumFormatRecognitionValues.PartitionCapable:
sb.AppendLine("\tDevice is capable of recognizing medium partitions");
break;
case MediumFormatRecognitionValues.Incapable:
sb.AppendLine("\tDevice is not capable of recognizing neither medium partitions nor format");
break;
default:
sb.AppendFormat("\tUnknown medium recognition code {0}", (byte)page.MediumFormatRecognition)
.AppendLine();
sb.AppendFormat("\tUnknown medium recognition code {0}", (byte)page.MediumFormatRecognition).
AppendLine();
break;
}

View File

@@ -35,42 +35,40 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4)
/// <summary>
/// Medium partition page (2-4)
/// Page codes 0x12, 0x13 and 0x14
/// </summary>
/// <summary>Medium partition page (2-4) Page codes 0x12, 0x13 and 0x14</summary>
public struct ModePage_12_13_14
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Array of partition sizes in units defined in mode page 11
/// </summary>
/// <summary>Array of partition sizes in units defined in mode page 11</summary>
public ushort[] PartitionSizes;
}
public static ModePage_12_13_14? DecodeModePage_12_13_14(byte[] pageResponse)
{
if(pageResponse == null) return null;
if(pageResponse == null)
return null;
if((pageResponse[0] & 0x40) == 0x40) return null;
if((pageResponse[0] & 0x40) == 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x12 && (pageResponse[0] & 0x3F) != 0x13 &&
(pageResponse[0] & 0x3F) != 0x14) return null;
if((pageResponse[0] & 0x3F) != 0x12 &&
(pageResponse[0] & 0x3F) != 0x13 &&
(pageResponse[0] & 0x3F) != 0x14)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 2) return null;
if(pageResponse.Length < 2)
return null;
ModePage_12_13_14 decoded = new ModePage_12_13_14();
var decoded = new ModePage_12_13_14();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -90,14 +88,16 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_12_13_14(ModePage_12_13_14? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_12_13_14 page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI medium partition page (extra):");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\tMedium has defined {0} partitions", page.PartitionSizes.Length).AppendLine();

View File

@@ -35,68 +35,38 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x1A: Power condition page
/// <summary>
/// Power condition page
/// Page code 0x1A
/// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4
/// 40 bytes in SPC-5
/// </summary>
/// <summary>Power condition page Page code 0x1A 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 40 bytes in SPC-5</summary>
public struct ModePage_1A
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Idle timer activated
/// </summary>
/// <summary>Idle timer activated</summary>
public bool Idle;
/// <summary>
/// Standby timer activated
/// </summary>
/// <summary>Standby timer activated</summary>
public bool Standby;
/// <summary>
/// Idle timer
/// </summary>
/// <summary>Idle timer</summary>
public uint IdleTimer;
/// <summary>
/// Standby timer
/// </summary>
/// <summary>Standby timer</summary>
public uint StandbyTimer;
/// <summary>
/// Interactions between background functions and power management
/// </summary>
/// <summary>Interactions between background functions and power management</summary>
public byte PM_BG_Precedence;
/// <summary>
/// Standby timer Y activated
/// </summary>
/// <summary>Standby timer Y activated</summary>
public bool Standby_Y;
/// <summary>
/// Idle timer B activated
/// </summary>
/// <summary>Idle timer B activated</summary>
public bool Idle_B;
/// <summary>
/// Idle timer C activated
/// </summary>
/// <summary>Idle timer C activated</summary>
public bool Idle_C;
/// <summary>
/// Idle timer B
/// </summary>
/// <summary>Idle timer B</summary>
public uint IdleTimer_B;
/// <summary>
/// Idle timer C
/// </summary>
/// <summary>Idle timer C</summary>
public uint IdleTimer_C;
/// <summary>
/// Standby timer Y
/// </summary>
/// <summary>Standby timer Y</summary>
public uint StandbyTimer_Y;
public byte CCF_Idle;
public byte CCF_Standby;
@@ -105,15 +75,19 @@ namespace DiscImageChef.Decoders.SCSI
public static ModePage_1A? DecodeModePage_1A(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x1A) return null;
if((pageResponse?[0] & 0x3F) != 0x1A)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 12) return null;
if(pageResponse.Length < 12)
return null;
ModePage_1A decoded = new ModePage_1A();
var decoded = new ModePage_1A();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -122,10 +96,12 @@ namespace DiscImageChef.Decoders.SCSI
decoded.IdleTimer = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) +
pageResponse[7]);
decoded.StandbyTimer = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + (pageResponse[10] << 8) +
pageResponse[11]);
if(pageResponse.Length < 40) return decoded;
if(pageResponse.Length < 40)
return decoded;
decoded.PM_BG_Precedence = (byte)((pageResponse[2] & 0xC0) >> 6);
decoded.Standby_Y |= (pageResponse[2] & 0x01) == 0x01;
@@ -134,8 +110,10 @@ namespace DiscImageChef.Decoders.SCSI
decoded.IdleTimer_B = (uint)((pageResponse[12] << 24) + (pageResponse[13] << 16) + (pageResponse[14] << 8) +
pageResponse[15]);
decoded.IdleTimer_C = (uint)((pageResponse[16] << 24) + (pageResponse[17] << 16) + (pageResponse[18] << 8) +
pageResponse[19]);
decoded.StandbyTimer_Y = (uint)((pageResponse[20] << 24) + (pageResponse[21] << 16) +
(pageResponse[22] << 8) + pageResponse[23]);
@@ -151,44 +129,60 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_1A(ModePage_1A? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_1A page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_1A page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Power condition page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.Standby && page.StandbyTimer > 0 || page.Standby_Y && page.StandbyTimer_Y > 0)
if(page.Standby && page.StandbyTimer > 0 ||
page.Standby_Y && page.StandbyTimer_Y > 0)
{
if(page.Standby && page.StandbyTimer > 0)
if(page.Standby &&
page.StandbyTimer > 0)
sb.AppendFormat("\tStandby timer Z is set to {0} ms", page.StandbyTimer * 100).AppendLine();
if(page.Standby_Y && page.StandbyTimer_Y > 0)
if(page.Standby_Y &&
page.StandbyTimer_Y > 0)
sb.AppendFormat("\tStandby timer Y is set to {0} ms", page.StandbyTimer_Y * 100).AppendLine();
}
else sb.AppendLine("\tDrive will not enter standy mode");
else
sb.AppendLine("\tDrive will not enter standy mode");
if(page.Idle && page.IdleTimer > 0 || page.Idle_B && page.IdleTimer_B > 0 ||
if(page.Idle && page.IdleTimer > 0 ||
page.Idle_B && page.IdleTimer_B > 0 ||
page.Idle_C && page.IdleTimer_C > 0)
{
if(page.Idle && page.IdleTimer > 0)
if(page.Idle &&
page.IdleTimer > 0)
sb.AppendFormat("\tIdle timer A is set to {0} ms", page.IdleTimer * 100).AppendLine();
if(page.Idle_B && page.IdleTimer_B > 0)
if(page.Idle_B &&
page.IdleTimer_B > 0)
sb.AppendFormat("\tIdle timer B is set to {0} ms", page.IdleTimer_B * 100).AppendLine();
if(page.Idle_C && page.IdleTimer_C > 0)
if(page.Idle_C &&
page.IdleTimer_C > 0)
sb.AppendFormat("\tIdle timer C is set to {0} ms", page.IdleTimer_C * 100).AppendLine();
}
else sb.AppendLine("\tDrive will not enter idle mode");
else
sb.AppendLine("\tDrive will not enter idle mode");
switch(page.PM_BG_Precedence)
{
case 0: break;
case 1:
sb.AppendLine("\tPerforming background functions take precedence over maintaining low power conditions");
break;
case 2:
sb.AppendLine("\tMaintaining low power conditions take precedence over performing background functions");
break;
}
@@ -197,41 +191,35 @@ namespace DiscImageChef.Decoders.SCSI
#endregion Mode Page 0x1A: Power condition page
#region Mode Page 0x1A subpage 0x01: Power Consumption mode page
/// <summary>
/// Power Consumption mode page
/// Page code 0x1A
/// Subpage code 0x01
/// 16 bytes in SPC-5
/// </summary>
/// <summary>Power Consumption mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5</summary>
public struct ModePage_1A_S01
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Active power level
/// </summary>
/// <summary>Active power level</summary>
public byte ActiveLevel;
/// <summary>
/// Power Consumption VPD identifier in use
/// </summary>
/// <summary>Power Consumption VPD identifier in use</summary>
public byte PowerConsumptionIdentifier;
}
public static ModePage_1A_S01? DecodeModePage_1A_S01(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) != 0x40) return null;
if((pageResponse?[0] & 0x40) != 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x1A) return null;
if((pageResponse[0] & 0x3F) != 0x1A)
return null;
if(pageResponse[1] != 0x01) return null;
if(pageResponse[1] != 0x01)
return null;
if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null;
if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length)
return null;
if(pageResponse.Length < 16) return null;
if(pageResponse.Length < 16)
return null;
ModePage_1A_S01 decoded = new ModePage_1A_S01();
var decoded = new ModePage_1A_S01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.ActiveLevel = (byte)(pageResponse[6] & 0x03);
@@ -245,29 +233,35 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_1A_S01(ModePage_1A_S01? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_1A_S01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Power Consumption page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.ActiveLevel)
{
case 0:
sb.AppendFormat("\tDevice power consumption is dictated by identifier {0} of Power Consumption VPD",
page.PowerConsumptionIdentifier).AppendLine();
break;
case 1:
sb.AppendLine("\tDevice is in highest relative power consumption level");
break;
case 2:
sb.AppendLine("\tDevice is in intermediate relative power consumption level");
break;
case 3:
sb.AppendLine("\tDevice is in lowest relative power consumption level");
break;
}

View File

@@ -35,56 +35,43 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x1B: Removable Block Access Capabilities page
/// <summary>
/// Removable Block Access Capabilities page
/// Page code 0x1B
/// 12 bytes in INF-8070
/// </summary>
/// <summary>Removable Block Access Capabilities page Page code 0x1B 12 bytes in INF-8070</summary>
public struct ModePage_1B
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Supports reporting progress of format
/// </summary>
/// <summary>Supports reporting progress of format</summary>
public bool SRFP;
/// <summary>
/// Non-CD Optical Device
/// </summary>
/// <summary>Non-CD Optical Device</summary>
public bool NCD;
/// <summary>
/// Phase change dual device supporting a CD and a Non-CD Optical devices
/// </summary>
/// <summary>Phase change dual device supporting a CD and a Non-CD Optical devices</summary>
public bool SML;
/// <summary>
/// Total number of LUNs
/// </summary>
/// <summary>Total number of LUNs</summary>
public byte TLUN;
/// <summary>
/// System Floppy Type device
/// </summary>
/// <summary>System Floppy Type device</summary>
public bool SFLP;
}
public static ModePage_1B? DecodeModePage_1B(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x1B) return null;
if((pageResponse?[0] & 0x3F) != 0x1B)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 12) return null;
if(pageResponse.Length < 12)
return null;
ModePage_1B decoded = new ModePage_1B();
var decoded = new ModePage_1B();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.SFLP |= (pageResponse[2] & 0x80) == 0x80;
@@ -102,20 +89,31 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_1B(ModePage_1B? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_1B page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_1B page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Removable Block Access Capabilities page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.SFLP) sb.AppendLine("\tDrive can be used as a system floppy device");
if(page.SRFP) sb.AppendLine("\tDrive supports reporting progress of format");
if(page.NCD) sb.AppendLine("\tDrive is a Non-CD Optical Device");
if(page.SML) sb.AppendLine("\tDevice is a dual device supporting CD and Non-CD Optical");
if(page.TLUN > 0) sb.AppendFormat("\tDrive supports {0} LUNs", page.TLUN).AppendLine();
if(page.SFLP)
sb.AppendLine("\tDrive can be used as a system floppy device");
if(page.SRFP)
sb.AppendLine("\tDrive supports reporting progress of format");
if(page.NCD)
sb.AppendLine("\tDrive is a Non-CD Optical Device");
if(page.SML)
sb.AppendLine("\tDevice is a dual device supporting CD and Non-CD Optical");
if(page.TLUN > 0)
sb.AppendFormat("\tDrive supports {0} LUNs", page.TLUN).AppendLine();
return sb.ToString();
}

View File

@@ -35,78 +35,55 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x1C: Informational exceptions control page
/// <summary>
/// Informational exceptions control page
/// Page code 0x1C
/// 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4
/// </summary>
/// <summary>Informational exceptions control page Page code 0x1C 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4</summary>
public struct ModePage_1C
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Informational exception operations should not affect performance
/// </summary>
/// <summary>Informational exception operations should not affect performance</summary>
public bool Perf;
/// <summary>
/// Disable informational exception operations
/// </summary>
/// <summary>Disable informational exception operations</summary>
public bool DExcpt;
/// <summary>
/// Create a test device failure at next interval time
/// </summary>
/// <summary>Create a test device failure at next interval time</summary>
public bool Test;
/// <summary>
/// Log informational exception conditions
/// </summary>
/// <summary>Log informational exception conditions</summary>
public bool LogErr;
/// <summary>
/// Method of reporting informational exceptions
/// </summary>
/// <summary>Method of reporting informational exceptions</summary>
public byte MRIE;
/// <summary>
/// 100 ms period to report an informational exception condition
/// </summary>
/// <summary>100 ms period to report an informational exception condition</summary>
public uint IntervalTimer;
/// <summary>
/// How many times to report informational exceptions
/// </summary>
/// <summary>How many times to report informational exceptions</summary>
public uint ReportCount;
/// <summary>
/// Enable background functions
/// </summary>
/// <summary>Enable background functions</summary>
public bool EBF;
/// <summary>
/// Warning reporting enabled
/// </summary>
/// <summary>Warning reporting enabled</summary>
public bool EWasc;
/// <summary>
/// Enable reporting of background self-test errors
/// </summary>
/// <summary>Enable reporting of background self-test errors</summary>
public bool EBACKERR;
}
public static ModePage_1C? DecodeModePage_1C(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x1C) return null;
if((pageResponse?[0] & 0x3F) != 0x1C)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_1C decoded = new ModePage_1C();
var decoded = new ModePage_1C();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -137,16 +114,19 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_1C(ModePage_1C? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_1C page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_1C page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Informational exceptions control page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.DExcpt) sb.AppendLine("\tInformational exceptions are disabled");
if(page.DExcpt)
sb.AppendLine("\tInformational exceptions are disabled");
else
{
sb.AppendLine("\tInformational exceptions are enabled");
@@ -155,33 +135,46 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tNo reporting of informational exception condition");
break;
case 1:
sb.AppendLine("\tAsynchronous event reporting of informational exceptions");
break;
case 2:
sb.AppendLine("\tGenerate unit attention on informational exceptions");
break;
case 3:
sb.AppendLine("\tConditionally generate recovered error on informational exceptions");
break;
case 4:
sb.AppendLine("\tUnconditionally generate recovered error on informational exceptions");
break;
case 5:
sb.AppendLine("\tGenerate no sense on informational exceptions");
break;
case 6:
sb.AppendLine("\tOnly report informational exception condition on request");
break;
default:
sb.AppendFormat("\tUnknown method of reporting {0}", page.MRIE).AppendLine();
break;
}
if(page.Perf) sb.AppendLine("\tInformational exceptions reporting should not affect drive performance");
if(page.Test) sb.AppendLine("\tA test informational exception will raise on next timer");
if(page.LogErr) sb.AppendLine("\tDrive shall log informational exception conditions");
if(page.Perf)
sb.AppendLine("\tInformational exceptions reporting should not affect drive performance");
if(page.Test)
sb.AppendLine("\tA test informational exception will raise on next timer");
if(page.LogErr)
sb.AppendLine("\tDrive shall log informational exception conditions");
if(page.IntervalTimer > 0)
if(page.IntervalTimer == 0xFFFFFFFF)
@@ -194,74 +187,61 @@ namespace DiscImageChef.Decoders.SCSI
page.ReportCount);
}
if(page.EWasc) sb.AppendLine("\tWarning reporting is enabled");
if(page.EBF) sb.AppendLine("\tBackground functions are enabled");
if(page.EBACKERR) sb.AppendLine("\tDrive will report background self-test errors");
if(page.EWasc)
sb.AppendLine("\tWarning reporting is enabled");
if(page.EBF)
sb.AppendLine("\tBackground functions are enabled");
if(page.EBACKERR)
sb.AppendLine("\tDrive will report background self-test errors");
return sb.ToString();
}
#endregion Mode Page 0x1C: Informational exceptions control page
#region Mode Page 0x1C subpage 0x01: Background Control mode page
/// <summary>
/// Background Control mode page
/// Page code 0x1A
/// Subpage code 0x01
/// 16 bytes in SPC-5
/// </summary>
/// <summary>Background Control mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5</summary>
public struct ModePage_1C_S01
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Suspend on log full
/// </summary>
/// <summary>Suspend on log full</summary>
public bool S_L_Full;
/// <summary>
/// Log only when intervention required
/// </summary>
/// <summary>Log only when intervention required</summary>
public bool LOWIR;
/// <summary>
/// Enable background medium scan
/// </summary>
/// <summary>Enable background medium scan</summary>
public bool En_Bms;
/// <summary>
/// Enable background pre-scan
/// </summary>
/// <summary>Enable background pre-scan</summary>
public bool En_Ps;
/// <summary>
/// Time in hours between background medium scans
/// </summary>
/// <summary>Time in hours between background medium scans</summary>
public ushort BackgroundScanInterval;
/// <summary>
/// Maximum time in hours for a background pre-scan to complete
/// </summary>
/// <summary>Maximum time in hours for a background pre-scan to complete</summary>
public ushort BackgroundPrescanTimeLimit;
/// <summary>
/// Minimum time in ms being idle before resuming a background scan
/// </summary>
/// <summary>Minimum time in ms being idle before resuming a background scan</summary>
public ushort MinIdleBeforeBgScan;
/// <summary>
/// Maximum time in ms to start processing commands while performing a background scan
/// </summary>
/// <summary>Maximum time in ms to start processing commands while performing a background scan</summary>
public ushort MaxTimeSuspendBgScan;
}
public static ModePage_1C_S01? DecodeModePage_1C_S01(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) != 0x40) return null;
if((pageResponse?[0] & 0x40) != 0x40)
return null;
if((pageResponse[0] & 0x3F) != 0x1C) return null;
if((pageResponse[0] & 0x3F) != 0x1C)
return null;
if(pageResponse[1] != 0x01) return null;
if(pageResponse[1] != 0x01)
return null;
if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) return null;
if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length)
return null;
if(pageResponse.Length < 16) return null;
if(pageResponse.Length < 16)
return null;
ModePage_1C_S01 decoded = new ModePage_1C_S01();
var decoded = new ModePage_1C_S01();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -283,19 +263,28 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_1C_S01(ModePage_1C_S01? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_1C_S01 page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Background Control page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.S_L_Full) sb.AppendLine("\tBackground scans will be halted if log is full");
if(page.LOWIR) sb.AppendLine("\tBackground scans will only be logged if they require intervention");
if(page.En_Bms) sb.AppendLine("\tBackground medium scans are enabled");
if(page.En_Ps) sb.AppendLine("\tBackground pre-scans are enabled");
if(page.S_L_Full)
sb.AppendLine("\tBackground scans will be halted if log is full");
if(page.LOWIR)
sb.AppendLine("\tBackground scans will only be logged if they require intervention");
if(page.En_Bms)
sb.AppendLine("\tBackground medium scans are enabled");
if(page.En_Ps)
sb.AppendLine("\tBackground pre-scans are enabled");
if(page.BackgroundScanInterval > 0)
sb.AppendFormat("\t{0} hours shall be between the start of a background scan operation and the next",
@@ -310,8 +299,8 @@ namespace DiscImageChef.Decoders.SCSI
page.MinIdleBeforeBgScan).AppendLine();
if(page.MaxTimeSuspendBgScan > 0)
sb
.AppendFormat("\tAt most {0} ms must be before suspending a background scan operation and processing received commands",
sb.
AppendFormat("\tAt most {0} ms must be before suspending a background scan operation and processing received commands",
page.MaxTimeSuspendBgScan).AppendLine();
return sb.ToString();

View File

@@ -35,48 +35,39 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x1C: Timer & Protect page
/// <summary>
/// Timer &amp; Protect page
/// Page code 0x1C
/// 8 bytes in INF-8070
/// </summary>
/// <summary>Timer &amp; Protect page Page code 0x1C 8 bytes in INF-8070</summary>
public struct ModePage_1C_SFF
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// Time the device shall remain in the current state after seek, read or write operation
/// </summary>
/// <summary>Time the device shall remain in the current state after seek, read or write operation</summary>
public byte InactivityTimeMultiplier;
/// <summary>
/// Disabled until power cycle
/// </summary>
/// <summary>Disabled until power cycle</summary>
public bool DISP;
/// <summary>
/// Software Write Protect until Power-down
/// </summary>
/// <summary>Software Write Protect until Power-down</summary>
public bool SWPP;
}
public static ModePage_1C_SFF? DecodeModePage_1C_SFF(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x1C) return null;
if((pageResponse?[0] & 0x3F) != 0x1C)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
ModePage_1C_SFF decoded = new ModePage_1C_SFF();
var decoded = new ModePage_1C_SFF();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.DISP |= (pageResponse[2] & 0x02) == 0x02;
@@ -92,67 +83,88 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_1C_SFF(ModePage_1C_SFF? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_1C_SFF page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("SCSI Timer & Protect page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.DISP) sb.AppendLine("\tDrive is disabled until power is cycled");
if(page.SWPP) sb.AppendLine("\tDrive is software write-protected until powered down");
if(page.DISP)
sb.AppendLine("\tDrive is disabled until power is cycled");
if(page.SWPP)
sb.AppendLine("\tDrive is software write-protected until powered down");
switch(page.InactivityTimeMultiplier)
{
case 0:
sb.AppendLine("\tDrive will remain in same status a vendor-specified time after a seek, read or write operation");
break;
case 1:
sb.AppendLine("\tDrive will remain in same status 125 ms after a seek, read or write operation");
break;
case 2:
sb.AppendLine("\tDrive will remain in same status 250 ms after a seek, read or write operation");
break;
case 3:
sb.AppendLine("\tDrive will remain in same status 500 ms after a seek, read or write operation");
break;
case 4:
sb.AppendLine("\tDrive will remain in same status 1 second after a seek, read or write operation");
break;
case 5:
sb.AppendLine("\tDrive will remain in same status 2 seconds after a seek, read or write operation");
break;
case 6:
sb.AppendLine("\tDrive will remain in same status 4 seconds after a seek, read or write operation");
break;
case 7:
sb.AppendLine("\tDrive will remain in same status 8 seconds after a seek, read or write operation");
break;
case 8:
sb.AppendLine("\tDrive will remain in same status 16 seconds after a seek, read or write operation");
break;
case 9:
sb.AppendLine("\tDrive will remain in same status 32 seconds after a seek, read or write operation");
break;
case 10:
sb.AppendLine("\tDrive will remain in same status 1 minute after a seek, read or write operation");
break;
case 11:
sb.AppendLine("\tDrive will remain in same status 2 minutes after a seek, read or write operation");
break;
case 12:
sb.AppendLine("\tDrive will remain in same status 4 minutes after a seek, read or write operation");
break;
case 13:
sb.AppendLine("\tDrive will remain in same status 8 minutes after a seek, read or write operation");
break;
case 14:
sb.AppendLine("\tDrive will remain in same status 16 minutes after a seek, read or write operation");
break;
case 15:
sb.AppendLine("\tDrive will remain in same status 32 minutes after a seek, read or write operation");
break;
}

View File

@@ -35,17 +35,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Mode Page 0x1D: Medium Configuration Mode Page
public struct ModePage_1D
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public bool WORMM;
public byte WormModeLabelRestrictions;
@@ -54,15 +51,19 @@ namespace DiscImageChef.Decoders.SCSI
public static ModePage_1D? DecodeModePage_1D(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x1D) return null;
if((pageResponse?[0] & 0x3F) != 0x1D)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 32) return null;
if(pageResponse.Length < 32)
return null;
ModePage_1D decoded = new ModePage_1D();
var decoded = new ModePage_1D();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.WORMM |= (pageResponse[2] & 0x01) == 0x01;
@@ -77,31 +78,38 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_1D(ModePage_1D? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
ModePage_1D page = modePage.Value;
StringBuilder sb = new StringBuilder();
ModePage_1D page = modePage.Value;
var sb = new StringBuilder();
sb.AppendLine("SCSI Medium Configuration Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.WORMM) sb.AppendLine("\tDrive is operating in WORM mode");
if(page.WORMM)
sb.AppendLine("\tDrive is operating in WORM mode");
switch(page.WormModeLabelRestrictions)
{
case 0:
sb.AppendLine("\tDrive does not allow any logical blocks to be overwritten");
break;
case 1:
sb.AppendLine("\tDrive allows a tape header to be overwritten");
break;
case 2:
sb.AppendLine("\tDrive allows all format labels to be overwritten");
break;
default:
sb.AppendFormat("\tUnknown WORM mode label restrictions code {0}", page.WormModeLabelRestrictions)
.AppendLine();
sb.AppendFormat("\tUnknown WORM mode label restrictions code {0}", page.WormModeLabelRestrictions).
AppendLine();
break;
}
@@ -109,13 +117,16 @@ namespace DiscImageChef.Decoders.SCSI
{
case 2:
sb.AppendLine("\tDrive allows any number of filemarks immediately preceding EOD to be overwritten except filemark closes to BOP");
break;
case 3:
sb.AppendLine("\tDrive allows any number of filemarks immediately preceding EOD to be overwritten");
break;
default:
sb.AppendFormat("\tUnknown WORM mode filemark restrictions code {0}",
page.WormModeLabelRestrictions).AppendLine();
break;
}

View File

@@ -35,17 +35,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Certance Mode Page 0x21: Drive Capabilities Control Mode page
public struct Certance_ModePage_21
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public byte OperatingSystemsSupport;
public byte FirmwareTestControl2;
@@ -59,15 +56,19 @@ namespace DiscImageChef.Decoders.SCSI
public static Certance_ModePage_21? DecodeCertanceModePage_21(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x21) return null;
if((pageResponse?[0] & 0x3F) != 0x21)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 9) return null;
if(pageResponse.Length != 9)
return null;
Certance_ModePage_21 decoded = new Certance_ModePage_21();
var decoded = new Certance_ModePage_21();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.OperatingSystemsSupport = pageResponse[2];
@@ -87,23 +88,27 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyCertanceModePage_21(Certance_ModePage_21? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
Certance_ModePage_21 page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("Certance Drive Capabilities Control Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.OperatingSystemsSupport)
{
case 0:
sb.AppendLine("\tOperating systems support is standard LTO");
break;
default:
sb.AppendFormat("\tOperating systems support is unknown code {0}", page.OperatingSystemsSupport)
.AppendLine();
sb.AppendFormat("\tOperating systems support is unknown code {0}", page.OperatingSystemsSupport).
AppendLine();
break;
}
@@ -112,15 +117,19 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tFactory test code is disabled");
break;
case 1:
sb.AppendLine("\tFactory test code 1 is disabled");
break;
case 2:
sb.AppendLine("\tFactory test code 2 is disabled");
break;
default:
sb.AppendFormat("\tUnknown factory test code {0}", page.FirmwareTestControl).AppendLine();
break;
}
@@ -128,12 +137,15 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tPower-On Self-Test is enabled");
break;
case 1:
sb.AppendLine("\tPower-On Self-Test is disable");
break;
default:
sb.AppendFormat("\tUnknown Power-On Self-Test code {0}", page.ExtendedPOSTMode).AppendLine();
break;
}
@@ -141,37 +153,48 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tCompression is controlled using mode pages 0Fh and 10h");
break;
case 1:
sb.AppendLine("\tCompression is enabled and not controllable");
break;
case 2:
sb.AppendLine("\tCompression is disabled and not controllable");
break;
default:
sb.AppendFormat("\tUnknown compression control code {0}", page.DataCompressionControl).AppendLine();
break;
}
if(page.HostUnloadOverride) sb.AppendLine("\tSCSI UNLOAD command will not eject the cartridge");
if(page.HostUnloadOverride)
sb.AppendLine("\tSCSI UNLOAD command will not eject the cartridge");
sb.Append("\tHow should tapes be unloaded in a power cycle, tape incompatibility, firmware download or cleaning end: ");
switch(page.AutoUnloadMode)
{
case 0:
sb.AppendLine("\tTape will stay threaded at beginning");
break;
case 1:
sb.AppendLine("\tTape will be unthreaded");
break;
case 2:
sb.AppendLine("\tTape will be unthreaded and unloaded");
break;
case 3:
sb.AppendLine("\tData tapes will be threaded at beginning, rest will be unloaded");
break;
default:
sb.AppendFormat("\tUnknown auto unload code {0}", page.AutoUnloadMode).AppendLine();
break;
}

View File

@@ -35,18 +35,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static partial class Modes
{
#region Certance Mode Page 0x22: Interface Control Mode Page
public struct Certance_ModePage_22
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public byte BaudRate;
public byte CmdFwd;
@@ -63,15 +59,19 @@ namespace DiscImageChef.Decoders.SCSI
public static Certance_ModePage_22? DecodeCertanceModePage_22(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x22) return null;
if((pageResponse?[0] & 0x3F) != 0x22)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 16) return null;
if(pageResponse.Length != 16)
return null;
Certance_ModePage_22 decoded = new Certance_ModePage_22();
var decoded = new Certance_ModePage_22();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.BaudRate = pageResponse[2];
@@ -94,14 +94,16 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyCertanceModePage_22(Certance_ModePage_22? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
Certance_ModePage_22 page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("Certance Interface Control Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.BaudRate)
{
@@ -109,38 +111,46 @@ namespace DiscImageChef.Decoders.SCSI
case 1:
case 2:
sb.AppendLine("\tLibrary interface will operate at 9600 baud on next reset");
break;
case 3:
sb.AppendLine("\tLibrary interface will operate at 19200 baud on next reset");
break;
case 4:
sb.AppendLine("\tLibrary interface will operate at 38400 baud on next reset");
break;
case 5:
sb.AppendLine("\tLibrary interface will operate at 57600 baud on next reset");
break;
case 6:
sb.AppendLine("\tLibrary interface will operate at 115200 baud on next reset");
break;
default:
sb.AppendFormat("\tUnknown library interface baud rate code {0}", page.BaudRate).AppendLine();
break;
}
sb.AppendLine(page.StopBits
? "Library interface transmits 2 stop bits per byte"
sb.AppendLine(page.StopBits ? "Library interface transmits 2 stop bits per byte"
: "Library interface transmits 1 stop bits per byte");
switch(page.CmdFwd)
{
case 0:
sb.AppendLine("\tCommand forwarding is disabled");
break;
case 1:
sb.AppendLine("\tCommand forwarding is enabled");
break;
default:
sb.AppendFormat("\tUnknown command forwarding code {0}", page.CmdFwd).AppendLine();
break;
}
@@ -148,26 +158,29 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tPort A link is down");
break;
case 3:
sb.AppendLine("\tPort A uses Parallel SCSI Ultra-160 interface");
break;
default:
sb.AppendFormat("\tUnknown port A transport type code {0}", page.PortATransportType).AppendLine();
break;
}
if(page.PortATransportType > 0)
sb.AppendFormat("\tDrive responds to SCSI ID {0}", page.PortAPresentSelectionID).AppendLine();
sb.AppendFormat("\tDrive will respond to SCSI ID {0} on Port A enabling", page.NextSelectionID)
.AppendLine();
sb.AppendFormat("\tDrive will respond to SCSI ID {0} on Port A enabling", page.NextSelectionID).
AppendLine();
sb.AppendFormat("\tDrive jumpers choose SCSI ID {0}", page.JumperedSelectionID).AppendLine();
sb.AppendLine(page.PortAEnabled ? "\tSCSI port is enabled" : "\tSCSI port is disabled");
sb.AppendLine(page.PortAEnabledOnPower
? "\tSCSI port will be enabled on next power up"
sb.AppendLine(page.PortAEnabledOnPower ? "\tSCSI port will be enabled on next power up"
: "\tSCSI port will be disabled on next power up");
return sb.ToString();

View File

@@ -35,17 +35,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region IBM Mode Page 0x24: Drive Capabilities Control Mode page
public struct IBM_ModePage_24
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public byte ModeControl;
public byte VelocitySetting;
@@ -55,15 +52,19 @@ namespace DiscImageChef.Decoders.SCSI
public static IBM_ModePage_24? DecodeIBMModePage_24(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x24) return null;
if((pageResponse?[0] & 0x3F) != 0x24)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 8) return null;
if(pageResponse.Length != 8)
return null;
IBM_ModePage_24 decoded = new IBM_ModePage_24();
var decoded = new IBM_ModePage_24();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.ModeControl = pageResponse[2];
@@ -79,22 +80,27 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyIBMModePage_24(IBM_ModePage_24? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
IBM_ModePage_24 page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("IBM Vendor-Specific Control Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\tVendor-specific mode control: {0}", page.ModeControl);
sb.AppendFormat("\tVendor-specific mode control: {0}", page.ModeControl);
sb.AppendFormat("\tVendor-specific velocity setting: {0}", page.VelocitySetting);
if(!page.EncryptionCapable) return sb.ToString();
if(!page.EncryptionCapable)
return sb.ToString();
sb.AppendLine("\tDrive supports encryption");
if(page.EncryptionEnabled) sb.AppendLine("\tDrive has encryption enabled");
if(page.EncryptionEnabled)
sb.AppendLine("\tDrive has encryption enabled");
return sb.ToString();
}

View File

@@ -39,116 +39,63 @@ using Newtonsoft.Json;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static partial class Modes
{
#region Mode Page 0x2A: CD-ROM capabilities page
/// <summary>
/// CD-ROM capabilities page
/// Page code 0x2A
/// 16 bytes in OB-U0077C
/// 20 bytes in SFF-8020i
/// 22 bytes in MMC-1
/// 26 bytes in MMC-2
/// Variable bytes in MMC-3
/// CD-ROM capabilities page Page code 0x2A 16 bytes in OB-U0077C 20 bytes in SFF-8020i 22 bytes in MMC-1 26 bytes
/// in MMC-2 Variable bytes in MMC-3
/// </summary>
public class ModePage_2A
{
public ModePage_2A_WriteDescriptor[] WriteSpeedPerformanceDescriptors;
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS { get; set; }
/// <summary>
/// Drive supports multi-session and/or Photo-CD
/// </summary>
/// <summary>Drive supports multi-session and/or Photo-CD</summary>
public bool MultiSession { get; set; }
/// <summary>
/// Drive is capable of reading sectors in Mode 2 Form 2 format
/// </summary>
/// <summary>Drive is capable of reading sectors in Mode 2 Form 2 format</summary>
public bool Mode2Form2 { get; set; }
/// <summary>
/// Drive is capable of reading sectors in Mode 2 Form 1 format
/// </summary>
/// <summary>Drive is capable of reading sectors in Mode 2 Form 1 format</summary>
public bool Mode2Form1 { get; set; }
/// <summary>
/// Drive is capable of playing audio
/// </summary>
/// <summary>Drive is capable of playing audio</summary>
public bool AudioPlay { get; set; }
/// <summary>
/// Drive can return the ISRC
/// </summary>
/// <summary>Drive can return the ISRC</summary>
public bool ISRC { get; set; }
/// <summary>
/// Drive can return the media catalogue number
/// </summary>
/// <summary>Drive can return the media catalogue number</summary>
public bool UPC { get; set; }
/// <summary>
/// Drive can return C2 pointers
/// </summary>
/// <summary>Drive can return C2 pointers</summary>
public bool C2Pointer { get; set; }
/// <summary>
/// Drive can read, deinterlave and correct R-W subchannels
/// </summary>
/// <summary>Drive can read, deinterlave and correct R-W subchannels</summary>
public bool DeinterlaveSubchannel { get; set; }
/// <summary>
/// Drive can read interleaved and uncorrected R-W subchannels
/// </summary>
/// <summary>Drive can read interleaved and uncorrected R-W subchannels</summary>
public bool Subchannel { get; set; }
/// <summary>
/// Drive can continue from a loss of streaming on audio reading
/// </summary>
/// <summary>Drive can continue from a loss of streaming on audio reading</summary>
public bool AccurateCDDA { get; set; }
/// <summary>
/// Audio can be read as digital data
/// </summary>
/// <summary>Audio can be read as digital data</summary>
public bool CDDACommand { get; set; }
/// <summary>
/// Loading Mechanism Type
/// </summary>
/// <summary>Loading Mechanism Type</summary>
public byte LoadingMechanism { get; set; }
/// <summary>
/// Drive can eject discs
/// </summary>
/// <summary>Drive can eject discs</summary>
public bool Eject { get; set; }
/// <summary>
/// Drive's optional prevent jumper status
/// </summary>
/// <summary>Drive's optional prevent jumper status</summary>
public bool PreventJumper { get; set; }
/// <summary>
/// Current lock status
/// </summary>
/// <summary>Current lock status</summary>
public bool LockState { get; set; }
/// <summary>
/// Drive can lock media
/// </summary>
/// <summary>Drive can lock media</summary>
public bool Lock { get; set; }
/// <summary>
/// Each channel can be muted independently
/// </summary>
/// <summary>Each channel can be muted independently</summary>
public bool SeparateChannelMute { get; set; }
/// <summary>
/// Each channel's volume can be controlled independently
/// </summary>
/// <summary>Each channel's volume can be controlled independently</summary>
public bool SeparateChannelVolume { get; set; }
/// <summary>
/// Maximum drive speed in Kbytes/second
/// </summary>
/// <summary>Maximum drive speed in Kbytes/second</summary>
public ushort MaximumSpeed { get; set; }
/// <summary>
/// Supported volume levels
/// </summary>
/// <summary>Supported volume levels</summary>
public ushort SupportedVolumeLevels { get; set; }
/// <summary>
/// Buffer size in Kbytes
/// </summary>
/// <summary>Buffer size in Kbytes</summary>
public ushort BufferSize { get; set; }
/// <summary>
/// Current drive speed in Kbytes/second
/// </summary>
/// <summary>Current drive speed in Kbytes/second</summary>
public ushort CurrentSpeed { get; set; }
public bool Method2 { get; set; }
@@ -185,8 +132,7 @@ namespace DiscImageChef.Decoders.SCSI
public byte RotationControlSelected { get; set; }
public ushort CurrentWriteSpeedSelected { get; set; }
[JsonIgnore]
[Key]
[JsonIgnore, Key]
public int Id { get; set; }
}
@@ -198,15 +144,19 @@ namespace DiscImageChef.Decoders.SCSI
public static ModePage_2A DecodeModePage_2A(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x2A) return null;
if((pageResponse?[0] & 0x3F) != 0x2A)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 16) return null;
if(pageResponse.Length < 16)
return null;
ModePage_2A decoded = new ModePage_2A();
var decoded = new ModePage_2A();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -237,7 +187,8 @@ namespace DiscImageChef.Decoders.SCSI
decoded.BufferSize = (ushort)((pageResponse[12] << 8) + pageResponse[13]);
decoded.CurrentSpeed = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
if(pageResponse.Length < 20) return decoded;
if(pageResponse.Length < 20)
return decoded;
decoded.Method2 |= (pageResponse[2] & 0x04) == 0x04;
decoded.ReadCDRW |= (pageResponse[2] & 0x02) == 0x02;
@@ -258,7 +209,8 @@ namespace DiscImageChef.Decoders.SCSI
decoded.RCK |= (pageResponse[17] & 0x04) == 0x04;
decoded.BCK |= (pageResponse[17] & 0x02) == 0x02;
if(pageResponse.Length < 22) return decoded;
if(pageResponse.Length < 22)
return decoded;
decoded.TestWrite |= (pageResponse[3] & 0x04) == 0x04;
decoded.MaxWriteSpeed = (ushort)((pageResponse[18] << 8) + pageResponse[19]);
@@ -266,7 +218,8 @@ namespace DiscImageChef.Decoders.SCSI
decoded.ReadBarcode |= (pageResponse[5] & 0x80) == 0x80;
if(pageResponse.Length < 26) return decoded;
if(pageResponse.Length < 26)
return decoded;
decoded.ReadDVDRAM |= (pageResponse[2] & 0x20) == 0x20;
decoded.ReadDVDR |= (pageResponse[2] & 0x10) == 0x10;
@@ -280,7 +233,8 @@ namespace DiscImageChef.Decoders.SCSI
decoded.CMRSupported = (ushort)((pageResponse[22] << 8) + pageResponse[23]);
if(pageResponse.Length < 32) return decoded;
if(pageResponse.Length < 32)
return decoded;
decoded.BUF |= (pageResponse[4] & 0x80) == 0x80;
decoded.RotationControlSelected = (byte)(pageResponse[27] & 0x03);
@@ -307,96 +261,191 @@ namespace DiscImageChef.Decoders.SCSI
pageResponse[0] = 0x2A;
if(decoded.PS) pageResponse[0] += 0x80;
if(decoded.PS)
pageResponse[0] += 0x80;
if(decoded.AudioPlay) pageResponse[4] += 0x01;
if(decoded.Mode2Form1) pageResponse[4] += 0x10;
if(decoded.Mode2Form2) pageResponse[4] += 0x20;
if(decoded.MultiSession) pageResponse[4] += 0x40;
if(decoded.AudioPlay)
pageResponse[4] += 0x01;
if(decoded.CDDACommand) pageResponse[5] += 0x01;
if(decoded.AccurateCDDA) pageResponse[5] += 0x02;
if(decoded.Subchannel) pageResponse[5] += 0x04;
if(decoded.DeinterlaveSubchannel) pageResponse[5] += 0x08;
if(decoded.C2Pointer) pageResponse[5] += 0x10;
if(decoded.UPC) pageResponse[5] += 0x20;
if(decoded.ISRC) pageResponse[5] += 0x40;
if(decoded.Mode2Form1)
pageResponse[4] += 0x10;
if(decoded.Mode2Form2)
pageResponse[4] += 0x20;
if(decoded.MultiSession)
pageResponse[4] += 0x40;
if(decoded.CDDACommand)
pageResponse[5] += 0x01;
if(decoded.AccurateCDDA)
pageResponse[5] += 0x02;
if(decoded.Subchannel)
pageResponse[5] += 0x04;
if(decoded.DeinterlaveSubchannel)
pageResponse[5] += 0x08;
if(decoded.C2Pointer)
pageResponse[5] += 0x10;
if(decoded.UPC)
pageResponse[5] += 0x20;
if(decoded.ISRC)
pageResponse[5] += 0x40;
decoded.LoadingMechanism = (byte)((pageResponse[6] & 0xE0) >> 5);
if(decoded.Lock) pageResponse[6] += 0x01;
if(decoded.LockState) pageResponse[6] += 0x02;
if(decoded.PreventJumper) pageResponse[6] += 0x04;
if(decoded.Eject) pageResponse[6] += 0x08;
if(decoded.SeparateChannelVolume) pageResponse[7] += 0x01;
if(decoded.SeparateChannelMute) pageResponse[7] += 0x02;
if(decoded.Lock)
pageResponse[6] += 0x01;
if(decoded.LockState)
pageResponse[6] += 0x02;
if(decoded.PreventJumper)
pageResponse[6] += 0x04;
if(decoded.Eject)
pageResponse[6] += 0x08;
if(decoded.SeparateChannelVolume)
pageResponse[7] += 0x01;
if(decoded.SeparateChannelMute)
pageResponse[7] += 0x02;
decoded.MaximumSpeed = (ushort)((pageResponse[8] << 8) + pageResponse[9]);
decoded.SupportedVolumeLevels = (ushort)((pageResponse[10] << 8) + pageResponse[11]);
decoded.BufferSize = (ushort)((pageResponse[12] << 8) + pageResponse[13]);
decoded.CurrentSpeed = (ushort)((pageResponse[14] << 8) + pageResponse[15]);
if(decoded.Method2 || decoded.ReadCDRW || decoded.ReadCDR || decoded.WriteCDRW ||
decoded.WriteCDR ||
decoded.Composite || decoded.DigitalPort1 || decoded.DigitalPort2 || decoded.SDP ||
decoded.SSS ||
decoded.Length > 0 || decoded.LSBF || decoded.RCK || decoded.BCK)
if(decoded.Method2 ||
decoded.ReadCDRW ||
decoded.ReadCDR ||
decoded.WriteCDRW ||
decoded.WriteCDR ||
decoded.Composite ||
decoded.DigitalPort1 ||
decoded.DigitalPort2 ||
decoded.SDP ||
decoded.SSS ||
decoded.Length > 0 ||
decoded.LSBF ||
decoded.RCK ||
decoded.BCK)
{
length = 20;
if(decoded.Method2) pageResponse[2] += 0x04;
if(decoded.ReadCDRW) pageResponse[2] += 0x02;
if(decoded.ReadCDR) pageResponse[2] += 0x01;
if(decoded.WriteCDRW) pageResponse[3] += 0x02;
if(decoded.WriteCDR) pageResponse[3] += 0x01;
if(decoded.Method2)
pageResponse[2] += 0x04;
if(decoded.Composite) pageResponse[4] += 0x02;
if(decoded.DigitalPort1) pageResponse[4] += 0x04;
if(decoded.DigitalPort2) pageResponse[4] += 0x08;
if(decoded.ReadCDRW)
pageResponse[2] += 0x02;
if(decoded.SDP) pageResponse[7] += 0x04;
if(decoded.SSS) pageResponse[7] += 0x08;
if(decoded.ReadCDR)
pageResponse[2] += 0x01;
if(decoded.WriteCDRW)
pageResponse[3] += 0x02;
if(decoded.WriteCDR)
pageResponse[3] += 0x01;
if(decoded.Composite)
pageResponse[4] += 0x02;
if(decoded.DigitalPort1)
pageResponse[4] += 0x04;
if(decoded.DigitalPort2)
pageResponse[4] += 0x08;
if(decoded.SDP)
pageResponse[7] += 0x04;
if(decoded.SSS)
pageResponse[7] += 0x08;
pageResponse[17] = (byte)(decoded.Length << 4);
if(decoded.LSBF) pageResponse[17] += 0x08;
if(decoded.RCK) pageResponse[17] += 0x04;
if(decoded.BCK) pageResponse[17] += 0x02;
if(decoded.LSBF)
pageResponse[17] += 0x08;
if(decoded.RCK)
pageResponse[17] += 0x04;
if(decoded.BCK)
pageResponse[17] += 0x02;
}
if(decoded.TestWrite || decoded.MaxWriteSpeed > 0 || decoded.CurrentWriteSpeed > 0 || decoded.ReadBarcode)
if(decoded.TestWrite ||
decoded.MaxWriteSpeed > 0 ||
decoded.CurrentWriteSpeed > 0 ||
decoded.ReadBarcode)
{
length = 22;
if(decoded.TestWrite) pageResponse[3] += 0x04;
if(decoded.TestWrite)
pageResponse[3] += 0x04;
pageResponse[18] = (byte)((decoded.MaxWriteSpeed & 0xFF00) >> 8);
pageResponse[19] = (byte)(decoded.MaxWriteSpeed & 0xFF);
pageResponse[20] = (byte)((decoded.CurrentWriteSpeed & 0xFF00) >> 8);
pageResponse[21] = (byte)(decoded.CurrentWriteSpeed & 0xFF);
if(decoded.ReadBarcode) pageResponse[5] += 0x80;
if(decoded.ReadBarcode)
pageResponse[5] += 0x80;
}
if(decoded.ReadDVDRAM || decoded.ReadDVDR || decoded.ReadDVDROM || decoded.WriteDVDRAM ||
decoded.WriteDVDR || decoded.LeadInPW || decoded.SCC || decoded.CMRSupported > 0)
if(decoded.ReadDVDRAM ||
decoded.ReadDVDR ||
decoded.ReadDVDROM ||
decoded.WriteDVDRAM ||
decoded.WriteDVDR ||
decoded.LeadInPW ||
decoded.SCC ||
decoded.CMRSupported > 0)
{
length = 26;
if(decoded.ReadDVDRAM) pageResponse[2] += 0x20;
if(decoded.ReadDVDR) pageResponse[2] += 0x10;
if(decoded.ReadDVDROM) pageResponse[2] += 0x08;
if(decoded.WriteDVDRAM) pageResponse[3] += 0x20;
if(decoded.WriteDVDR) pageResponse[3] += 0x10;
if(decoded.ReadDVDRAM)
pageResponse[2] += 0x20;
if(decoded.LeadInPW) pageResponse[3] += 0x20;
if(decoded.SCC) pageResponse[3] += 0x10;
if(decoded.ReadDVDR)
pageResponse[2] += 0x10;
if(decoded.ReadDVDROM)
pageResponse[2] += 0x08;
if(decoded.WriteDVDRAM)
pageResponse[3] += 0x20;
if(decoded.WriteDVDR)
pageResponse[3] += 0x10;
if(decoded.LeadInPW)
pageResponse[3] += 0x20;
if(decoded.SCC)
pageResponse[3] += 0x10;
pageResponse[22] = (byte)((decoded.CMRSupported & 0xFF00) >> 8);
pageResponse[23] = (byte)(decoded.CMRSupported & 0xFF);
}
if(decoded.BUF || decoded.RotationControlSelected > 0 || decoded.CurrentWriteSpeedSelected > 0)
if(decoded.BUF ||
decoded.RotationControlSelected > 0 ||
decoded.CurrentWriteSpeedSelected > 0)
{
length = 32;
if(decoded.BUF) pageResponse[4] += 0x80;
if(decoded.BUF)
pageResponse[4] += 0x80;
pageResponse[27] += decoded.RotationControlSelected;
pageResponse[28] = (byte)((decoded.CurrentWriteSpeedSelected & 0xFF00) >> 8);
pageResponse[29] = (byte)(decoded.CurrentWriteSpeedSelected & 0xFF);
@@ -405,12 +454,15 @@ namespace DiscImageChef.Decoders.SCSI
if(decoded.WriteSpeedPerformanceDescriptors != null)
{
length = 32;
for(int i = 0; i < decoded.WriteSpeedPerformanceDescriptors.Length; i++)
{
length += 4;
pageResponse[1 + 32 + i * 4] = decoded.WriteSpeedPerformanceDescriptors[i].RotationControl;
pageResponse[2 + 32 + i * 4] =
(byte)((decoded.WriteSpeedPerformanceDescriptors[i].WriteSpeed & 0xFF00) >> 8);
pageResponse[3 + 32 + i * 4] =
(byte)(decoded.WriteSpeedPerformanceDescriptors[i].WriteSpeed & 0xFF);
}
@@ -419,6 +471,7 @@ namespace DiscImageChef.Decoders.SCSI
pageResponse[1] = (byte)(length - 2);
byte[] buf = new byte[length];
Array.Copy(pageResponse, 0, buf, 0, length);
return buf;
}
@@ -427,57 +480,87 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyModePage_2A(ModePage_2A modePage)
{
if(modePage is null) return null;
if(modePage is null)
return null;
ModePage_2A page = modePage;
StringBuilder sb = new StringBuilder();
ModePage_2A page = modePage;
var sb = new StringBuilder();
sb.AppendLine("SCSI CD-ROM capabilities page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.AudioPlay) sb.AppendLine("\tDrive can play audio");
if(page.Mode2Form1) sb.AppendLine("\tDrive can read sectors in Mode 2 Form 1 format");
if(page.Mode2Form2) sb.AppendLine("\tDrive can read sectors in Mode 2 Form 2 format");
if(page.MultiSession) sb.AppendLine("\tDrive supports multi-session discs and/or Photo-CD");
if(page.AudioPlay)
sb.AppendLine("\tDrive can play audio");
if(page.CDDACommand) sb.AppendLine("\tDrive can read digital audio");
if(page.AccurateCDDA) sb.AppendLine("\tDrive can continue from streaming loss");
if(page.Subchannel) sb.AppendLine("\tDrive can read uncorrected and interleaved R-W subchannels");
if(page.DeinterlaveSubchannel) sb.AppendLine("\tDrive can read, deinterleave and correct R-W subchannels");
if(page.C2Pointer) sb.AppendLine("\tDrive supports C2 pointers");
if(page.UPC) sb.AppendLine("\tDrive can read Media Catalogue Number");
if(page.ISRC) sb.AppendLine("\tDrive can read ISRC");
if(page.Mode2Form1)
sb.AppendLine("\tDrive can read sectors in Mode 2 Form 1 format");
if(page.Mode2Form2)
sb.AppendLine("\tDrive can read sectors in Mode 2 Form 2 format");
if(page.MultiSession)
sb.AppendLine("\tDrive supports multi-session discs and/or Photo-CD");
if(page.CDDACommand)
sb.AppendLine("\tDrive can read digital audio");
if(page.AccurateCDDA)
sb.AppendLine("\tDrive can continue from streaming loss");
if(page.Subchannel)
sb.AppendLine("\tDrive can read uncorrected and interleaved R-W subchannels");
if(page.DeinterlaveSubchannel)
sb.AppendLine("\tDrive can read, deinterleave and correct R-W subchannels");
if(page.C2Pointer)
sb.AppendLine("\tDrive supports C2 pointers");
if(page.UPC)
sb.AppendLine("\tDrive can read Media Catalogue Number");
if(page.ISRC)
sb.AppendLine("\tDrive can read ISRC");
switch(page.LoadingMechanism)
{
case 0:
sb.AppendLine("\tDrive uses media caddy");
break;
case 1:
sb.AppendLine("\tDrive uses a tray");
break;
case 2:
sb.AppendLine("\tDrive is pop-up");
break;
case 4:
sb.AppendLine("\tDrive is a changer with individually changeable discs");
break;
case 5:
sb.AppendLine("\tDrive is a changer using cartridges");
break;
default:
sb.AppendFormat("\tDrive uses unknown loading mechanism type {0}", page.LoadingMechanism)
.AppendLine();
sb.AppendFormat("\tDrive uses unknown loading mechanism type {0}", page.LoadingMechanism).
AppendLine();
break;
}
if(page.Lock) sb.AppendLine("\tDrive can lock media");
if(page.Lock)
sb.AppendLine("\tDrive can lock media");
if(page.PreventJumper)
{
sb.AppendLine("\tDrive power ups locked");
sb.AppendLine(page.LockState
? "\tDrive is locked, media cannot be ejected or inserted"
sb.AppendLine(page.LockState ? "\tDrive is locked, media cannot be ejected or inserted"
: "\tDrive is not locked, media can be ejected and inserted");
}
else
@@ -485,16 +568,24 @@ namespace DiscImageChef.Decoders.SCSI
? "\tDrive is locked, media cannot be ejected, but if empty, can be inserted"
: "\tDrive is not locked, media can be ejected and inserted");
if(page.Eject) sb.AppendLine("\tDrive can eject media");
if(page.Eject)
sb.AppendLine("\tDrive can eject media");
if(page.SeparateChannelMute) sb.AppendLine("\tEach channel can be muted independently");
if(page.SeparateChannelVolume) sb.AppendLine("\tEach channel's volume can be controlled independently");
if(page.SeparateChannelMute)
sb.AppendLine("\tEach channel can be muted independently");
if(page.SeparateChannelVolume)
sb.AppendLine("\tEach channel's volume can be controlled independently");
if(page.SupportedVolumeLevels > 0)
sb.AppendFormat("\tDrive supports {0} volume levels", page.SupportedVolumeLevels).AppendLine();
if(page.BufferSize > 0) sb.AppendFormat("\tDrive has {0} Kbyte of buffer", page.BufferSize).AppendLine();
if(page.BufferSize > 0)
sb.AppendFormat("\tDrive has {0} Kbyte of buffer", page.BufferSize).AppendLine();
if(page.MaximumSpeed > 0)
sb.AppendFormat("\tDrive's maximum reading speed is {0} Kbyte/sec.", page.MaximumSpeed).AppendLine();
if(page.CurrentSpeed > 0)
sb.AppendFormat("\tDrive's current reading speed is {0} Kbyte/sec.", page.CurrentSpeed).AppendLine();
@@ -502,23 +593,34 @@ namespace DiscImageChef.Decoders.SCSI
{
sb.AppendLine(page.WriteCDR ? "\tDrive can read and write CD-R" : "\tDrive can read CD-R");
if(page.Method2) sb.AppendLine("\tDrive supports reading CD-R packet media");
if(page.Method2)
sb.AppendLine("\tDrive supports reading CD-R packet media");
}
if(page.ReadCDRW)
sb.AppendLine(page.WriteCDRW ? "\tDrive can read and write CD-RW" : "\tDrive can read CD-RW");
if(page.ReadDVDROM) sb.AppendLine("\tDrive can read DVD-ROM");
if(page.ReadDVDROM)
sb.AppendLine("\tDrive can read DVD-ROM");
if(page.ReadDVDR)
sb.AppendLine(page.WriteDVDR ? "\tDrive can read and write DVD-R" : "\tDrive can read DVD-R");
if(page.ReadDVDRAM)
sb.AppendLine(page.WriteDVDRAM ? "\tDrive can read and write DVD-RAM" : "\tDrive can read DVD-RAM");
if(page.Composite) sb.AppendLine("\tDrive can deliver a composite audio and video data stream");
if(page.DigitalPort1) sb.AppendLine("\tDrive supports IEC-958 digital output on port 1");
if(page.DigitalPort2) sb.AppendLine("\tDrive supports IEC-958 digital output on port 2");
if(page.Composite)
sb.AppendLine("\tDrive can deliver a composite audio and video data stream");
if(page.DigitalPort1)
sb.AppendLine("\tDrive supports IEC-958 digital output on port 1");
if(page.DigitalPort2)
sb.AppendLine("\tDrive supports IEC-958 digital output on port 2");
if(page.SDP)
sb.AppendLine("\tDrive contains a changer that can report the exact contents of the slots");
if(page.SDP) sb.AppendLine("\tDrive contains a changer that can report the exact contents of the slots");
if(page.CurrentWriteSpeedSelected > 0)
{
if(page.RotationControlSelected == 0)
@@ -531,33 +633,41 @@ namespace DiscImageChef.Decoders.SCSI
else
{
if(page.MaxWriteSpeed > 0)
sb.AppendFormat("\tDrive's maximum writing speed is {0} Kbyte/sec.", page.MaxWriteSpeed)
.AppendLine();
sb.AppendFormat("\tDrive's maximum writing speed is {0} Kbyte/sec.", page.MaxWriteSpeed).
AppendLine();
if(page.CurrentWriteSpeed > 0)
sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec.", page.CurrentWriteSpeed)
.AppendLine();
sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec.", page.CurrentWriteSpeed).
AppendLine();
}
if(page.WriteSpeedPerformanceDescriptors != null)
foreach(ModePage_2A_WriteDescriptor descriptor in
page.WriteSpeedPerformanceDescriptors.Where(descriptor => descriptor.WriteSpeed > 0))
if(descriptor.RotationControl == 0)
sb.AppendFormat("\tDrive supports writing at {0} Kbyte/sec. in CLV mode", descriptor.WriteSpeed)
.AppendLine();
sb.AppendFormat("\tDrive supports writing at {0} Kbyte/sec. in CLV mode",
descriptor.WriteSpeed).AppendLine();
else if(descriptor.RotationControl == 1)
sb.AppendFormat("\tDrive supports writing at is {0} Kbyte/sec. in pure CAV mode",
descriptor.WriteSpeed).AppendLine();
if(page.TestWrite) sb.AppendLine("\tDrive supports test writing");
if(page.TestWrite)
sb.AppendLine("\tDrive supports test writing");
if(page.ReadBarcode) sb.AppendLine("\tDrive can read barcode");
if(page.ReadBarcode)
sb.AppendLine("\tDrive can read barcode");
if(page.SCC) sb.AppendLine("\tDrive can read both sides of a disc");
if(page.LeadInPW) sb.AppendLine("\tDrive an read raw R-W subchannel from the Lead-In");
if(page.SCC)
sb.AppendLine("\tDrive can read both sides of a disc");
if(page.CMRSupported == 1) sb.AppendLine("\tDrive supports DVD CSS and/or DVD CPPM");
if(page.LeadInPW)
sb.AppendLine("\tDrive an read raw R-W subchannel from the Lead-In");
if(page.BUF) sb.AppendLine("\tDrive supports buffer under-run free recording");
if(page.CMRSupported == 1)
sb.AppendLine("\tDrive supports DVD CSS and/or DVD CPPM");
if(page.BUF)
sb.AppendLine("\tDrive supports buffer under-run free recording");
return sb.ToString();
}

View File

@@ -35,18 +35,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "UnassignedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global")]
public static partial class Modes
{
#region IBM Mode Page 0x2F: Behaviour Configuration Mode page
public struct IBM_ModePage_2F
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public byte FenceBehaviour;
public byte CleanBehaviour;
@@ -63,27 +59,28 @@ namespace DiscImageChef.Decoders.SCSI
public static IBM_ModePage_2F? DecodeIBMModePage_2F(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x2F) return null;
if((pageResponse?[0] & 0x3F) != 0x2F)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length < 8) return null;
if(pageResponse.Length < 8)
return null;
return new IBM_ModePage_2F
{
PS = (pageResponse[0] & 0x80) == 0x80,
FenceBehaviour = pageResponse[2],
CleanBehaviour = pageResponse[3],
WORMEmulation = pageResponse[4],
SenseDataBehaviour = pageResponse[5],
CCDM = (pageResponse[6] & 0x04) == 0x04,
DDEOR = (pageResponse[6] & 0x02) == 0x02,
CLNCHK = (pageResponse[6] & 0x01) == 0x01,
FirmwareUpdateBehaviour = pageResponse[7],
UOE_C = (byte)((pageResponse[8] & 0x30) >> 4),
UOE_F = (byte)((pageResponse[8] & 0x0C) >> 2)
PS = (pageResponse[0] & 0x80) == 0x80, FenceBehaviour = pageResponse[2],
CleanBehaviour = pageResponse[3], WORMEmulation = pageResponse[4],
SenseDataBehaviour = pageResponse[5],
CCDM = (pageResponse[6] & 0x04) == 0x04,
DDEOR = (pageResponse[6] & 0x02) == 0x02,
CLNCHK = (pageResponse[6] & 0x01) == 0x01, FirmwareUpdateBehaviour = pageResponse[7],
UOE_C = (byte)((pageResponse[8] & 0x30) >> 4),
UOE_F = (byte)((pageResponse[8] & 0x0C) >> 2)
};
}
@@ -92,25 +89,30 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyIBMModePage_2F(IBM_ModePage_2F? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
IBM_ModePage_2F page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("IBM Behaviour Configuration Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.FenceBehaviour)
{
case 0:
sb.AppendLine("\tFence behaviour is normal");
break;
case 1:
sb.AppendLine("\tPanic fence behaviour is enabled");
break;
default:
sb.AppendFormat("\tUnknown fence behaviour code {0}", page.FenceBehaviour).AppendLine();
break;
}
@@ -118,12 +120,15 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tCleaning behaviour is normal");
break;
case 1:
sb.AppendLine("\tDrive will periodically request cleaning");
break;
default:
sb.AppendFormat("\tUnknown cleaning behaviour code {0}", page.CleanBehaviour).AppendLine();
break;
}
@@ -131,12 +136,15 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tWORM emulation is disabled");
break;
case 1:
sb.AppendLine("\tWORM emulation is enabled");
break;
default:
sb.AppendFormat("\tUnknown WORM emulation code {0}", page.WORMEmulation).AppendLine();
break;
}
@@ -144,24 +152,38 @@ namespace DiscImageChef.Decoders.SCSI
{
case 0:
sb.AppendLine("\tUses 35-bytes sense data");
break;
case 1:
sb.AppendLine("\tUses 96-bytes sense data");
break;
default:
sb.AppendFormat("\tUnknown sense data behaviour code {0}", page.WORMEmulation).AppendLine();
break;
}
if(page.CLNCHK) sb.AppendLine("\tDrive will set Check Condition when cleaning is needed");
if(page.DDEOR) sb.AppendLine("\tNo deferred error will be reported to a rewind command");
if(page.CCDM) sb.AppendLine("\tDrive will set Check Condition when the criteria for Dead Media is met");
if(page.CLNCHK)
sb.AppendLine("\tDrive will set Check Condition when cleaning is needed");
if(page.DDEOR)
sb.AppendLine("\tNo deferred error will be reported to a rewind command");
if(page.CCDM)
sb.AppendLine("\tDrive will set Check Condition when the criteria for Dead Media is met");
if(page.FirmwareUpdateBehaviour > 0)
sb.AppendLine("\tDrive will not accept downlevel firmware via an FMR tape");
if(page.UOE_C == 1) sb.AppendLine("\tDrive will eject cleaning cartridges on error");
if(page.UOE_F == 1) sb.AppendLine("\tDrive will eject firmware cartridges on error");
if(page.UOE_D == 1) sb.AppendLine("\tDrive will eject data cartridges on error");
if(page.UOE_C == 1)
sb.AppendLine("\tDrive will eject cleaning cartridges on error");
if(page.UOE_F == 1)
sb.AppendLine("\tDrive will eject firmware cartridges on error");
if(page.UOE_D == 1)
sb.AppendLine("\tDrive will eject data cartridges on error");
return sb.ToString();
}

View File

@@ -36,27 +36,30 @@ using System.Linq;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region Apple Mode Page 0x30: Apple OEM String
static readonly byte[] AppleOEMString =
{
0x41, 0x50, 0x50, 0x4C, 0x45, 0x20, 0x43, 0x4F, 0x4D, 0x50, 0x55, 0x54, 0x45, 0x52, 0x2C, 0x20, 0x49,
0x4E, 0x43, 0x2E
0x41, 0x50, 0x50, 0x4C, 0x45, 0x20, 0x43, 0x4F, 0x4D, 0x50, 0x55, 0x54, 0x45, 0x52, 0x2C, 0x20, 0x49, 0x4E,
0x43, 0x2E
};
public static bool IsAppleModePage_30(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return false;
if((pageResponse?[0] & 0x40) == 0x40)
return false;
if((pageResponse?[0] & 0x3F) != 0x30) return false;
if((pageResponse?[0] & 0x3F) != 0x30)
return false;
if(pageResponse[1] + 2 != pageResponse.Length) return false;
if(pageResponse[1] + 2 != pageResponse.Length)
return false;
if(pageResponse.Length != 30) return false;
if(pageResponse.Length != 30)
return false;
byte[] str = new byte[20];
Array.Copy(pageResponse, 10, str, 0, 20);

View File

@@ -36,17 +36,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region HP Mode Page 0x3B: Serial Number Override Mode page
public struct HP_ModePage_3B
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public byte MSN;
public byte[] SerialNumber;
@@ -54,15 +51,19 @@ namespace DiscImageChef.Decoders.SCSI
public static HP_ModePage_3B? DecodeHPModePage_3B(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x3B) return null;
if((pageResponse?[0] & 0x3F) != 0x3B)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 16) return null;
if(pageResponse.Length != 16)
return null;
HP_ModePage_3B decoded = new HP_ModePage_3B();
var decoded = new HP_ModePage_3B();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.MSN = (byte)(pageResponse[2] & 0x03);
@@ -77,22 +78,26 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyHPModePage_3B(HP_ModePage_3B? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
HP_ModePage_3B page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("HP Serial Number Override Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.MSN)
{
case 1:
sb.AppendLine("\tSerial number is the manufacturer's default value");
break;
case 3:
sb.AppendLine("\tSerial number is not the manufacturer's default value");
break;
}

View File

@@ -36,17 +36,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region HP Mode Page 0x3C: Device Time Mode page
public struct HP_ModePage_3C
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public bool LT;
public bool WT;
@@ -64,30 +61,39 @@ namespace DiscImageChef.Decoders.SCSI
public static HP_ModePage_3C? DecodeHPModePage_3C(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x3C) return null;
if((pageResponse?[0] & 0x3F) != 0x3C)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 36) return null;
if(pageResponse.Length != 36)
return null;
HP_ModePage_3C decoded = new HP_ModePage_3C();
var decoded = new HP_ModePage_3C();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.LT |= (pageResponse[2] & 0x04) == 0x04;
decoded.WT |= (pageResponse[2] & 0x02) == 0x02;
decoded.PT |= (pageResponse[2] & 0x01) == 0x01;
decoded.CurrentPowerOn = (ushort)((pageResponse[6] << 8) + pageResponse[7]);
decoded.PowerOnTime = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + (pageResponse[10] << 8) +
pageResponse[11]);
decoded.UTC |= (pageResponse[14] & 0x02) == 0x02;
decoded.NTP |= (pageResponse[14] & 0x01) == 0x01;
decoded.WorldTime = (uint)((pageResponse[16] << 24) + (pageResponse[17] << 16) + (pageResponse[18] << 8) +
pageResponse[19]);
decoded.LibraryHours = pageResponse[23];
decoded.LibraryMinutes = pageResponse[24];
decoded.LibrarySeconds = pageResponse[25];
decoded.CumulativePowerOn = (uint)((pageResponse[32] << 24) + (pageResponse[33] << 16) +
(pageResponse[34] << 8) + pageResponse[35]);
@@ -99,30 +105,38 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyHPModePage_3C(HP_ModePage_3C? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
HP_ModePage_3C page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("HP Device Time Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.PT)
{
sb.AppendFormat("\tDrive has been powered up {0} times", page.CurrentPowerOn);
sb.AppendFormat("\tDrive has been powered up since {0} this time",
TimeSpan.FromSeconds(page.PowerOnTime)).AppendLine();
sb.AppendFormat("\tDrive has been powered up a total of {0}",
TimeSpan.FromSeconds(page.CumulativePowerOn)).AppendLine();
}
if(page.WT)
{
sb.AppendFormat("\tDrive's date/time is: {0}", DateHandlers.UnixUnsignedToDateTime(page.WorldTime))
.AppendLine();
if(page.UTC) sb.AppendLine("\tDrive's time is UTC");
if(page.NTP) sb.AppendLine("\tDrive's time is synchronized with a NTP source");
sb.AppendFormat("\tDrive's date/time is: {0}", DateHandlers.UnixUnsignedToDateTime(page.WorldTime)).
AppendLine();
if(page.UTC)
sb.AppendLine("\tDrive's time is UTC");
if(page.NTP)
sb.AppendLine("\tDrive's time is synchronized with a NTP source");
}
if(page.LT)

View File

@@ -35,32 +35,33 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region HP Mode Page 0x3D: Extended Reset Mode page
public struct HP_ModePage_3D
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public byte ResetBehaviour;
}
public static HP_ModePage_3D? DecodeHPModePage_3D(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x3D) return null;
if((pageResponse?[0] & 0x3F) != 0x3D)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 4) return null;
if(pageResponse.Length != 4)
return null;
HP_ModePage_3D decoded = new HP_ModePage_3D();
var decoded = new HP_ModePage_3D();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.ResetBehaviour = (byte)(pageResponse[2] & 0x03);
@@ -73,25 +74,30 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyHPModePage_3D(HP_ModePage_3D? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
HP_ModePage_3D page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("HP Extended Reset Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
switch(page.ResetBehaviour)
{
case 0:
sb.AppendLine("\tNormal reset behaviour");
break;
case 1:
sb.AppendLine("\tDrive will flush and position itself on a LUN or target reset");
break;
case 2:
sb.AppendLine("\tDrive will maintain position on a LUN or target reset");
break;
}

View File

@@ -35,32 +35,33 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region IBM Mode Page 0x3D: Behaviour Configuration Mode page
public struct IBM_ModePage_3D
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public ushort NumberOfWraps;
}
public static IBM_ModePage_3D? DecodeIBMModePage_3D(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x3D) return null;
if((pageResponse?[0] & 0x3F) != 0x3D)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 5) return null;
if(pageResponse.Length != 5)
return null;
IBM_ModePage_3D decoded = new IBM_ModePage_3D();
var decoded = new IBM_ModePage_3D();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.NumberOfWraps = (ushort)((pageResponse[3] << 8) + pageResponse[4]);
@@ -73,14 +74,16 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyIBMModePage_3D(IBM_ModePage_3D? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
IBM_ModePage_3D page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("IBM LEOT Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendFormat("\t{0} wraps", page.NumberOfWraps).AppendLine();

View File

@@ -36,68 +36,51 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "NotAccessedField.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")]
public static partial class Modes
{
#region Fujitsu Mode Page 0x3E: Verify Control page
public enum Fujitsu_VerifyModes : byte
{
/// <summary>
/// Always verify after writing
/// </summary>
Always = 0,
/// <summary>
/// Never verify after writing
/// </summary>
Never = 1,
/// <summary>
/// Verify after writing depending on condition
/// </summary>
Depends = 2,
Reserved = 4
/// <summary>Always verify after writing</summary>
Always = 0, /// <summary>Never verify after writing</summary>
Never = 1, /// <summary>Verify after writing depending on condition</summary>
Depends = 2, Reserved = 4
}
public struct Fujitsu_ModePage_3E
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
/// <summary>
/// If set, AV data support mode is applied
/// </summary>
/// <summary>If set, AV data support mode is applied</summary>
public bool audioVisualMode;
/// <summary>
/// If set the test write operation is restricted
/// </summary>
/// <summary>If set the test write operation is restricted</summary>
public bool streamingMode;
public byte Reserved1;
/// <summary>
/// Verify mode for WRITE commands
/// </summary>
/// <summary>Verify mode for WRITE commands</summary>
public Fujitsu_VerifyModes verifyMode;
public byte Reserved2;
/// <summary>
/// Device type provided in response to INQUIRY
/// </summary>
/// <summary>Device type provided in response to INQUIRY</summary>
public PeripheralDeviceTypes devType;
public byte[] Reserved3;
}
public static Fujitsu_ModePage_3E? DecodeFujitsuModePage_3E(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x3E) return null;
if((pageResponse?[0] & 0x3F) != 0x3E)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 8) return null;
if(pageResponse.Length != 8)
return null;
Fujitsu_ModePage_3E decoded = new Fujitsu_ModePage_3E();
var decoded = new Fujitsu_ModePage_3E();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
@@ -120,16 +103,20 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyFujitsuModePage_3E(Fujitsu_ModePage_3E? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
Fujitsu_ModePage_3E page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("Fujitsu Verify Control Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
if(page.audioVisualMode)
sb.AppendLine("\tAudio/Visual data support mode is applied");
if(page.audioVisualMode) sb.AppendLine("\tAudio/Visual data support mode is applied");
if(page.streamingMode)
sb.AppendLine("\tTest write operation is restricted during read or write operations.");
@@ -137,17 +124,20 @@ namespace DiscImageChef.Decoders.SCSI
{
case Fujitsu_VerifyModes.Always:
sb.AppendLine("\tAlways apply the verify operation");
break;
case Fujitsu_VerifyModes.Never:
sb.AppendLine("\tNever apply the verify operation");
break;
case Fujitsu_VerifyModes.Depends:
sb.AppendLine("\tApply the verify operation depending on the condition");
break;
}
sb.AppendFormat("\tThe device type that would be provided in the INQUIRY response is {0}", page.devType)
.AppendLine();
sb.AppendFormat("\tThe device type that would be provided in the INQUIRY response is {0}", page.devType).
AppendLine();
return sb.ToString();
}

View File

@@ -35,17 +35,14 @@ using System.Text;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
#region HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page
public struct HP_ModePage_3E
{
/// <summary>
/// Parameters can be saved
/// </summary>
/// <summary>Parameters can be saved</summary>
public bool PS;
public bool NonAuto;
public bool CDmode;
@@ -53,15 +50,19 @@ namespace DiscImageChef.Decoders.SCSI
public static HP_ModePage_3E? DecodeHPModePage_3E(byte[] pageResponse)
{
if((pageResponse?[0] & 0x40) == 0x40) return null;
if((pageResponse?[0] & 0x40) == 0x40)
return null;
if((pageResponse?[0] & 0x3F) != 0x3E) return null;
if((pageResponse?[0] & 0x3F) != 0x3E)
return null;
if(pageResponse[1] + 2 != pageResponse.Length) return null;
if(pageResponse[1] + 2 != pageResponse.Length)
return null;
if(pageResponse.Length != 4) return null;
if(pageResponse.Length != 4)
return null;
HP_ModePage_3E decoded = new HP_ModePage_3E();
var decoded = new HP_ModePage_3E();
decoded.PS |= (pageResponse[0] & 0x80) == 0x80;
decoded.NonAuto |= (pageResponse[2] & 0x02) == 0x02;
@@ -75,19 +76,22 @@ namespace DiscImageChef.Decoders.SCSI
public static string PrettifyHPModePage_3E(HP_ModePage_3E? modePage)
{
if(!modePage.HasValue) return null;
if(!modePage.HasValue)
return null;
HP_ModePage_3E page = modePage.Value;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
sb.AppendLine("HP CD-ROM Emulation/Disaster Recovery Mode Page:");
if(page.PS) sb.AppendLine("\tParameters can be saved");
if(page.PS)
sb.AppendLine("\tParameters can be saved");
sb.AppendLine(page.CDmode
? "\tDrive is emulating a CD-ROM drive"
sb.AppendLine(page.CDmode ? "\tDrive is emulating a CD-ROM drive"
: "\tDrive is not emulating a CD-ROM drive");
if(page.NonAuto) sb.AppendLine("\tDrive will not exit emulation automatically");
if(page.NonAuto)
sb.AppendLine("\tDrive will not exit emulation automatically");
return sb.ToString();
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,21 +37,26 @@ using System.Linq;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
public static ModeHeader? DecodeModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
if(modeResponse == null || modeResponse.Length < 8) return null;
if(modeResponse == null ||
modeResponse.Length < 8)
return null;
ushort modeLength = (ushort)((modeResponse[0] << 8) + modeResponse[1]);
ushort blockDescLength = (ushort)((modeResponse[6] << 8) + modeResponse[7]);
if(modeResponse.Length < modeLength) return null;
if(modeResponse.Length < modeLength)
return null;
ModeHeader header = new ModeHeader {MediumType = (MediumTypes)modeResponse[2]};
var header = new ModeHeader
{
MediumType = (MediumTypes)modeResponse[2]
};
bool longLBA = (modeResponse[4] & 0x01) == 0x01;
@@ -59,11 +64,17 @@ namespace DiscImageChef.Decoders.SCSI
if(longLBA)
{
header.BlockDescriptors = new BlockDescriptor[blockDescLength / 16];
for(int i = 0; i < header.BlockDescriptors.Length; i++)
{
if(12 + i * 16 + 8 >= modeResponse.Length) break;
if(12 + i * 16 + 8 >= modeResponse.Length)
break;
header.BlockDescriptors[i] = new BlockDescriptor
{
Density = DensityType.Default
};
header.BlockDescriptors[i] = new BlockDescriptor {Density = DensityType.Default};
byte[] temp = new byte[8];
temp[0] = modeResponse[7 + i * 16 + 8];
temp[1] = modeResponse[6 + i * 16 + 8];
@@ -83,11 +94,14 @@ namespace DiscImageChef.Decoders.SCSI
else
{
header.BlockDescriptors = new BlockDescriptor[blockDescLength / 8];
for(int i = 0; i < header.BlockDescriptors.Length; i++)
{
if(7 + i * 8 + 8 >= modeResponse.Length) break;
if(7 + i * 8 + 8 >= modeResponse.Length)
break;
header.BlockDescriptors[i] = new BlockDescriptor();
if(deviceType != PeripheralDeviceTypes.DirectAccess)
header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 8];
else
@@ -111,19 +125,23 @@ namespace DiscImageChef.Decoders.SCSI
case PeripheralDeviceTypes.MultiMediaDevice:
header.WriteProtected = (modeResponse[3] & 0x80) == 0x80;
header.DPOFUA = (modeResponse[3] & 0x10) == 0x10;
break;
case PeripheralDeviceTypes.SequentialAccess:
header.WriteProtected = (modeResponse[3] & 0x80) == 0x80;
header.Speed = (byte)(modeResponse[3] & 0x0F);
header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4);
break;
case PeripheralDeviceTypes.PrinterDevice:
header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4);
break;
case PeripheralDeviceTypes.OpticalDevice:
header.WriteProtected = (modeResponse[3] & 0x80) == 0x80;
header.EBC = (modeResponse[3] & 0x01) == 0x01;
header.DPOFUA = (modeResponse[3] & 0x10) == 0x10;
break;
}
@@ -136,29 +154,41 @@ namespace DiscImageChef.Decoders.SCSI
public static DecodedMode? DecodeMode10(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
ModeHeader? hdr = DecodeModeHeader10(modeResponse, deviceType);
if(!hdr.HasValue) return null;
DecodedMode decoded = new DecodedMode {Header = hdr.Value};
bool longlba = (modeResponse[4] & 0x01) == 0x01;
int offset;
int blkDrLength = 0;
if(decoded.Header.BlockDescriptors != null) blkDrLength = decoded.Header.BlockDescriptors.Length;
if(!hdr.HasValue)
return null;
var decoded = new DecodedMode
{
Header = hdr.Value
};
bool longlba = (modeResponse[4] & 0x01) == 0x01;
int offset;
int blkDrLength = 0;
if(decoded.Header.BlockDescriptors != null)
blkDrLength = decoded.Header.BlockDescriptors.Length;
if(longlba)
offset = 8 + blkDrLength * 16;
else
offset = 8 + blkDrLength * 8;
if(longlba) offset = 8 + blkDrLength * 16;
else offset = 8 + blkDrLength * 8;
int length = modeResponse[0] << 8;
length += modeResponse[1];
length += 2;
if(length != modeResponse.Length) return decoded;
if(length != modeResponse.Length)
return decoded;
List<ModePage> listpages = new List<ModePage>();
while(offset < modeResponse.Length)
{
bool isSubpage = (modeResponse[offset] & 0x40) == 0x40;
ModePage pg = new ModePage();
byte pageNo = (byte)(modeResponse[offset] & 0x3F);
bool isSubpage = (modeResponse[offset] & 0x40) == 0x40;
var pg = new ModePage();
byte pageNo = (byte)(modeResponse[offset] & 0x3F);
if(pageNo == 0)
{
@@ -174,7 +204,8 @@ namespace DiscImageChef.Decoders.SCSI
{
pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4];
if(pg.PageResponse.Length + offset > modeResponse.Length) return decoded;
if(pg.PageResponse.Length + offset > modeResponse.Length)
return decoded;
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
@@ -185,7 +216,8 @@ namespace DiscImageChef.Decoders.SCSI
{
pg.PageResponse = new byte[modeResponse[offset + 1] + 2];
if(pg.PageResponse.Length + offset > modeResponse.Length) return decoded;
if(pg.PageResponse.Length + offset > modeResponse.Length)
return decoded;
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
@@ -203,15 +235,15 @@ namespace DiscImageChef.Decoders.SCSI
}
public static byte[] EncodeModeHeader10(ModeHeader header, PeripheralDeviceTypes deviceType,
bool longLBA = false)
bool longLBA = false)
{
byte[] hdr;
if(header.BlockDescriptors != null)
hdr = longLBA
? new byte[8 + header.BlockDescriptors.Length * 16]
: new byte[8 + header.BlockDescriptors.Length * 8];
else hdr = new byte[8];
hdr = longLBA ? new byte[8 + header.BlockDescriptors.Length * 16]
: new byte[8 + header.BlockDescriptors.Length * 8];
else
hdr = new byte[8];
hdr[2] = (byte)header.MediumType;
@@ -219,27 +251,43 @@ namespace DiscImageChef.Decoders.SCSI
{
case PeripheralDeviceTypes.DirectAccess:
case PeripheralDeviceTypes.MultiMediaDevice:
if(header.WriteProtected) hdr[3] += 0x80;
if(header.DPOFUA) hdr[3] += 0x10;
if(header.WriteProtected)
hdr[3] += 0x80;
if(header.DPOFUA)
hdr[3] += 0x10;
break;
case PeripheralDeviceTypes.SequentialAccess:
if(header.WriteProtected) hdr[3] += 0x80;
if(header.WriteProtected)
hdr[3] += 0x80;
hdr[3] += (byte)(header.Speed & 0x0F);
hdr[3] += (byte)((header.BufferedMode << 4) & 0x70);
break;
case PeripheralDeviceTypes.PrinterDevice:
hdr[3] += (byte)((header.BufferedMode << 4) & 0x70);
break;
case PeripheralDeviceTypes.OpticalDevice:
if(header.WriteProtected) hdr[3] += 0x80;
if(header.EBC) hdr[3] += 0x01;
if(header.DPOFUA) hdr[3] += 0x10;
if(header.WriteProtected)
hdr[3] += 0x80;
if(header.EBC)
hdr[3] += 0x01;
if(header.DPOFUA)
hdr[3] += 0x10;
break;
}
if(longLBA) hdr[4] += 0x01;
if(longLBA)
hdr[4] += 0x01;
if(header.BlockDescriptors == null) return hdr;
if(header.BlockDescriptors == null)
return hdr;
if(longLBA)
for(int i = 0; i < header.BlockDescriptors.Length; i++)
@@ -262,8 +310,10 @@ namespace DiscImageChef.Decoders.SCSI
for(int i = 0; i < header.BlockDescriptors.Length; i++)
{
if(deviceType != PeripheralDeviceTypes.DirectAccess)
hdr[0 + i * 8 + 8] = (byte)header.BlockDescriptors[i].Density;
else hdr[0 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF000000) >> 24);
hdr[0 + i * 8 + 8] = (byte)header.BlockDescriptors[i].Density;
else
hdr[0 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF000000) >> 24);
hdr[1 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF0000) >> 16);
hdr[2 + i * 8 + 8] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF00) >> 8);
hdr[3 + i * 8 + 8] = (byte)(header.BlockDescriptors[i].Blocks & 0xFF);
@@ -277,8 +327,10 @@ namespace DiscImageChef.Decoders.SCSI
public static byte[] EncodeMode10(DecodedMode mode, PeripheralDeviceTypes deviceType)
{
int modeSize = 0;
if(mode.Pages != null) modeSize += mode.Pages.Sum(page => page.PageResponse.Length);
int modeSize = 0;
if(mode.Pages != null)
modeSize += mode.Pages.Sum(page => page.PageResponse.Length);
byte[] hdr = EncodeModeHeader10(mode.Header, deviceType);
modeSize += hdr.Length;
@@ -286,10 +338,12 @@ namespace DiscImageChef.Decoders.SCSI
Array.Copy(hdr, 0, md, 0, hdr.Length);
if(mode.Pages == null) return md;
if(mode.Pages == null)
return md;
{
int offset = hdr.Length;
foreach(ModePage page in mode.Pages)
{
Array.Copy(page.PageResponse, 0, md, offset, page.PageResponse.Length);

View File

@@ -37,21 +37,26 @@ using System.Linq;
namespace DiscImageChef.Decoders.SCSI
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"),
SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static partial class Modes
{
public static ModeHeader? DecodeModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
if(modeResponse == null || modeResponse.Length < 4 || modeResponse.Length < modeResponse[0] + 1)
if(modeResponse == null ||
modeResponse.Length < 4 ||
modeResponse.Length < modeResponse[0] + 1)
return null;
ModeHeader header = new ModeHeader {MediumType = (MediumTypes)modeResponse[1]};
var header = new ModeHeader
{
MediumType = (MediumTypes)modeResponse[1]
};
if(modeResponse[3] > 0)
{
header.BlockDescriptors = new BlockDescriptor[modeResponse[3] / 8];
for(int i = 0; i < header.BlockDescriptors.Length; i++)
{
header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + i * 8 + 4];
@@ -70,19 +75,23 @@ namespace DiscImageChef.Decoders.SCSI
case PeripheralDeviceTypes.MultiMediaDevice:
header.WriteProtected = (modeResponse[2] & 0x80) == 0x80;
header.DPOFUA = (modeResponse[2] & 0x10) == 0x10;
break;
case PeripheralDeviceTypes.SequentialAccess:
header.WriteProtected = (modeResponse[2] & 0x80) == 0x80;
header.Speed = (byte)(modeResponse[2] & 0x0F);
header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4);
break;
case PeripheralDeviceTypes.PrinterDevice:
header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4);
break;
case PeripheralDeviceTypes.OpticalDevice:
header.WriteProtected = (modeResponse[2] & 0x80) == 0x80;
header.EBC = (modeResponse[2] & 0x01) == 0x01;
header.DPOFUA = (modeResponse[2] & 0x10) == 0x10;
break;
}
@@ -95,24 +104,33 @@ namespace DiscImageChef.Decoders.SCSI
public static DecodedMode? DecodeMode6(byte[] modeResponse, PeripheralDeviceTypes deviceType)
{
ModeHeader? hdr = DecodeModeHeader6(modeResponse, deviceType);
if(!hdr.HasValue) return null;
DecodedMode decoded = new DecodedMode {Header = hdr.Value};
int blkDrLength = 0;
if(decoded.Header.BlockDescriptors != null) blkDrLength = decoded.Header.BlockDescriptors.Length;
if(!hdr.HasValue)
return null;
var decoded = new DecodedMode
{
Header = hdr.Value
};
int blkDrLength = 0;
if(decoded.Header.BlockDescriptors != null)
blkDrLength = decoded.Header.BlockDescriptors.Length;
int offset = 4 + blkDrLength * 8;
int length = modeResponse[0] + 1;
if(length != modeResponse.Length) return decoded;
if(length != modeResponse.Length)
return decoded;
List<ModePage> listpages = new List<ModePage>();
while(offset < modeResponse.Length)
{
bool isSubpage = (modeResponse[offset] & 0x40) == 0x40;
ModePage pg = new ModePage();
byte pageNo = (byte)(modeResponse[offset] & 0x3F);
bool isSubpage = (modeResponse[offset] & 0x40) == 0x40;
var pg = new ModePage();
byte pageNo = (byte)(modeResponse[offset] & 0x3F);
if(pageNo == 0)
{
@@ -126,10 +144,13 @@ namespace DiscImageChef.Decoders.SCSI
{
if(isSubpage)
{
if(offset + 3 >= modeResponse.Length) break;
if(offset + 3 >= modeResponse.Length)
break;
pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4];
if(pg.PageResponse.Length + offset > modeResponse.Length) return decoded;
if(pg.PageResponse.Length + offset > modeResponse.Length)
return decoded;
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
@@ -138,10 +159,13 @@ namespace DiscImageChef.Decoders.SCSI
}
else
{
if(offset + 1 >= modeResponse.Length) break;
if(offset + 1 >= modeResponse.Length)
break;
pg.PageResponse = new byte[modeResponse[offset + 1] + 2];
if(pg.PageResponse.Length + offset > modeResponse.Length) return decoded;
if(pg.PageResponse.Length + offset > modeResponse.Length)
return decoded;
Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length);
pg.Page = (byte)(modeResponse[offset] & 0x3F);
@@ -160,8 +184,7 @@ namespace DiscImageChef.Decoders.SCSI
public static byte[] EncodeModeHeader6(ModeHeader header, PeripheralDeviceTypes deviceType)
{
byte[] hdr = header.BlockDescriptors != null
? new byte[4 + header.BlockDescriptors.Length * 8]
byte[] hdr = header.BlockDescriptors != null ? new byte[4 + header.BlockDescriptors.Length * 8]
: new byte[4];
hdr[1] = (byte)header.MediumType;
@@ -170,25 +193,40 @@ namespace DiscImageChef.Decoders.SCSI
{
case PeripheralDeviceTypes.DirectAccess:
case PeripheralDeviceTypes.MultiMediaDevice:
if(header.WriteProtected) hdr[2] += 0x80;
if(header.DPOFUA) hdr[2] += 0x10;
if(header.WriteProtected)
hdr[2] += 0x80;
if(header.DPOFUA)
hdr[2] += 0x10;
break;
case PeripheralDeviceTypes.SequentialAccess:
if(header.WriteProtected) hdr[2] += 0x80;
if(header.WriteProtected)
hdr[2] += 0x80;
hdr[2] += (byte)(header.Speed & 0x0F);
hdr[2] += (byte)((header.BufferedMode << 4) & 0x70);
break;
case PeripheralDeviceTypes.PrinterDevice:
hdr[2] += (byte)((header.BufferedMode << 4) & 0x70);
break;
case PeripheralDeviceTypes.OpticalDevice:
if(header.WriteProtected) hdr[2] += 0x80;
if(header.EBC) hdr[2] += 0x01;
if(header.DPOFUA) hdr[2] += 0x10;
if(header.WriteProtected)
hdr[2] += 0x80;
if(header.EBC)
hdr[2] += 0x01;
if(header.DPOFUA)
hdr[2] += 0x10;
break;
}
if(header.BlockDescriptors == null) return hdr;
if(header.BlockDescriptors == null)
return hdr;
hdr[3] = (byte)(header.BlockDescriptors.Length * 8);
@@ -208,8 +246,10 @@ namespace DiscImageChef.Decoders.SCSI
public static byte[] EncodeMode6(DecodedMode mode, PeripheralDeviceTypes deviceType)
{
int modeSize = 0;
if(mode.Pages != null) modeSize += mode.Pages.Sum(page => page.PageResponse.Length);
int modeSize = 0;
if(mode.Pages != null)
modeSize += mode.Pages.Sum(page => page.PageResponse.Length);
byte[] hdr = EncodeModeHeader6(mode.Header, deviceType);
modeSize += hdr.Length;
@@ -217,10 +257,12 @@ namespace DiscImageChef.Decoders.SCSI
Array.Copy(hdr, 0, md, 0, hdr.Length);
if(mode.Pages == null) return md;
if(mode.Pages == null)
return md;
{
int offset = hdr.Length;
foreach(ModePage page in mode.Pages)
{
Array.Copy(page.PageResponse, 0, md, offset, page.PageResponse.Length);

Some files were not shown because too many files have changed in this diff Show More