diff --git a/ATA/Identify.cs b/ATA/Identify.cs index c37ba6f..27079cf 100644 --- a/ATA/Identify.cs +++ b/ATA/Identify.cs @@ -35,2209 +35,2208 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.CommonTypes.Structs.Devices.SCSI; -namespace Aaru.Decoders.ATA +namespace Aaru.Decoders.ATA; + +// Information from following standards: +// T10-791D rev. 4c (ATA) +// T10-948D rev. 4c (ATA-2) +// T13-1153D rev. 18 (ATA/ATAPI-4) +// T13-1321D rev. 3 (ATA/ATAPI-5) +// T13-1410D rev. 3b (ATA/ATAPI-6) +// T13-1532D rev. 4b (ATA/ATAPI-7) +// T13-1699D rev. 3f (ATA8-ACS) +// T13-1699D rev. 4a (ATA8-ACS) +// T13-2015D rev. 2 (ACS-2) +// T13-2161D rev. 5 (ACS-3) +// CF+ & CF Specification rev. 1.4 (CFA) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Identify { - // Information from following standards: - // T10-791D rev. 4c (ATA) - // T10-948D rev. 4c (ATA-2) - // T13-1153D rev. 18 (ATA/ATAPI-4) - // T13-1321D rev. 3 (ATA/ATAPI-5) - // T13-1410D rev. 3b (ATA/ATAPI-6) - // T13-1532D rev. 4b (ATA/ATAPI-7) - // T13-1699D rev. 3f (ATA8-ACS) - // T13-1699D rev. 4a (ATA8-ACS) - // T13-2015D rev. 2 (ACS-2) - // T13-2161D rev. 5 (ACS-3) - // CF+ & CF Specification rev. 1.4 (CFA) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Identify + public static string Prettify(byte[] IdentifyDeviceResponse) { - public static string Prettify(byte[] IdentifyDeviceResponse) + if(IdentifyDeviceResponse.Length != 512) + return null; + + CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice? decoded = + CommonTypes.Structs.Devices.ATA.Identify.Decode(IdentifyDeviceResponse); + + return Prettify(decoded); + } + + public static string Prettify(CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice? IdentifyDeviceResponse) + { + if(IdentifyDeviceResponse == null) + return null; + + var sb = new StringBuilder(); + + bool atapi = false; + bool cfa = false; + + CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice ATAID = IdentifyDeviceResponse.Value; + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. + NonMagnetic)) + if((ushort)ATAID.GeneralConfiguration != 0x848A) + atapi = true; + else + cfa = true; + + if(atapi) + sb.AppendLine("ATAPI device"); + else if(cfa) + sb.AppendLine("CompactFlash device"); + else + sb.AppendLine("ATA device"); + + if(ATAID.Model != "") + sb.AppendFormat("Model: {0}", ATAID.Model).AppendLine(); + + if(ATAID.FirmwareRevision != "") + sb.AppendFormat("Firmware revision: {0}", ATAID.FirmwareRevision).AppendLine(); + + if(ATAID.SerialNumber != "") + sb.AppendFormat("Serial #: {0}", ATAID.SerialNumber).AppendLine(); + + if(ATAID.AdditionalPID != "") + sb.AppendFormat("Additional product ID: {0}", ATAID.AdditionalPID).AppendLine(); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && + !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear)) { - if(IdentifyDeviceResponse.Length != 512) - return null; + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + MediaSerial)) + { + if(ATAID.MediaManufacturer != "") + sb.AppendFormat("Media manufacturer: {0}", ATAID.MediaManufacturer).AppendLine(); - CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice? decoded = - CommonTypes.Structs.Devices.ATA.Identify.Decode(IdentifyDeviceResponse); + if(ATAID.MediaSerial != "") + sb.AppendFormat("Media serial #: {0}", ATAID.MediaSerial).AppendLine(); + } - return Prettify(decoded); + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WWN)) + sb.AppendFormat("World Wide Name: {0:X16}", ATAID.WWN).AppendLine(); } - public static string Prettify(CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice? IdentifyDeviceResponse) + bool ata1 = false, ata2 = false, ata3 = false, ata4 = false, ata5 = false, ata6 = false, ata7 = false, + acs = false, acs2 = false, acs3 = false, acs4 = false; + + if((ushort)ATAID.MajorVersion == 0x0000 || + (ushort)ATAID.MajorVersion == 0xFFFF) { - if(IdentifyDeviceResponse == null) - return null; + // Obsolete in ATA-2, if present, device supports ATA-1 + ata1 |= + ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. + FastIDE) || + ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. + SlowIDE) || + ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. + UltraFastIDE); - var sb = new StringBuilder(); + ata2 |= ATAID.ExtendedIdentify.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.ExtendedIdentifyBit. + Words64to70Valid); - bool atapi = false; - bool cfa = false; + if(!ata1 && + !ata2 && + !atapi && + !cfa) + ata2 = true; - CommonTypes.Structs.Devices.ATA.Identify.IdentifyDevice ATAID = IdentifyDeviceResponse.Value; + ata4 |= atapi; + ata3 |= cfa; - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. - NonMagnetic)) - if((ushort)ATAID.GeneralConfiguration != 0x848A) - atapi = true; - else - cfa = true; + if(cfa && ata1) + ata1 = false; - if(atapi) - sb.AppendLine("ATAPI device"); - else if(cfa) - sb.AppendLine("CompactFlash device"); - else - sb.AppendLine("ATA device"); + if(cfa && ata2) + ata2 = false; - if(ATAID.Model != "") - sb.AppendFormat("Model: {0}", ATAID.Model).AppendLine(); + ata5 |= ATAID.Signature == 0xA5; + } + else + { + ata1 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata1); + ata2 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata2); + ata3 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata3); + ata4 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi4); + ata5 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi5); + ata6 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi6); + ata7 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi7); + acs |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata8ACS); + acs2 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS2); + acs3 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS3); + acs4 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS4); + } - if(ATAID.FirmwareRevision != "") - sb.AppendFormat("Firmware revision: {0}", ATAID.FirmwareRevision).AppendLine(); + int maxatalevel = 0; + int minatalevel = 255; + sb.Append("Supported ATA versions: "); - if(ATAID.SerialNumber != "") - sb.AppendFormat("Serial #: {0}", ATAID.SerialNumber).AppendLine(); + if(ata1) + { + sb.Append("ATA-1 "); + maxatalevel = 1; + minatalevel = 1; + } - if(ATAID.AdditionalPID != "") - sb.AppendFormat("Additional product ID: {0}", ATAID.AdditionalPID).AppendLine(); + if(ata2) + { + sb.Append("ATA-2 "); + maxatalevel = 2; - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && - !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear)) + if(minatalevel > 2) + minatalevel = 2; + } + + if(ata3) + { + sb.Append("ATA-3 "); + maxatalevel = 3; + + if(minatalevel > 3) + minatalevel = 3; + } + + if(ata4) + { + sb.Append("ATA/ATAPI-4 "); + maxatalevel = 4; + + if(minatalevel > 4) + minatalevel = 4; + } + + if(ata5) + { + sb.Append("ATA/ATAPI-5 "); + maxatalevel = 5; + + if(minatalevel > 5) + minatalevel = 5; + } + + if(ata6) + { + sb.Append("ATA/ATAPI-6 "); + maxatalevel = 6; + + if(minatalevel > 6) + minatalevel = 6; + } + + if(ata7) + { + sb.Append("ATA/ATAPI-7 "); + maxatalevel = 7; + + if(minatalevel > 7) + minatalevel = 7; + } + + if(acs) + { + sb.Append("ATA8-ACS "); + maxatalevel = 8; + + if(minatalevel > 8) + minatalevel = 8; + } + + if(acs2) + { + sb.Append("ATA8-ACS2 "); + maxatalevel = 9; + + if(minatalevel > 9) + minatalevel = 9; + } + + if(acs3) + { + sb.Append("ATA8-ACS3 "); + maxatalevel = 10; + + if(minatalevel > 10) + minatalevel = 10; + } + + if(acs4) + { + sb.Append("ATA8-ACS4 "); + maxatalevel = 11; + + if(minatalevel > 11) + minatalevel = 11; + } + + sb.AppendLine(); + + sb.Append("Maximum ATA revision supported: "); + + if(maxatalevel >= 3) + switch(ATAID.MinorVersion) { - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - MediaSerial)) - { - if(ATAID.MediaManufacturer != "") - sb.AppendFormat("Media manufacturer: {0}", ATAID.MediaManufacturer).AppendLine(); - - if(ATAID.MediaSerial != "") - sb.AppendFormat("Media serial #: {0}", ATAID.MediaSerial).AppendLine(); - } - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WWN)) - sb.AppendFormat("World Wide Name: {0:X16}", ATAID.WWN).AppendLine(); - } - - bool ata1 = false, ata2 = false, ata3 = false, ata4 = false, ata5 = false, ata6 = false, ata7 = false, - acs = false, acs2 = false, acs3 = false, acs4 = false; - - if((ushort)ATAID.MajorVersion == 0x0000 || - (ushort)ATAID.MajorVersion == 0xFFFF) - { - // Obsolete in ATA-2, if present, device supports ATA-1 - ata1 |= - ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. - FastIDE) || - ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. - SlowIDE) || - ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. - UltraFastIDE); - - ata2 |= ATAID.ExtendedIdentify.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.ExtendedIdentifyBit. - Words64to70Valid); - - if(!ata1 && - !ata2 && - !atapi && - !cfa) - ata2 = true; - - ata4 |= atapi; - ata3 |= cfa; - - if(cfa && ata1) - ata1 = false; - - if(cfa && ata2) - ata2 = false; - - ata5 |= ATAID.Signature == 0xA5; - } - else - { - ata1 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata1); - ata2 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata2); - ata3 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata3); - ata4 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi4); - ata5 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi5); - ata6 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi6); - ata7 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.AtaAtapi7); - acs |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.Ata8ACS); - acs2 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS2); - acs3 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS3); - acs4 |= ATAID.MajorVersion.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.MajorVersionBit.ACS4); - } - - int maxatalevel = 0; - int minatalevel = 255; - sb.Append("Supported ATA versions: "); - - if(ata1) - { - sb.Append("ATA-1 "); - maxatalevel = 1; - minatalevel = 1; - } - - if(ata2) - { - sb.Append("ATA-2 "); - maxatalevel = 2; - - if(minatalevel > 2) - minatalevel = 2; - } - - if(ata3) - { - sb.Append("ATA-3 "); - maxatalevel = 3; - - if(minatalevel > 3) - minatalevel = 3; - } - - if(ata4) - { - sb.Append("ATA/ATAPI-4 "); - maxatalevel = 4; - - if(minatalevel > 4) - minatalevel = 4; - } - - if(ata5) - { - sb.Append("ATA/ATAPI-5 "); - maxatalevel = 5; - - if(minatalevel > 5) - minatalevel = 5; - } - - if(ata6) - { - sb.Append("ATA/ATAPI-6 "); - maxatalevel = 6; - - if(minatalevel > 6) - minatalevel = 6; - } - - if(ata7) - { - sb.Append("ATA/ATAPI-7 "); - maxatalevel = 7; - - if(minatalevel > 7) - minatalevel = 7; - } - - if(acs) - { - sb.Append("ATA8-ACS "); - maxatalevel = 8; - - if(minatalevel > 8) - minatalevel = 8; - } - - if(acs2) - { - sb.Append("ATA8-ACS2 "); - maxatalevel = 9; - - if(minatalevel > 9) - minatalevel = 9; - } - - if(acs3) - { - sb.Append("ATA8-ACS3 "); - maxatalevel = 10; - - if(minatalevel > 10) - minatalevel = 10; - } - - if(acs4) - { - sb.Append("ATA8-ACS4 "); - maxatalevel = 11; - - if(minatalevel > 11) - minatalevel = 11; - } - - sb.AppendLine(); - - sb.Append("Maximum ATA revision supported: "); - - if(maxatalevel >= 3) - switch(ATAID.MinorVersion) - { - case 0x0000: - case 0xFFFF: - sb.AppendLine("Minor ATA version not specified"); - - break; - case 0x0001: - sb.AppendLine("ATA (ATA-1) X3T9.2 781D prior to revision 4"); - - break; - case 0x0002: - sb.AppendLine("ATA-1 published, ANSI X3.221-1994"); - - break; - case 0x0003: - sb.AppendLine("ATA (ATA-1) X3T9.2 781D revision 4"); - - break; - case 0x0004: - sb.AppendLine("ATA-2 published, ANSI X3.279-1996"); - - break; - case 0x0005: - sb.AppendLine("ATA-2 X3T10 948D prior to revision 2k"); - - break; - case 0x0006: - sb.AppendLine("ATA-3 X3T10 2008D revision 1"); - - break; - case 0x0007: - sb.AppendLine("ATA-2 X3T10 948D revision 2k"); - - break; - case 0x0008: - sb.AppendLine("ATA-3 X3T10 2008D revision 0"); - - break; - case 0x0009: - sb.AppendLine("ATA-2 X3T10 948D revision 3"); - - break; - case 0x000A: - sb.AppendLine("ATA-3 published, ANSI X3.298-1997"); - - break; - case 0x000B: - sb.AppendLine("ATA-3 X3T10 2008D revision 6"); - - break; - case 0x000C: - sb.AppendLine("ATA-3 X3T13 2008D revision 7"); - - break; - case 0x000D: - sb.AppendLine("ATA/ATAPI-4 X3T13 1153D revision 6"); - - break; - case 0x000E: - sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 13"); - - break; - case 0x000F: - sb.AppendLine("ATA/ATAPI-4 X3T13 1153D revision 7"); - - break; - case 0x0010: - sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 18"); - - break; - case 0x0011: - sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 15"); - - break; - case 0x0012: - sb.AppendLine("ATA/ATAPI-4 published, ANSI INCITS 317-1998"); - - break; - case 0x0013: - sb.AppendLine("ATA/ATAPI-5 T13 1321D revision 3"); - - break; - case 0x0014: - sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 14"); - - break; - case 0x0015: - sb.AppendLine("ATA/ATAPI-5 T13 1321D revision 1"); - - break; - case 0x0016: - sb.AppendLine("ATA/ATAPI-5 published, ANSI INCITS 340-2000"); - - break; - case 0x0017: - sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 17"); - - break; - case 0x0018: - sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 0"); - - break; - case 0x0019: - sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 3a"); - - break; - case 0x001A: - sb.AppendLine("ATA/ATAPI-7 T13 1532D revision 1"); - - break; - case 0x001B: - sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 2"); - - break; - case 0x001C: - sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 1"); - - break; - case 0x001D: - sb.AppendLine("ATA/ATAPI-7 published ANSI INCITS 397-2005"); - - break; - case 0x001E: - sb.AppendLine("ATA/ATAPI-7 T13 1532D revision 0"); - - break; - case 0x001F: - sb.AppendLine("ACS-3 Revision 3b"); - - break; - case 0x0021: - sb.AppendLine("ATA/ATAPI-7 T13 1532D revision 4a"); - - break; - case 0x0022: - sb.AppendLine("ATA/ATAPI-6 published, ANSI INCITS 361-2002"); - - break; - case 0x0027: - sb.AppendLine("ATA8-ACS revision 3c"); - - break; - case 0x0028: - sb.AppendLine("ATA8-ACS revision 6"); - - break; - case 0x0029: - sb.AppendLine("ATA8-ACS revision 4"); - - break; - case 0x0031: - sb.AppendLine("ACS-2 Revision 2"); - - break; - case 0x0033: - sb.AppendLine("ATA8-ACS Revision 3e"); - - break; - case 0x0039: - sb.AppendLine("ATA8-ACS Revision 4c"); - - break; - case 0x0042: - sb.AppendLine("ATA8-ACS Revision 3f"); - - break; - case 0x0052: - sb.AppendLine("ATA8-ACS revision 3b"); - - break; - case 0x006D: - sb.AppendLine("ACS-3 Revision 5"); - - break; - case 0x0082: - sb.AppendLine("ACS-2 published, ANSI INCITS 482-2012"); - - break; - case 0x0107: - sb.AppendLine("ATA8-ACS revision 2d"); - - break; - case 0x0110: - sb.AppendLine("ACS-2 Revision 3"); - - break; - case 0x011B: - sb.AppendLine("ACS-3 Revision 4"); - - break; - default: - sb.AppendFormat("Unknown ATA revision 0x{0:X4}", ATAID.MinorVersion).AppendLine(); - - break; - } - - switch((ATAID.TransportMajorVersion & 0xF000) >> 12) - { - case 0x0: - sb.Append("Parallel ATA device: "); - - if((ATAID.TransportMajorVersion & 0x0002) == 0x0002) - sb.Append("ATA/ATAPI-7 "); - - if((ATAID.TransportMajorVersion & 0x0001) == 0x0001) - sb.Append("ATA8-APT "); - - sb.AppendLine(); + case 0x0000: + case 0xFFFF: + sb.AppendLine("Minor ATA version not specified"); break; - case 0x1: - sb.Append("Serial ATA device: "); - - if((ATAID.TransportMajorVersion & 0x0001) == 0x0001) - sb.Append("ATA8-AST "); - - if((ATAID.TransportMajorVersion & 0x0002) == 0x0002) - sb.Append("SATA 1.0a "); - - if((ATAID.TransportMajorVersion & 0x0004) == 0x0004) - sb.Append("SATA II Extensions "); - - if((ATAID.TransportMajorVersion & 0x0008) == 0x0008) - sb.Append("SATA 2.5 "); - - if((ATAID.TransportMajorVersion & 0x0010) == 0x0010) - sb.Append("SATA 2.6 "); - - if((ATAID.TransportMajorVersion & 0x0020) == 0x0020) - sb.Append("SATA 3.0 "); - - if((ATAID.TransportMajorVersion & 0x0040) == 0x0040) - sb.Append("SATA 3.1 "); - - sb.AppendLine(); + case 0x0001: + sb.AppendLine("ATA (ATA-1) X3T9.2 781D prior to revision 4"); break; - case 0xE: - sb.AppendLine("SATA Express device"); + case 0x0002: + sb.AppendLine("ATA-1 published, ANSI X3.221-1994"); + + break; + case 0x0003: + sb.AppendLine("ATA (ATA-1) X3T9.2 781D revision 4"); + + break; + case 0x0004: + sb.AppendLine("ATA-2 published, ANSI X3.279-1996"); + + break; + case 0x0005: + sb.AppendLine("ATA-2 X3T10 948D prior to revision 2k"); + + break; + case 0x0006: + sb.AppendLine("ATA-3 X3T10 2008D revision 1"); + + break; + case 0x0007: + sb.AppendLine("ATA-2 X3T10 948D revision 2k"); + + break; + case 0x0008: + sb.AppendLine("ATA-3 X3T10 2008D revision 0"); + + break; + case 0x0009: + sb.AppendLine("ATA-2 X3T10 948D revision 3"); + + break; + case 0x000A: + sb.AppendLine("ATA-3 published, ANSI X3.298-1997"); + + break; + case 0x000B: + sb.AppendLine("ATA-3 X3T10 2008D revision 6"); + + break; + case 0x000C: + sb.AppendLine("ATA-3 X3T13 2008D revision 7"); + + break; + case 0x000D: + sb.AppendLine("ATA/ATAPI-4 X3T13 1153D revision 6"); + + break; + case 0x000E: + sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 13"); + + break; + case 0x000F: + sb.AppendLine("ATA/ATAPI-4 X3T13 1153D revision 7"); + + break; + case 0x0010: + sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 18"); + + break; + case 0x0011: + sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 15"); + + break; + case 0x0012: + sb.AppendLine("ATA/ATAPI-4 published, ANSI INCITS 317-1998"); + + break; + case 0x0013: + sb.AppendLine("ATA/ATAPI-5 T13 1321D revision 3"); + + break; + case 0x0014: + sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 14"); + + break; + case 0x0015: + sb.AppendLine("ATA/ATAPI-5 T13 1321D revision 1"); + + break; + case 0x0016: + sb.AppendLine("ATA/ATAPI-5 published, ANSI INCITS 340-2000"); + + break; + case 0x0017: + sb.AppendLine("ATA/ATAPI-4 T13 1153D revision 17"); + + break; + case 0x0018: + sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 0"); + + break; + case 0x0019: + sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 3a"); + + break; + case 0x001A: + sb.AppendLine("ATA/ATAPI-7 T13 1532D revision 1"); + + break; + case 0x001B: + sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 2"); + + break; + case 0x001C: + sb.AppendLine("ATA/ATAPI-6 T13 1410D revision 1"); + + break; + case 0x001D: + sb.AppendLine("ATA/ATAPI-7 published ANSI INCITS 397-2005"); + + break; + case 0x001E: + sb.AppendLine("ATA/ATAPI-7 T13 1532D revision 0"); + + break; + case 0x001F: + sb.AppendLine("ACS-3 Revision 3b"); + + break; + case 0x0021: + sb.AppendLine("ATA/ATAPI-7 T13 1532D revision 4a"); + + break; + case 0x0022: + sb.AppendLine("ATA/ATAPI-6 published, ANSI INCITS 361-2002"); + + break; + case 0x0027: + sb.AppendLine("ATA8-ACS revision 3c"); + + break; + case 0x0028: + sb.AppendLine("ATA8-ACS revision 6"); + + break; + case 0x0029: + sb.AppendLine("ATA8-ACS revision 4"); + + break; + case 0x0031: + sb.AppendLine("ACS-2 Revision 2"); + + break; + case 0x0033: + sb.AppendLine("ATA8-ACS Revision 3e"); + + break; + case 0x0039: + sb.AppendLine("ATA8-ACS Revision 4c"); + + break; + case 0x0042: + sb.AppendLine("ATA8-ACS Revision 3f"); + + break; + case 0x0052: + sb.AppendLine("ATA8-ACS revision 3b"); + + break; + case 0x006D: + sb.AppendLine("ACS-3 Revision 5"); + + break; + case 0x0082: + sb.AppendLine("ACS-2 published, ANSI INCITS 482-2012"); + + break; + case 0x0107: + sb.AppendLine("ATA8-ACS revision 2d"); + + break; + case 0x0110: + sb.AppendLine("ACS-2 Revision 3"); + + break; + case 0x011B: + sb.AppendLine("ACS-3 Revision 4"); break; default: - sb.AppendFormat("Unknown transport type 0x{0:X1}", (ATAID.TransportMajorVersion & 0xF000) >> 12). - AppendLine(); + sb.AppendFormat("Unknown ATA revision 0x{0:X4}", ATAID.MinorVersion).AppendLine(); break; } - if(atapi) + switch((ATAID.TransportMajorVersion & 0xF000) >> 12) + { + case 0x0: + sb.Append("Parallel ATA device: "); + + if((ATAID.TransportMajorVersion & 0x0002) == 0x0002) + sb.Append("ATA/ATAPI-7 "); + + if((ATAID.TransportMajorVersion & 0x0001) == 0x0001) + sb.Append("ATA8-APT "); + + sb.AppendLine(); + + break; + case 0x1: + sb.Append("Serial ATA device: "); + + if((ATAID.TransportMajorVersion & 0x0001) == 0x0001) + sb.Append("ATA8-AST "); + + if((ATAID.TransportMajorVersion & 0x0002) == 0x0002) + sb.Append("SATA 1.0a "); + + if((ATAID.TransportMajorVersion & 0x0004) == 0x0004) + sb.Append("SATA II Extensions "); + + if((ATAID.TransportMajorVersion & 0x0008) == 0x0008) + sb.Append("SATA 2.5 "); + + if((ATAID.TransportMajorVersion & 0x0010) == 0x0010) + sb.Append("SATA 2.6 "); + + if((ATAID.TransportMajorVersion & 0x0020) == 0x0020) + sb.Append("SATA 3.0 "); + + if((ATAID.TransportMajorVersion & 0x0040) == 0x0040) + sb.Append("SATA 3.1 "); + + sb.AppendLine(); + + break; + case 0xE: + sb.AppendLine("SATA Express device"); + + break; + default: + sb.AppendFormat("Unknown transport type 0x{0:X1}", (ATAID.TransportMajorVersion & 0xF000) >> 12). + AppendLine(); + + break; + } + + if(atapi) + { + // Bits 12 to 8, SCSI Peripheral Device Type + switch((PeripheralDeviceTypes)(((ushort)ATAID.GeneralConfiguration & 0x1F00) >> 8)) { - // Bits 12 to 8, SCSI Peripheral Device Type - switch((PeripheralDeviceTypes)(((ushort)ATAID.GeneralConfiguration & 0x1F00) >> 8)) - { - case PeripheralDeviceTypes.DirectAccess: //0x00, - sb.AppendLine("ATAPI Direct-access device"); + case PeripheralDeviceTypes.DirectAccess: //0x00, + sb.AppendLine("ATAPI Direct-access device"); - break; - case PeripheralDeviceTypes.SequentialAccess: //0x01, - sb.AppendLine("ATAPI Sequential-access device"); + break; + case PeripheralDeviceTypes.SequentialAccess: //0x01, + sb.AppendLine("ATAPI Sequential-access device"); - break; - case PeripheralDeviceTypes.PrinterDevice: //0x02, - sb.AppendLine("ATAPI Printer device"); + break; + case PeripheralDeviceTypes.PrinterDevice: //0x02, + sb.AppendLine("ATAPI Printer device"); - break; - case PeripheralDeviceTypes.ProcessorDevice: //0x03, - sb.AppendLine("ATAPI Processor device"); + break; + case PeripheralDeviceTypes.ProcessorDevice: //0x03, + sb.AppendLine("ATAPI Processor device"); - break; - case PeripheralDeviceTypes.WriteOnceDevice: //0x04, - sb.AppendLine("ATAPI Write-once device"); + break; + case PeripheralDeviceTypes.WriteOnceDevice: //0x04, + sb.AppendLine("ATAPI Write-once device"); - break; - case PeripheralDeviceTypes.MultiMediaDevice: //0x05, - sb.AppendLine("ATAPI CD-ROM/DVD/etc device"); + break; + case PeripheralDeviceTypes.MultiMediaDevice: //0x05, + sb.AppendLine("ATAPI CD-ROM/DVD/etc device"); - break; - case PeripheralDeviceTypes.ScannerDevice: //0x06, - sb.AppendLine("ATAPI Scanner device"); + break; + case PeripheralDeviceTypes.ScannerDevice: //0x06, + sb.AppendLine("ATAPI Scanner device"); - break; - case PeripheralDeviceTypes.OpticalDevice: //0x07, - sb.AppendLine("ATAPI Optical memory device"); + break; + case PeripheralDeviceTypes.OpticalDevice: //0x07, + sb.AppendLine("ATAPI Optical memory device"); - break; - case PeripheralDeviceTypes.MediumChangerDevice: //0x08, - sb.AppendLine("ATAPI Medium change device"); + break; + case PeripheralDeviceTypes.MediumChangerDevice: //0x08, + sb.AppendLine("ATAPI Medium change device"); - break; - case PeripheralDeviceTypes.CommsDevice: //0x09, - sb.AppendLine("ATAPI Communications device"); + break; + case PeripheralDeviceTypes.CommsDevice: //0x09, + sb.AppendLine("ATAPI Communications device"); - break; - case PeripheralDeviceTypes.PrePressDevice1: //0x0A, - sb.AppendLine("ATAPI Graphics arts pre-press device (defined in ASC IT8)"); + break; + case PeripheralDeviceTypes.PrePressDevice1: //0x0A, + sb.AppendLine("ATAPI Graphics arts pre-press device (defined in ASC IT8)"); - break; - case PeripheralDeviceTypes.PrePressDevice2: //0x0B, - sb.AppendLine("ATAPI Graphics arts pre-press device (defined in ASC IT8)"); + break; + case PeripheralDeviceTypes.PrePressDevice2: //0x0B, + sb.AppendLine("ATAPI Graphics arts pre-press device (defined in ASC IT8)"); - break; - case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, - sb.AppendLine("ATAPI Array controller device"); + break; + case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, + sb.AppendLine("ATAPI Array controller device"); - break; - case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, - sb.AppendLine("ATAPI Enclosure services device"); + break; + case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, + sb.AppendLine("ATAPI Enclosure services device"); - break; - case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, - sb.AppendLine("ATAPI Simplified direct-access device"); + break; + case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, + sb.AppendLine("ATAPI Simplified direct-access device"); - break; - case PeripheralDeviceTypes.OCRWDevice: //0x0F, - sb.AppendLine("ATAPI Optical card reader/writer device"); + break; + case PeripheralDeviceTypes.OCRWDevice: //0x0F, + sb.AppendLine("ATAPI Optical card reader/writer device"); - break; - case PeripheralDeviceTypes.BridgingExpander: //0x10, - sb.AppendLine("ATAPI Bridging Expanders"); + break; + case PeripheralDeviceTypes.BridgingExpander: //0x10, + sb.AppendLine("ATAPI Bridging Expanders"); - break; - case PeripheralDeviceTypes.ObjectDevice: //0x11, - sb.AppendLine("ATAPI Object-based Storage Device"); + break; + case PeripheralDeviceTypes.ObjectDevice: //0x11, + sb.AppendLine("ATAPI Object-based Storage Device"); - break; - case PeripheralDeviceTypes.ADCDevice: //0x12, - sb.AppendLine("ATAPI Automation/Drive Interface"); + break; + case PeripheralDeviceTypes.ADCDevice: //0x12, + sb.AppendLine("ATAPI Automation/Drive Interface"); - break; - case PeripheralDeviceTypes.WellKnownDevice: //0x1E, - sb.AppendLine("ATAPI Well known logical unit"); + break; + case PeripheralDeviceTypes.WellKnownDevice: //0x1E, + sb.AppendLine("ATAPI Well known logical unit"); - break; - case PeripheralDeviceTypes.UnknownDevice: //0x1F - sb.AppendLine("ATAPI Unknown or no device type"); + break; + case PeripheralDeviceTypes.UnknownDevice: //0x1F + sb.AppendLine("ATAPI Unknown or no device type"); - break; - default: - sb.AppendFormat("ATAPI Unknown device type field value 0x{0:X2}", - ((ushort)ATAID.GeneralConfiguration & 0x1F00) >> 8).AppendLine(); + break; + default: + sb.AppendFormat("ATAPI Unknown device type field value 0x{0:X2}", + ((ushort)ATAID.GeneralConfiguration & 0x1F00) >> 8).AppendLine(); - break; - } - - // ATAPI DRQ behaviour - switch(((ushort)ATAID.GeneralConfiguration & 0x60) >> 5) - { - case 0: - sb.AppendLine("Device shall set DRQ within 3 ms of receiving PACKET"); - - break; - case 1: - sb.AppendLine("Device shall assert INTRQ when DRQ is set to one"); - - break; - case 2: - sb.AppendLine("Device shall set DRQ within 50 µs of receiving PACKET"); - - break; - default: - sb.AppendFormat("Unknown ATAPI DRQ behaviour code {0}", - ((ushort)ATAID.GeneralConfiguration & 0x60) >> 5).AppendLine(); - - break; - } - - // ATAPI PACKET size - switch((ushort)ATAID.GeneralConfiguration & 0x03) - { - case 0: - sb.AppendLine("ATAPI device uses 12 byte command packet"); - - break; - case 1: - sb.AppendLine("ATAPI device uses 16 byte command packet"); - - break; - default: - sb.AppendFormat("Unknown ATAPI packet size code {0}", - (ushort)ATAID.GeneralConfiguration & 0x03).AppendLine(); - - break; - } - } - else if(!cfa) - { - if(minatalevel >= 5) - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.IncompleteResponse)) - sb.AppendLine("Incomplete identify response"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. - NonMagnetic)) - sb.AppendLine("Device uses non-magnetic media"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. - Removable)) - sb.AppendLine("Device is removable"); - - if(minatalevel <= 5) - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.Fixed)) - sb.AppendLine("Device is fixed"); - - if(ata1) - { - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.SlowIDE)) - sb.AppendLine("Device transfer rate is <= 5 Mb/s"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.FastIDE)) - sb.AppendLine("Device transfer rate is > 5 Mb/s but <= 10 Mb/s"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.UltraFastIDE)) - sb.AppendLine("Device transfer rate is > 10 Mb/s"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.SoftSector)) - sb.AppendLine("Device is soft sectored"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.HardSector)) - sb.AppendLine("Device is hard sectored"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.NotMFM)) - sb.AppendLine("Device is not MFM encoded"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.FormatGapReq)) - sb.AppendLine("Format speed tolerance gap is required"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.TrackOffset)) - sb.AppendLine("Track offset option is available"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.DataStrobeOffset)) - sb.AppendLine("Data strobe offset option is available"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.RotationalSpeedTolerance)) - sb.AppendLine("Rotational speed tolerance is higher than 0,5%"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.SpindleControl)) - sb.AppendLine("Spindle motor control is implemented"); - - if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - GeneralConfigurationBit.HighHeadSwitch)) - sb.AppendLine("Head switch time is bigger than 15 µs."); - } + break; } - if(ATAID.NominalRotationRate != 0x0000 && - ATAID.NominalRotationRate != 0xFFFF) - if(ATAID.NominalRotationRate == 0x0001) - sb.AppendLine("Device does not rotate."); - else - sb.AppendFormat("Device rotate at {0} rpm", ATAID.NominalRotationRate).AppendLine(); - - uint logicalSectorSize = 0; - - if(!atapi) + // ATAPI DRQ behaviour + switch(((ushort)ATAID.GeneralConfiguration & 0x60) >> 5) { - uint physicalSectorSize; + case 0: + sb.AppendLine("Device shall set DRQ within 3 ms of receiving PACKET"); - if((ATAID.PhysLogSectorSize & 0x8000) == 0x0000 && - (ATAID.PhysLogSectorSize & 0x4000) == 0x4000) - { - if((ATAID.PhysLogSectorSize & 0x1000) == 0x1000) - if(ATAID.LogicalSectorWords <= 255 || - ATAID.LogicalAlignment == 0xFFFF) - logicalSectorSize = 512; - else - logicalSectorSize = ATAID.LogicalSectorWords * 2; - else - logicalSectorSize = 512; + break; + case 1: + sb.AppendLine("Device shall assert INTRQ when DRQ is set to one"); - if((ATAID.PhysLogSectorSize & 0x2000) == 0x2000) - physicalSectorSize = logicalSectorSize * (uint)Math.Pow(2, ATAID.PhysLogSectorSize & 0xF); - else - physicalSectorSize = logicalSectorSize; - } - else - { - logicalSectorSize = 512; - physicalSectorSize = 512; - } + break; + case 2: + sb.AppendLine("Device shall set DRQ within 50 µs of receiving PACKET"); - sb.AppendFormat("Physical sector size: {0} bytes", physicalSectorSize).AppendLine(); - sb.AppendFormat("Logical sector size: {0} bytes", logicalSectorSize).AppendLine(); + break; + default: + sb.AppendFormat("Unknown ATAPI DRQ behaviour code {0}", + ((ushort)ATAID.GeneralConfiguration & 0x60) >> 5).AppendLine(); - if(logicalSectorSize != physicalSectorSize && - (ATAID.LogicalAlignment & 0x8000) == 0x0000 && - (ATAID.LogicalAlignment & 0x4000) == 0x4000) - sb.AppendFormat("Logical sector starts at offset {0} from physical sector", - ATAID.LogicalAlignment & 0x3FFF).AppendLine(); - - if(minatalevel <= 5) - if(ATAID.CurrentCylinders > 0 && - ATAID.CurrentHeads > 0 && - ATAID.CurrentSectorsPerTrack > 0) - { - sb.AppendFormat("Cylinders: {0} max., {1} current", ATAID.Cylinders, ATAID.CurrentCylinders). - AppendLine(); - - sb.AppendFormat("Heads: {0} max., {1} current", ATAID.Heads, ATAID.CurrentHeads).AppendLine(); - - sb.AppendFormat("Sectors per track: {0} max., {1} current", ATAID.SectorsPerTrack, - ATAID.CurrentSectorsPerTrack).AppendLine(); - - sb.AppendFormat("Sectors addressable in CHS mode: {0} max., {1} current", - ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack, ATAID.CurrentSectors). - AppendLine(); - } - else - { - sb.AppendFormat("Cylinders: {0}", ATAID.Cylinders).AppendLine(); - sb.AppendFormat("Heads: {0}", ATAID.Heads).AppendLine(); - sb.AppendFormat("Sectors per track: {0}", ATAID.SectorsPerTrack).AppendLine(); - - sb.AppendFormat("Sectors addressable in CHS mode: {0}", - ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack).AppendLine(); - } - - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) - sb.AppendFormat("{0} sectors in 28-bit LBA mode", ATAID.LBASectors).AppendLine(); - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) - sb.AppendFormat("{0} sectors in 48-bit LBA mode", ATAID.LBA48Sectors).AppendLine(); - - if(minatalevel <= 5) - if(ATAID.CurrentSectors > 0) - sb.AppendFormat("Device size in CHS mode: {0} bytes, {1} Mb, {2} MiB", - (ulong)ATAID.CurrentSectors * logicalSectorSize, - (ulong)ATAID.CurrentSectors * logicalSectorSize / 1000 / 1000, - (ulong)ATAID.CurrentSectors * 512 / 1024 / 1024).AppendLine(); - else - { - ulong currentSectors = (ulong)(ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack); - - sb.AppendFormat("Device size in CHS mode: {0} bytes, {1} Mb, {2} MiB", - currentSectors * logicalSectorSize, - currentSectors * logicalSectorSize / 1000 / 1000, - currentSectors * 512 / 1024 / 1024).AppendLine(); - } - - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) - if((ulong)ATAID.LBASectors * logicalSectorSize / 1024 / 1024 > 1000000) - sb.AppendFormat("Device size in 28-bit LBA mode: {0} bytes, {1} Tb, {2} TiB", - (ulong)ATAID.LBASectors * logicalSectorSize, - (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, - (ulong)ATAID.LBASectors * 512 / 1024 / 1024 / 1024 / 1024).AppendLine(); - else if((ulong)ATAID.LBASectors * logicalSectorSize / 1024 / 1024 > 1000) - sb.AppendFormat("Device size in 28-bit LBA mode: {0} bytes, {1} Gb, {2} GiB", - (ulong)ATAID.LBASectors * logicalSectorSize, - (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000 / 1000, - (ulong)ATAID.LBASectors * 512 / 1024 / 1024 / 1024).AppendLine(); - else - sb.AppendFormat("Device size in 28-bit LBA mode: {0} bytes, {1} Mb, {2} MiB", - (ulong)ATAID.LBASectors * logicalSectorSize, - (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000, - (ulong)ATAID.LBASectors * 512 / 1024 / 1024).AppendLine(); - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ExtSectors)) - if(ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 > 1000000) - sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Tb, {2} TiB", - ATAID.ExtendedUserSectors * logicalSectorSize, - ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, - ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 / 1024 / 1024). - AppendLine(); - else if(ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 > 1000) - sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Gb, {2} GiB", - ATAID.ExtendedUserSectors * logicalSectorSize, - ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000 / 1000, - ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 / 1024). - AppendLine(); - else - sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Mb, {2} MiB", - ATAID.ExtendedUserSectors * logicalSectorSize, - ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000, - ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024).AppendLine(); - else - { - if(ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 > 1000000) - sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Tb, {2} TiB", - ATAID.LBA48Sectors * logicalSectorSize, - ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, - ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 / 1024 / 1024). - AppendLine(); - else if(ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 > 1000) - sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Gb, {2} GiB", - ATAID.LBA48Sectors * logicalSectorSize, - ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000, - ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 / 1024).AppendLine(); - else - sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Mb, {2} MiB", - ATAID.LBA48Sectors * logicalSectorSize, - ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000, - ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024).AppendLine(); - } - - if(ata1 || cfa) - { - if(cfa) - sb.AppendFormat("{0} sectors in card", ATAID.SectorsPerCard).AppendLine(); - - if(ATAID.UnformattedBPT > 0) - sb.AppendFormat("{0} bytes per unformatted track", ATAID.UnformattedBPT).AppendLine(); - - if(ATAID.UnformattedBPS > 0) - sb.AppendFormat("{0} bytes per unformatted sector", ATAID.UnformattedBPS).AppendLine(); - } + break; } - if((ushort)ATAID.SpecificConfiguration != 0x0000 && - (ushort)ATAID.SpecificConfiguration != 0xFFFF) - switch(ATAID.SpecificConfiguration) - { - case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum. - RequiresSetIncompleteResponse: - sb.AppendLine("Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete."); - - break; - case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum.RequiresSetCompleteResponse: - sb.AppendLine("Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete."); - - break; - case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum. - NotRequiresSetIncompleteResponse: - sb.AppendLine("Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete."); - - break; - case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum. - NotRequiresSetCompleteResponse: - sb.AppendLine("Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is complete."); - - break; - default: - sb.AppendFormat("Unknown device specific configuration 0x{0:X4}", - (ushort)ATAID.SpecificConfiguration).AppendLine(); - - break; - } - - // Obsolete since ATA-2, however, it is yet used in ATA-8 devices - if(ATAID.BufferSize != 0x0000 && - ATAID.BufferSize != 0xFFFF && - ATAID.BufferType != 0x0000 && - ATAID.BufferType != 0xFFFF) - switch(ATAID.BufferType) - { - case 1: - sb.AppendFormat("{0} KiB of single ported single sector buffer", ATAID.BufferSize * 512 / 1024). - AppendLine(); - - break; - case 2: - sb.AppendFormat("{0} KiB of dual ported multi sector buffer", ATAID.BufferSize * 512 / 1024). - AppendLine(); - - break; - case 3: - sb.AppendFormat("{0} KiB of dual ported multi sector buffer with read caching", - ATAID.BufferSize * 512 / 1024).AppendLine(); - - break; - default: - sb.AppendFormat("{0} KiB of unknown type {1} buffer", ATAID.BufferSize * 512 / 1024, - ATAID.BufferType).AppendLine(); - - break; - } - - if(ATAID.EccBytes != 0x0000 && - ATAID.EccBytes != 0xFFFF) - sb.AppendFormat("READ/WRITE LONG has {0} extra bytes", ATAID.EccBytes).AppendLine(); - - sb.AppendLine(); - - sb.Append("Device capabilities:"); - - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. - StandardStandbyTimer)) - sb.AppendLine().Append("Standby time values are standard"); - - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.IORDY)) + // ATAPI PACKET size + switch((ushort)ATAID.GeneralConfiguration & 0x03) { - sb.AppendLine().Append("IORDY is supported"); + case 0: + sb.AppendLine("ATAPI device uses 12 byte command packet"); - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.CanDisableIORDY)) - sb.Append(" and can be disabled"); + break; + case 1: + sb.AppendLine("ATAPI device uses 16 byte command packet"); + + break; + default: + sb.AppendFormat("Unknown ATAPI packet size code {0}", + (ushort)ATAID.GeneralConfiguration & 0x03).AppendLine(); + + break; } + } + else if(!cfa) + { + if(minatalevel >= 5) + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.IncompleteResponse)) + sb.AppendLine("Incomplete identify response"); - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.DMASupport)) - sb.AppendLine().Append("DMA is supported"); + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. + NonMagnetic)) + sb.AppendLine("Device uses non-magnetic media"); - if(ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2.MustBeSet) && - !ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2.MustBeClear)) - if(ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2. - SpecificStandbyTimer)) - sb.AppendLine().Append("Device indicates a specific minimum standby timer value"); + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.GeneralConfigurationBit. + Removable)) + sb.AppendLine("Device is removable"); - if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.MultipleValid)) - { - sb.AppendLine(). - AppendFormat("A maximum of {0} sectors can be transferred per interrupt on READ/WRITE MULTIPLE", - ATAID.MultipleSectorNumber); - - sb.AppendLine().AppendFormat("Device supports setting a maximum of {0} sectors", - ATAID.MultipleMaxSectors); - } - - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. - PhysicalAlignment1) || - ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.PhysicalAlignment0)) - sb.AppendLine().AppendFormat("Long Physical Alignment setting is {0}", - (ushort)ATAID.Capabilities & 0x03); + if(minatalevel <= 5) + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.Fixed)) + sb.AppendLine("Device is fixed"); if(ata1) - if(ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit. - TrustedComputing)) - sb.AppendLine().Append("Device supports doubleword I/O"); - - if(atapi) { - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.InterleavedDMA)) - sb.AppendLine().Append("ATAPI device supports interleaved DMA"); + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.SlowIDE)) + sb.AppendLine("Device transfer rate is <= 5 Mb/s"); - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.CommandQueue)) - sb.AppendLine().Append("ATAPI device supports command queueing"); + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.FastIDE)) + sb.AppendLine("Device transfer rate is > 5 Mb/s but <= 10 Mb/s"); - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. - OverlapOperation)) - sb.AppendLine().Append("ATAPI device supports overlapped operations"); + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.UltraFastIDE)) + sb.AppendLine("Device transfer rate is > 10 Mb/s"); - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. - RequiresATASoftReset)) - sb.AppendLine().Append("ATAPI device requires ATA software reset"); + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.SoftSector)) + sb.AppendLine("Device is soft sectored"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.HardSector)) + sb.AppendLine("Device is hard sectored"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.NotMFM)) + sb.AppendLine("Device is not MFM encoded"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.FormatGapReq)) + sb.AppendLine("Format speed tolerance gap is required"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.TrackOffset)) + sb.AppendLine("Track offset option is available"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.DataStrobeOffset)) + sb.AppendLine("Data strobe offset option is available"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.RotationalSpeedTolerance)) + sb.AppendLine("Rotational speed tolerance is higher than 0,5%"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.SpindleControl)) + sb.AppendLine("Spindle motor control is implemented"); + + if(ATAID.GeneralConfiguration.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + GeneralConfigurationBit.HighHeadSwitch)) + sb.AppendLine("Head switch time is bigger than 15 µs."); + } + } + + if(ATAID.NominalRotationRate != 0x0000 && + ATAID.NominalRotationRate != 0xFFFF) + if(ATAID.NominalRotationRate == 0x0001) + sb.AppendLine("Device does not rotate."); + else + sb.AppendFormat("Device rotate at {0} rpm", ATAID.NominalRotationRate).AppendLine(); + + uint logicalSectorSize = 0; + + if(!atapi) + { + uint physicalSectorSize; + + if((ATAID.PhysLogSectorSize & 0x8000) == 0x0000 && + (ATAID.PhysLogSectorSize & 0x4000) == 0x4000) + { + if((ATAID.PhysLogSectorSize & 0x1000) == 0x1000) + if(ATAID.LogicalSectorWords <= 255 || + ATAID.LogicalAlignment == 0xFFFF) + logicalSectorSize = 512; + else + logicalSectorSize = ATAID.LogicalSectorWords * 2; + else + logicalSectorSize = 512; + + if((ATAID.PhysLogSectorSize & 0x2000) == 0x2000) + physicalSectorSize = logicalSectorSize * (uint)Math.Pow(2, ATAID.PhysLogSectorSize & 0xF); + else + physicalSectorSize = logicalSectorSize; + } + else + { + logicalSectorSize = 512; + physicalSectorSize = 512; } - if(minatalevel <= 3) - { - sb.AppendLine().AppendFormat("PIO timing mode: {0}", ATAID.PIOTransferTimingMode); - sb.AppendLine().AppendFormat("DMA timing mode: {0}", ATAID.DMATransferTimingMode); - } + sb.AppendFormat("Physical sector size: {0} bytes", physicalSectorSize).AppendLine(); + sb.AppendFormat("Logical sector size: {0} bytes", logicalSectorSize).AppendLine(); - sb.AppendLine().Append("Advanced PIO: "); + if(logicalSectorSize != physicalSectorSize && + (ATAID.LogicalAlignment & 0x8000) == 0x0000 && + (ATAID.LogicalAlignment & 0x4000) == 0x4000) + sb.AppendFormat("Logical sector starts at offset {0} from physical sector", + ATAID.LogicalAlignment & 0x3FFF).AppendLine(); - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) - sb.Append("PIO0 "); - - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) - sb.Append("PIO1 "); - - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) - sb.Append("PIO2 "); - - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) - sb.Append("PIO3 "); - - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) - sb.Append("PIO4 "); - - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) - sb.Append("PIO5 "); - - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) - sb.Append("PIO6 "); - - if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) - sb.Append("PIO7 "); - - if(minatalevel <= 3 && - !atapi) - { - sb.AppendLine().Append("Single-word DMA: "); - - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + if(minatalevel <= 5) + if(ATAID.CurrentCylinders > 0 && + ATAID.CurrentHeads > 0 && + ATAID.CurrentSectorsPerTrack > 0) { - sb.Append("DMA0 "); + sb.AppendFormat("Cylinders: {0} max., {1} current", ATAID.Cylinders, ATAID.CurrentCylinders). + AppendLine(); - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) - sb.Append("(active) "); - } + sb.AppendFormat("Heads: {0} max., {1} current", ATAID.Heads, ATAID.CurrentHeads).AppendLine(); - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) - { - sb.Append("DMA1 "); + sb.AppendFormat("Sectors per track: {0} max., {1} current", ATAID.SectorsPerTrack, + ATAID.CurrentSectorsPerTrack).AppendLine(); - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) - sb.Append("(active) "); - } - - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) - { - sb.Append("DMA2 "); - - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) - sb.Append("(active) "); - } - - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) - { - sb.Append("DMA3 "); - - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) - sb.Append("(active) "); - } - - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) - { - sb.Append("DMA4 "); - - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) - sb.Append("(active) "); - } - - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) - { - sb.Append("DMA5 "); - - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) - sb.Append("(active) "); - } - - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) - { - sb.Append("DMA6 "); - - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) - sb.Append("(active) "); - } - - if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) - { - sb.Append("DMA7 "); - - if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) - sb.Append("(active) "); - } - } - - sb.AppendLine().Append("Multi-word DMA: "); - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) - { - sb.Append("MDMA0 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) - sb.Append("(active) "); - } - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) - { - sb.Append("MDMA1 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) - sb.Append("(active) "); - } - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) - { - sb.Append("MDMA2 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) - sb.Append("(active) "); - } - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) - { - sb.Append("MDMA3 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) - sb.Append("(active) "); - } - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) - { - sb.Append("MDMA4 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) - sb.Append("(active) "); - } - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) - { - sb.Append("MDMA5 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) - sb.Append("(active) "); - } - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) - { - sb.Append("MDMA6 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) - sb.Append("(active) "); - } - - if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) - { - sb.Append("MDMA7 "); - - if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) - sb.Append("(active) "); - } - - sb.AppendLine().Append("Ultra DMA: "); - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) - { - sb.Append("UDMA0 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) - sb.Append("(active) "); - } - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) - { - sb.Append("UDMA1 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) - sb.Append("(active) "); - } - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) - { - sb.Append("UDMA2 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) - sb.Append("(active) "); - } - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) - { - sb.Append("UDMA3 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) - sb.Append("(active) "); - } - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) - { - sb.Append("UDMA4 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) - sb.Append("(active) "); - } - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) - { - sb.Append("UDMA5 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) - sb.Append("(active) "); - } - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) - { - sb.Append("UDMA6 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) - sb.Append("(active) "); - } - - if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) - { - sb.Append("UDMA7 "); - - if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) - sb.Append("(active) "); - } - - if(ATAID.MinMDMACycleTime != 0 && - ATAID.RecMDMACycleTime != 0) - sb.AppendLine(). - AppendFormat("At minimum {0} ns. transfer cycle time per word in MDMA, " + "{1} ns. recommended", - ATAID.MinMDMACycleTime, ATAID.RecMDMACycleTime); - - if(ATAID.MinPIOCycleTimeNoFlow != 0) - sb.AppendLine(). - AppendFormat("At minimum {0} ns. transfer cycle time per word in PIO, " + "without flow control", - ATAID.MinPIOCycleTimeNoFlow); - - if(ATAID.MinPIOCycleTimeFlow != 0) - sb.AppendLine(). - AppendFormat("At minimum {0} ns. transfer cycle time per word in PIO, " + "with IORDY flow control", - ATAID.MinPIOCycleTimeFlow); - - if(ATAID.MaxQueueDepth != 0) - sb.AppendLine().AppendFormat("{0} depth of queue maximum", ATAID.MaxQueueDepth + 1); - - if(atapi) - { - if(ATAID.PacketBusRelease != 0) - sb.AppendLine().AppendFormat("{0} ns. typical to release bus from receipt of PACKET", - ATAID.PacketBusRelease); - - if(ATAID.ServiceBusyClear != 0) - sb.AppendLine().AppendFormat("{0} ns. typical to clear BSY bit from receipt of SERVICE", - ATAID.ServiceBusyClear); - } - - if((ATAID.TransportMajorVersion & 0xF000) >> 12 == 0x1 || - (ATAID.TransportMajorVersion & 0xF000) >> 12 == 0xE) - { - if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.Clear)) - { - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - Gen1Speed)) - sb.AppendLine().Append("SATA 1.5Gb/s is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - Gen2Speed)) - sb.AppendLine().Append("SATA 3.0Gb/s is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - Gen3Speed)) - sb.AppendLine().Append("SATA 6.0Gb/s is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - PowerReceipt)) - sb.AppendLine().Append("Receipt of host initiated power management requests is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - PHYEventCounter)) - sb.AppendLine().Append("PHY Event counters are supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - HostSlumbTrans)) - sb.AppendLine().Append("Supports host automatic partial to slumber transitions is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - DevSlumbTrans)) - sb.AppendLine().Append("Supports device automatic partial to slumber transitions is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.NCQ)) - { - sb.AppendLine().Append("NCQ is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - NCQPriority)) - sb.AppendLine().Append("NCQ priority is supported"); - - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - UnloadNCQ)) - sb.AppendLine().Append("Unload is supported with outstanding NCQ commands"); - } - } - - if(!ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2. - Clear)) - { - if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - Clear) && - ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.NCQ)) - { - if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SATACapabilitiesBit2.NCQMgmt)) - sb.AppendLine().Append("NCQ queue management is supported"); - - if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SATACapabilitiesBit2.NCQStream)) - sb.AppendLine().Append("NCQ streaming is supported"); - } - - if(atapi) - { - if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SATACapabilitiesBit2.HostEnvDetect)) - sb.AppendLine().Append("ATAPI device supports host environment detection"); - - if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SATACapabilitiesBit2.DevAttSlimline)) - sb.AppendLine().Append("ATAPI device supports attention on slimline connected devices"); - } - - //sb.AppendFormat("Negotiated speed = {0}", ((ushort)ATAID.SATACapabilities2 & 0x000E) >> 1); - } - } - - if(ATAID.InterseekDelay != 0x0000 && - ATAID.InterseekDelay != 0xFFFF) - sb.AppendLine().AppendFormat("{0} microseconds of interseek delay for ISO-7779 acoustic testing", - ATAID.InterseekDelay); - - if((ushort)ATAID.DeviceFormFactor != 0x0000 && - (ushort)ATAID.DeviceFormFactor != 0xFFFF) - switch(ATAID.DeviceFormFactor) - { - case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.FiveAndQuarter: - sb.AppendLine().Append("Device nominal size is 5.25\""); - - break; - case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.ThreeAndHalf: - sb.AppendLine().Append("Device nominal size is 3.5\""); - - break; - case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.TwoAndHalf: - sb.AppendLine().Append("Device nominal size is 2.5\""); - - break; - case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.OnePointEight: - sb.AppendLine().Append("Device nominal size is 1.8\""); - - break; - case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.LessThanOnePointEight: - sb.AppendLine().Append("Device nominal size is smaller than 1.8\""); - - break; - default: - sb.AppendLine().AppendFormat("Device nominal size field value {0} is unknown", - ATAID.DeviceFormFactor); - - break; - } - - if(atapi) - if(ATAID.ATAPIByteCount > 0) - sb.AppendLine().AppendFormat("{0} bytes count limit for ATAPI", ATAID.ATAPIByteCount); - - if(cfa) - if((ATAID.CFAPowerMode & 0x8000) == 0x8000) - { - sb.AppendLine().Append("CompactFlash device supports power mode 1"); - - if((ATAID.CFAPowerMode & 0x2000) == 0x2000) - sb.AppendLine().Append("CompactFlash power mode 1 required for one or more commands"); - - if((ATAID.CFAPowerMode & 0x1000) == 0x1000) - sb.AppendLine().Append("CompactFlash power mode 1 is disabled"); - - sb.AppendLine().AppendFormat("CompactFlash device uses a maximum of {0} mA", - ATAID.CFAPowerMode & 0x0FFF); - } - - sb.AppendLine(); - - sb.AppendLine().Append("Command set and features:"); - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Nop)) - { - sb.AppendLine().Append("NOP is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Nop)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.ReadBuffer)) - { - sb.AppendLine().Append("READ BUFFER is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.ReadBuffer)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteBuffer)) - { - sb.AppendLine().Append("WRITE BUFFER is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteBuffer)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.HPA)) - { - sb.AppendLine().Append("Host Protected Area is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.HPA)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.DeviceReset)) - { - sb.AppendLine().Append("DEVICE RESET is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.DeviceReset)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Service)) - { - sb.AppendLine().Append("SERVICE interrupt is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Service)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Release)) - { - sb.AppendLine().Append("Release is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Release)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.LookAhead)) - { - sb.AppendLine().Append("Look-ahead read is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.LookAhead)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteCache)) - { - sb.AppendLine().Append("Write cache is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteCache)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Packet)) - { - sb.AppendLine().Append("PACKET is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Packet)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.PowerManagement)) - { - sb.AppendLine().Append("Power management is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit. - PowerManagement)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.RemovableMedia)) - { - sb.AppendLine().Append("Removable media feature set is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit. - RemovableMedia)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SecurityMode)) - { - sb.AppendLine().Append("Security mode is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SecurityMode)) - sb.Append(" and enabled"); - } - - if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) - sb.AppendLine().Append("28-bit LBA is supported"); - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.MustBeSet) && - !ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.MustBeClear)) - { - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) - { - sb.AppendLine().Append("48-bit LBA is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.FlushCache)) - { - sb.AppendLine().Append("FLUSH CACHE is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - FlushCache)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.FlushCacheExt)) - { - sb.AppendLine().Append("FLUSH CACHE EXT is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - FlushCacheExt)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DCO)) - { - sb.AppendLine().Append("Device Configuration Overlay feature set is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DCO)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.AAM)) - { - sb.AppendLine().Append("Automatic Acoustic Management is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.AAM)) - sb.AppendFormat(" and enabled with value {0} (vendor recommends {1}", ATAID.CurrentAAM, - ATAID.RecommendedAAM); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.SetMax)) - { - sb.AppendLine().Append("SET MAX security extension is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.SetMax)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - AddressOffsetReservedAreaBoot)) - { - sb.AppendLine().Append("Address Offset Reserved Area Boot is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - AddressOffsetReservedAreaBoot)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - SetFeaturesRequired)) - sb.AppendLine().Append("SET FEATURES is required before spin-up"); - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.PowerUpInStandby)) - { - sb.AppendLine().Append("Power-up in standby is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - PowerUpInStandby)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - RemovableNotification)) - { - sb.AppendLine().Append("Removable Media Status Notification is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - RemovableNotification)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.APM)) - { - sb.AppendLine().Append("Advanced Power Management is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.APM)) - sb.AppendFormat(" and enabled with value {0}", ATAID.CurrentAPM); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.CompactFlash)) - { - sb.AppendLine().Append("CompactFlash feature set is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - CompactFlash)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.RWQueuedDMA)) - { - sb.AppendLine().Append("READ DMA QUEUED and WRITE DMA QUEUED are supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - RWQueuedDMA)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DownloadMicrocode)) - { - sb.AppendLine().Append("DOWNLOAD MICROCODE is supported"); - - if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. - DownloadMicrocode)) - sb.Append(" and enabled"); - } - } - - if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SMART)) - { - sb.AppendLine().Append("S.M.A.R.T. is supported"); - - if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SMART)) - sb.Append(" and enabled"); - } - - if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. - Supported)) - sb.AppendLine().Append("S.M.A.R.T. Command Transport is supported"); - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && - !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear)) - { - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.SMARTSelfTest)) - { - sb.AppendLine().Append("S.M.A.R.T. self-testing is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - SMARTSelfTest)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.SMARTLog)) - { - sb.AppendLine().Append("S.M.A.R.T. error logging is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - SMARTLog)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.IdleImmediate)) - { - sb.AppendLine().Append("IDLE IMMEDIATE with UNLOAD FEATURE is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - IdleImmediate)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WriteURG)) - sb.AppendLine().Append("URG bit is supported in WRITE STREAM DMA EXT and WRITE STREAM EXT"); - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.ReadURG)) - sb.AppendLine().Append("URG bit is supported in READ STREAM DMA EXT and READ STREAM EXT"); - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WWN)) - sb.AppendLine().Append("Device has a World Wide Name"); - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.FUAWriteQ)) - { - sb.AppendLine().Append("WRITE DMA QUEUED FUA EXT is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - FUAWriteQ)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.FUAWrite)) - { - sb.AppendLine().Append("WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - FUAWrite)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.GPL)) - { - sb.AppendLine().Append("General Purpose Logging is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.GPL)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.Streaming)) - { - sb.AppendLine().Append("Streaming feature set is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - Streaming)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MCPT)) - { - sb.AppendLine().Append("Media Card Pass Through command set is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MCPT)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MediaSerial)) - { - sb.AppendLine().Append("Media Serial is supported"); - - if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. - MediaSerial)) - sb.Append(" and valid"); - } - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.MustBeSet) && - !ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.MustBeClear)) - { - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DSN)) - { - sb.AppendLine().Append("DSN feature set is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DSN)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.AMAC)) - { - sb.AppendLine().Append("Accessible Max Address Configuration is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.AMAC)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.ExtPowerCond)) - { - sb.AppendLine().Append("Extended Power Conditions are supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. - ExtPowerCond)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.ExtStatusReport)) - { - sb.AppendLine().Append("Extended Status Reporting is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. - ExtStatusReport)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.FreeFallControl)) - { - sb.AppendLine().Append("Free-fall control feature set is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. - FreeFallControl)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. - SegmentedDownloadMicrocode)) - { - sb.AppendLine().Append("Segmented feature in DOWNLOAD MICROCODE is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. - SegmentedDownloadMicrocode)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.RWDMAExtGpl)) - { - sb.AppendLine().Append("READ/WRITE DMA EXT GPL are supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. - RWDMAExtGpl)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WriteUnc)) - { - sb.AppendLine().Append("WRITE UNCORRECTABLE is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. - WriteUnc)) - sb.Append(" and enabled"); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) - { - sb.AppendLine().Append("Write/Read/Verify is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) - sb.Append(" and enabled"); - - sb.AppendLine().AppendFormat("{0} sectors for Write/Read/Verify mode 2", ATAID.WRVSectorCountMode2); - sb.AppendLine().AppendFormat("{0} sectors for Write/Read/Verify mode 3", ATAID.WRVSectorCountMode3); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) - sb.AppendLine().AppendFormat("Current Write/Read/Verify mode: {0}", ATAID.WRVMode); - } - - if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DT1825)) - { - sb.AppendLine().Append("DT1825 is supported"); - - if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DT1825)) - sb.Append(" and enabled"); - } - } - - if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.BlockErase)) - sb.AppendLine().Append("BLOCK ERASE EXT is supported"); - - if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.Overwrite)) - sb.AppendLine().Append("OVERWRITE EXT is supported"); - - if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.CryptoScramble)) - sb.AppendLine().Append("CRYPTO SCRAMBLE EXT is supported"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DeviceConfDMA)) - sb.AppendLine(). - Append("DEVICE CONFIGURATION IDENTIFY DMA and DEVICE CONFIGURATION SET DMA are supported"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ReadBufferDMA)) - sb.AppendLine().Append("READ BUFFER DMA is supported"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.WriteBufferDMA)) - sb.AppendLine().Append("WRITE BUFFER DMA is supported"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DownloadMicroCodeDMA)) - sb.AppendLine().Append("DOWNLOAD MICROCODE DMA is supported"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.SetMaxDMA)) - sb.AppendLine().Append("SET PASSWORD DMA and SET UNLOCK DMA are supported"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.Ata28)) - sb.AppendLine().Append("Not all 28-bit commands are supported"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.CFast)) - sb.AppendLine().Append("Device follows CFast specification"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.IEEE1667)) - sb.AppendLine().Append("Device follows IEEE-1667"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DeterministicTrim)) - { - sb.AppendLine().Append("Read after TRIM is deterministic"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ReadZeroTrim)) - sb.AppendLine().Append("Read after TRIM returns empty data"); - } - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5. - LongPhysSectorAligError)) - sb.AppendLine().Append("Device supports Long Physical Sector Alignment Error Reporting Control"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.Encrypted)) - sb.AppendLine().Append("Device encrypts all user data"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.AllCacheNV)) - sb.AppendLine().Append("Device's write cache is non-volatile"); - - if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ZonedBit0) || - ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ZonedBit1)) - sb.AppendLine().Append("Device is zoned"); - - if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.Sanitize)) - { - sb.AppendLine().Append("Sanitize feature set is supported"); - - sb.AppendLine(). - Append(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3. - SanitizeCommands) - ? "Sanitize commands are specified by ACS-3 or higher" - : "Sanitize commands are specified by ACS-2"); - - if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3. - SanitizeAntifreeze)) - sb.AppendLine().Append("SANITIZE ANTIFREEZE LOCK EXT is supported"); - } - - if(!ata1 && - maxatalevel >= 8) - if(ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit.Set) && - !ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit. - Clear) && - ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit. - TrustedComputing)) - sb.AppendLine().Append("Trusted Computing feature set is supported"); - - if((ATAID.TransportMajorVersion & 0xF000) >> 12 == 0x1 || - (ATAID.TransportMajorVersion & 0xF000) >> 12 == 0xE) - { - if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.Clear)) - if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. - ReadLogDMAExt)) - sb.AppendLine().Append("READ LOG DMA EXT is supported"); - - if(!ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2. - Clear)) - if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2. - FPDMAQ)) - sb.AppendLine().Append("RECEIVE FPDMA QUEUED and SEND FPDMA QUEUED are supported"); - - if(!ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.Clear)) - { - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - NonZeroBufferOffset)) - { - sb.AppendLine().Append("Non-zero buffer offsets are supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - NonZeroBufferOffset)) - sb.Append(" and enabled"); - } - - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.DMASetup)) - { - sb.AppendLine().Append("DMA Setup auto-activation is supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - DMASetup)) - sb.Append(" and enabled"); - } - - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - InitPowerMgmt)) - { - sb.AppendLine().Append("Device-initiated power management is supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - InitPowerMgmt)) - sb.Append(" and enabled"); - } - - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.InOrderData)) - { - sb.AppendLine().Append("In-order data delivery is supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - InOrderData)) - sb.Append(" and enabled"); - } - - if(!atapi) - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - HardwareFeatureControl)) - { - sb.AppendLine().Append("Hardware Feature Control is supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SATAFeaturesBit.HardwareFeatureControl)) - sb.Append(" and enabled"); - } - - if(atapi) - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - AsyncNotification)) - { - sb.AppendLine().Append("Asynchronous notification is supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SATAFeaturesBit.AsyncNotification)) - sb.Append(" and enabled"); - } - - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - SettingsPreserve)) - { - sb.AppendLine().Append("Software Settings Preservation is supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - SettingsPreserve)) - sb.Append(" and enabled"); - } - - if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - NCQAutoSense)) - sb.AppendLine().Append("NCQ Autosense is supported"); - - if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. - EnabledSlumber)) - sb.AppendLine().Append("Automatic Partial to Slumber transitions are enabled"); - } - } - - if((ATAID.RemovableStatusSet & 0x03) > 0) - sb.AppendLine().Append("Removable Media Status Notification feature set is supported"); - - if(ATAID.FreeFallSensitivity != 0x00 && - ATAID.FreeFallSensitivity != 0xFF) - sb.AppendLine().AppendFormat("Free-fall sensitivity set to {0}", ATAID.FreeFallSensitivity); - - if(ATAID.DataSetMgmt.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.DataSetMgmtBit.Trim)) - sb.AppendLine().Append("TRIM is supported"); - - if(ATAID.DataSetMgmtSize > 0) - sb.AppendLine().AppendFormat("DATA SET MANAGEMENT can receive a maximum of {0} blocks of 512 bytes", - ATAID.DataSetMgmtSize); - - sb.AppendLine().AppendLine(); - - if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Supported)) - { - sb.AppendLine("Security:"); - - if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enabled)) - { - sb.AppendLine("Security is enabled"); - - sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SecurityStatusBit.Locked) - ? "Security is locked" : "Security is not locked"); - - sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SecurityStatusBit.Frozen) - ? "Security is frozen" : "Security is not frozen"); - - sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SecurityStatusBit.Expired) - ? "Security count has expired" : "Security count has not expired"); - - sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. - SecurityStatusBit.Maximum) - ? "Security level is maximum" : "Security level is high"); + sb.AppendFormat("Sectors addressable in CHS mode: {0} max., {1} current", + ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack, ATAID.CurrentSectors). + AppendLine(); } else - sb.AppendLine("Security is not enabled"); - - if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enhanced)) - sb.AppendLine("Supports enhanced security erase"); - - sb.AppendFormat("{0} minutes to complete secure erase", ATAID.SecurityEraseTime * 2).AppendLine(); - - if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enhanced)) - sb.AppendFormat("{0} minutes to complete enhanced secure erase", - ATAID.EnhancedSecurityEraseTime * 2).AppendLine(); - - sb.AppendFormat("Master password revision code: {0}", ATAID.MasterPasswordRevisionCode).AppendLine(); - } - - if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && - !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear) && - ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.Streaming)) - { - sb.AppendLine().AppendLine("Streaming:"); - sb.AppendFormat("Minimum request size is {0}", ATAID.StreamMinReqSize); - sb.AppendFormat("Streaming transfer time in PIO is {0}", ATAID.StreamTransferTimePIO); - sb.AppendFormat("Streaming transfer time in DMA is {0}", ATAID.StreamTransferTimeDMA); - sb.AppendFormat("Streaming access latency is {0}", ATAID.StreamAccessLatency); - sb.AppendFormat("Streaming performance granularity is {0}", ATAID.StreamPerformanceGranularity); - } - - if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. - Supported)) - { - sb.AppendLine().AppendLine("S.M.A.R.T. Command Transport (SCT):"); - - if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. - LongSectorAccess)) - sb.AppendLine("SCT Long Sector Address is supported"); - - if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. - WriteSame)) - sb.AppendLine("SCT Write Same is supported"); - - if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. - ErrorRecoveryControl)) - sb.AppendLine("SCT Error Recovery Control is supported"); - - if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. - FeaturesControl)) - sb.AppendLine("SCT Features Control is supported"); - - if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. - DataTables)) - sb.AppendLine("SCT Data Tables are supported"); - } - - if((ATAID.NVCacheCaps & 0x0010) == 0x0010) - { - sb.AppendLine().AppendLine("Non-Volatile Cache:"); - sb.AppendLine().AppendFormat("Version {0}", (ATAID.NVCacheCaps & 0xF000) >> 12).AppendLine(); - - if((ATAID.NVCacheCaps & 0x0001) == 0x0001) { - sb.Append("Power mode feature set is supported"); + sb.AppendFormat("Cylinders: {0}", ATAID.Cylinders).AppendLine(); + sb.AppendFormat("Heads: {0}", ATAID.Heads).AppendLine(); + sb.AppendFormat("Sectors per track: {0}", ATAID.SectorsPerTrack).AppendLine(); - if((ATAID.NVCacheCaps & 0x0002) == 0x0002) - sb.Append(" and enabled"); - - sb.AppendLine(); - - sb.AppendLine().AppendFormat("Version {0}", (ATAID.NVCacheCaps & 0x0F00) >> 8).AppendLine(); + sb.AppendFormat("Sectors addressable in CHS mode: {0}", + ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack).AppendLine(); } - sb.AppendLine().AppendFormat("Non-Volatile Cache is {0} bytes", ATAID.NVCacheSize * logicalSectorSize). - AppendLine(); + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) + sb.AppendFormat("{0} sectors in 28-bit LBA mode", ATAID.LBASectors).AppendLine(); + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) + sb.AppendFormat("{0} sectors in 48-bit LBA mode", ATAID.LBA48Sectors).AppendLine(); + + if(minatalevel <= 5) + if(ATAID.CurrentSectors > 0) + sb.AppendFormat("Device size in CHS mode: {0} bytes, {1} Mb, {2} MiB", + (ulong)ATAID.CurrentSectors * logicalSectorSize, + (ulong)ATAID.CurrentSectors * logicalSectorSize / 1000 / 1000, + (ulong)ATAID.CurrentSectors * 512 / 1024 / 1024).AppendLine(); + else + { + ulong currentSectors = (ulong)(ATAID.Cylinders * ATAID.Heads * ATAID.SectorsPerTrack); + + sb.AppendFormat("Device size in CHS mode: {0} bytes, {1} Mb, {2} MiB", + currentSectors * logicalSectorSize, + currentSectors * logicalSectorSize / 1000 / 1000, + currentSectors * 512 / 1024 / 1024).AppendLine(); + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) + if((ulong)ATAID.LBASectors * logicalSectorSize / 1024 / 1024 > 1000000) + sb.AppendFormat("Device size in 28-bit LBA mode: {0} bytes, {1} Tb, {2} TiB", + (ulong)ATAID.LBASectors * logicalSectorSize, + (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, + (ulong)ATAID.LBASectors * 512 / 1024 / 1024 / 1024 / 1024).AppendLine(); + else if((ulong)ATAID.LBASectors * logicalSectorSize / 1024 / 1024 > 1000) + sb.AppendFormat("Device size in 28-bit LBA mode: {0} bytes, {1} Gb, {2} GiB", + (ulong)ATAID.LBASectors * logicalSectorSize, + (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000 / 1000, + (ulong)ATAID.LBASectors * 512 / 1024 / 1024 / 1024).AppendLine(); + else + sb.AppendFormat("Device size in 28-bit LBA mode: {0} bytes, {1} Mb, {2} MiB", + (ulong)ATAID.LBASectors * logicalSectorSize, + (ulong)ATAID.LBASectors * logicalSectorSize / 1000 / 1000, + (ulong)ATAID.LBASectors * 512 / 1024 / 1024).AppendLine(); + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ExtSectors)) + if(ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 > 1000000) + sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Tb, {2} TiB", + ATAID.ExtendedUserSectors * logicalSectorSize, + ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, + ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 / 1024 / 1024). + AppendLine(); + else if(ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 > 1000) + sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Gb, {2} GiB", + ATAID.ExtendedUserSectors * logicalSectorSize, + ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000 / 1000, + ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024 / 1024). + AppendLine(); + else + sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Mb, {2} MiB", + ATAID.ExtendedUserSectors * logicalSectorSize, + ATAID.ExtendedUserSectors * logicalSectorSize / 1000 / 1000, + ATAID.ExtendedUserSectors * logicalSectorSize / 1024 / 1024).AppendLine(); + else + { + if(ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 > 1000000) + sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Tb, {2} TiB", + ATAID.LBA48Sectors * logicalSectorSize, + ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000 / 1000, + ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 / 1024 / 1024). + AppendLine(); + else if(ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 > 1000) + sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Gb, {2} GiB", + ATAID.LBA48Sectors * logicalSectorSize, + ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000 / 1000, + ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024 / 1024).AppendLine(); + else + sb.AppendFormat("Device size in 48-bit LBA mode: {0} bytes, {1} Mb, {2} MiB", + ATAID.LBA48Sectors * logicalSectorSize, + ATAID.LBA48Sectors * logicalSectorSize / 1000 / 1000, + ATAID.LBA48Sectors * logicalSectorSize / 1024 / 1024).AppendLine(); + } + + if(ata1 || cfa) + { + if(cfa) + sb.AppendFormat("{0} sectors in card", ATAID.SectorsPerCard).AppendLine(); + + if(ATAID.UnformattedBPT > 0) + sb.AppendFormat("{0} bytes per unformatted track", ATAID.UnformattedBPT).AppendLine(); + + if(ATAID.UnformattedBPS > 0) + sb.AppendFormat("{0} bytes per unformatted sector", ATAID.UnformattedBPS).AppendLine(); + } + } + + if((ushort)ATAID.SpecificConfiguration != 0x0000 && + (ushort)ATAID.SpecificConfiguration != 0xFFFF) + switch(ATAID.SpecificConfiguration) + { + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum. + RequiresSetIncompleteResponse: + sb.AppendLine("Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete."); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum.RequiresSetCompleteResponse: + sb.AppendLine("Device requires SET FEATURES to spin up and IDENTIFY DEVICE response is complete."); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum. + NotRequiresSetIncompleteResponse: + sb.AppendLine("Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is incomplete."); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.SpecificConfigurationEnum. + NotRequiresSetCompleteResponse: + sb.AppendLine("Device does not require SET FEATURES to spin up and IDENTIFY DEVICE response is complete."); + + break; + default: + sb.AppendFormat("Unknown device specific configuration 0x{0:X4}", + (ushort)ATAID.SpecificConfiguration).AppendLine(); + + break; } - #if DEBUG - sb.AppendLine(); + // Obsolete since ATA-2, however, it is yet used in ATA-8 devices + if(ATAID.BufferSize != 0x0000 && + ATAID.BufferSize != 0xFFFF && + ATAID.BufferType != 0x0000 && + ATAID.BufferType != 0xFFFF) + switch(ATAID.BufferType) + { + case 1: + sb.AppendFormat("{0} KiB of single ported single sector buffer", ATAID.BufferSize * 512 / 1024). + AppendLine(); - if(ATAID.VendorWord9 != 0x0000 && - ATAID.VendorWord9 != 0xFFFF) - sb.AppendFormat("Word 9: 0x{0:X4}", ATAID.VendorWord9).AppendLine(); + break; + case 2: + sb.AppendFormat("{0} KiB of dual ported multi sector buffer", ATAID.BufferSize * 512 / 1024). + AppendLine(); - if((ATAID.VendorWord47 & 0x7F) != 0x7F && - (ATAID.VendorWord47 & 0x7F) != 0x00) - sb.AppendFormat("Word 47 bits 15 to 8: 0x{0:X2}", ATAID.VendorWord47).AppendLine(); + break; + case 3: + sb.AppendFormat("{0} KiB of dual ported multi sector buffer with read caching", + ATAID.BufferSize * 512 / 1024).AppendLine(); - if(ATAID.VendorWord51 != 0x00 && - ATAID.VendorWord51 != 0xFF) - sb.AppendFormat("Word 51 bits 7 to 0: 0x{0:X2}", ATAID.VendorWord51).AppendLine(); + break; + default: + sb.AppendFormat("{0} KiB of unknown type {1} buffer", ATAID.BufferSize * 512 / 1024, + ATAID.BufferType).AppendLine(); - if(ATAID.VendorWord52 != 0x00 && - ATAID.VendorWord52 != 0xFF) - sb.AppendFormat("Word 52 bits 7 to 0: 0x{0:X2}", ATAID.VendorWord52).AppendLine(); + break; + } - if(ATAID.ReservedWord64 != 0x00 && - ATAID.ReservedWord64 != 0xFF) - sb.AppendFormat("Word 64 bits 15 to 8: 0x{0:X2}", ATAID.ReservedWord64).AppendLine(); + if(ATAID.EccBytes != 0x0000 && + ATAID.EccBytes != 0xFFFF) + sb.AppendFormat("READ/WRITE LONG has {0} extra bytes", ATAID.EccBytes).AppendLine(); - if(ATAID.ReservedWord70 != 0x0000 && - ATAID.ReservedWord70 != 0xFFFF) - sb.AppendFormat("Word 70: 0x{0:X4}", ATAID.ReservedWord70).AppendLine(); + sb.AppendLine(); - if(ATAID.ReservedWord73 != 0x0000 && - ATAID.ReservedWord73 != 0xFFFF) - sb.AppendFormat("Word 73: 0x{0:X4}", ATAID.ReservedWord73).AppendLine(); + sb.Append("Device capabilities:"); - if(ATAID.ReservedWord74 != 0x0000 && - ATAID.ReservedWord74 != 0xFFFF) - sb.AppendFormat("Word 74: 0x{0:X4}", ATAID.ReservedWord74).AppendLine(); + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. + StandardStandbyTimer)) + sb.AppendLine().Append("Standby time values are standard"); - if(ATAID.ReservedWord116 != 0x0000 && - ATAID.ReservedWord116 != 0xFFFF) - sb.AppendFormat("Word 116: 0x{0:X4}", ATAID.ReservedWord116).AppendLine(); + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.IORDY)) + { + sb.AppendLine().Append("IORDY is supported"); - for(int i = 0; i < ATAID.ReservedWords121.Length; i++) - if(ATAID.ReservedWords121[i] != 0x0000 && - ATAID.ReservedWords121[i] != 0xFFFF) - sb.AppendFormat("Word {1}: 0x{0:X4}", ATAID.ReservedWords121[i], 121 + i).AppendLine(); - - for(int i = 0; i < ATAID.ReservedWords129.Length; i++) - if(ATAID.ReservedWords129[i] != 0x0000 && - ATAID.ReservedWords129[i] != 0xFFFF) - sb.AppendFormat("Word {1}: 0x{0:X4}", ATAID.ReservedWords129[i], 129 + i).AppendLine(); - - for(int i = 0; i < ATAID.ReservedCFA.Length; i++) - if(ATAID.ReservedCFA[i] != 0x0000 && - ATAID.ReservedCFA[i] != 0xFFFF) - sb.AppendFormat("Word {1} (CFA): 0x{0:X4}", ATAID.ReservedCFA[i], 161 + i).AppendLine(); - - if(ATAID.ReservedWord174 != 0x0000 && - ATAID.ReservedWord174 != 0xFFFF) - sb.AppendFormat("Word 174: 0x{0:X4}", ATAID.ReservedWord174).AppendLine(); - - if(ATAID.ReservedWord175 != 0x0000 && - ATAID.ReservedWord175 != 0xFFFF) - sb.AppendFormat("Word 175: 0x{0:X4}", ATAID.ReservedWord175).AppendLine(); - - if(ATAID.ReservedCEATAWord207 != 0x0000 && - ATAID.ReservedCEATAWord207 != 0xFFFF) - sb.AppendFormat("Word 207 (CE-ATA): 0x{0:X4}", ATAID.ReservedCEATAWord207).AppendLine(); - - if(ATAID.ReservedCEATAWord208 != 0x0000 && - ATAID.ReservedCEATAWord208 != 0xFFFF) - sb.AppendFormat("Word 208 (CE-ATA): 0x{0:X4}", ATAID.ReservedCEATAWord208).AppendLine(); - - if(ATAID.NVReserved != 0x00 && - ATAID.NVReserved != 0xFF) - sb.AppendFormat("Word 219 bits 15 to 8: 0x{0:X2}", ATAID.NVReserved).AppendLine(); - - if(ATAID.WRVReserved != 0x00 && - ATAID.WRVReserved != 0xFF) - sb.AppendFormat("Word 220 bits 15 to 8: 0x{0:X2}", ATAID.WRVReserved).AppendLine(); - - if(ATAID.ReservedWord221 != 0x0000 && - ATAID.ReservedWord221 != 0xFFFF) - sb.AppendFormat("Word 221: 0x{0:X4}", ATAID.ReservedWord221).AppendLine(); - - for(int i = 0; i < ATAID.ReservedCEATA224.Length; i++) - if(ATAID.ReservedCEATA224[i] != 0x0000 && - ATAID.ReservedCEATA224[i] != 0xFFFF) - sb.AppendFormat("Word {1} (CE-ATA): 0x{0:X4}", ATAID.ReservedCEATA224[i], 224 + i).AppendLine(); - - for(int i = 0; i < ATAID.ReservedWords.Length; i++) - if(ATAID.ReservedWords[i] != 0x0000 && - ATAID.ReservedWords[i] != 0xFFFF) - sb.AppendFormat("Word {1}: 0x{0:X4}", ATAID.ReservedWords[i], 236 + i).AppendLine(); - #endif - return sb.ToString(); + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.CanDisableIORDY)) + sb.Append(" and can be disabled"); } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.DMASupport)) + sb.AppendLine().Append("DMA is supported"); + + if(ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2.MustBeSet) && + !ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2.MustBeClear)) + if(ATAID.Capabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit2. + SpecificStandbyTimer)) + sb.AppendLine().Append("Device indicates a specific minimum standby timer value"); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.MultipleValid)) + { + sb.AppendLine(). + AppendFormat("A maximum of {0} sectors can be transferred per interrupt on READ/WRITE MULTIPLE", + ATAID.MultipleSectorNumber); + + sb.AppendLine().AppendFormat("Device supports setting a maximum of {0} sectors", + ATAID.MultipleMaxSectors); + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. + PhysicalAlignment1) || + ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.PhysicalAlignment0)) + sb.AppendLine().AppendFormat("Long Physical Alignment setting is {0}", + (ushort)ATAID.Capabilities & 0x03); + + if(ata1) + if(ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit. + TrustedComputing)) + sb.AppendLine().Append("Device supports doubleword I/O"); + + if(atapi) + { + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.InterleavedDMA)) + sb.AppendLine().Append("ATAPI device supports interleaved DMA"); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.CommandQueue)) + sb.AppendLine().Append("ATAPI device supports command queueing"); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. + OverlapOperation)) + sb.AppendLine().Append("ATAPI device supports overlapped operations"); + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit. + RequiresATASoftReset)) + sb.AppendLine().Append("ATAPI device requires ATA software reset"); + } + + if(minatalevel <= 3) + { + sb.AppendLine().AppendFormat("PIO timing mode: {0}", ATAID.PIOTransferTimingMode); + sb.AppendLine().AppendFormat("DMA timing mode: {0}", ATAID.DMATransferTimingMode); + } + + sb.AppendLine().Append("Advanced PIO: "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + sb.Append("PIO0 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + sb.Append("PIO1 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + sb.Append("PIO2 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + sb.Append("PIO3 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + sb.Append("PIO4 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + sb.Append("PIO5 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + sb.Append("PIO6 "); + + if(ATAID.APIOSupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + sb.Append("PIO7 "); + + if(minatalevel <= 3 && + !atapi) + { + sb.AppendLine().Append("Single-word DMA: "); + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + { + sb.Append("DMA0 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + sb.Append("(active) "); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + { + sb.Append("DMA1 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + sb.Append("(active) "); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + { + sb.Append("DMA2 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + sb.Append("(active) "); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + { + sb.Append("DMA3 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + sb.Append("(active) "); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + { + sb.Append("DMA4 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + sb.Append("(active) "); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + { + sb.Append("DMA5 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + sb.Append("(active) "); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + { + sb.Append("DMA6 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + sb.Append("(active) "); + } + + if(ATAID.DMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + { + sb.Append("DMA7 "); + + if(ATAID.DMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + sb.Append("(active) "); + } + } + + sb.AppendLine().Append("Multi-word DMA: "); + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + { + sb.Append("MDMA0 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + sb.Append("(active) "); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + { + sb.Append("MDMA1 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + sb.Append("(active) "); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + { + sb.Append("MDMA2 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + sb.Append("(active) "); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + { + sb.Append("MDMA3 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + sb.Append("(active) "); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + { + sb.Append("MDMA4 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + sb.Append("(active) "); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + { + sb.Append("MDMA5 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + sb.Append("(active) "); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + { + sb.Append("MDMA6 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + sb.Append("(active) "); + } + + if(ATAID.MDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + { + sb.Append("MDMA7 "); + + if(ATAID.MDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + sb.Append("(active) "); + } + + sb.AppendLine().Append("Ultra DMA: "); + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + { + sb.Append("UDMA0 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode0)) + sb.Append("(active) "); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + { + sb.Append("UDMA1 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode1)) + sb.Append("(active) "); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + { + sb.Append("UDMA2 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode2)) + sb.Append("(active) "); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + { + sb.Append("UDMA3 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode3)) + sb.Append("(active) "); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + { + sb.Append("UDMA4 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode4)) + sb.Append("(active) "); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + { + sb.Append("UDMA5 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode5)) + sb.Append("(active) "); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + { + sb.Append("UDMA6 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode6)) + sb.Append("(active) "); + } + + if(ATAID.UDMASupported.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + { + sb.Append("UDMA7 "); + + if(ATAID.UDMAActive.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TransferMode.Mode7)) + sb.Append("(active) "); + } + + if(ATAID.MinMDMACycleTime != 0 && + ATAID.RecMDMACycleTime != 0) + sb.AppendLine(). + AppendFormat("At minimum {0} ns. transfer cycle time per word in MDMA, " + "{1} ns. recommended", + ATAID.MinMDMACycleTime, ATAID.RecMDMACycleTime); + + if(ATAID.MinPIOCycleTimeNoFlow != 0) + sb.AppendLine(). + AppendFormat("At minimum {0} ns. transfer cycle time per word in PIO, " + "without flow control", + ATAID.MinPIOCycleTimeNoFlow); + + if(ATAID.MinPIOCycleTimeFlow != 0) + sb.AppendLine(). + AppendFormat("At minimum {0} ns. transfer cycle time per word in PIO, " + "with IORDY flow control", + ATAID.MinPIOCycleTimeFlow); + + if(ATAID.MaxQueueDepth != 0) + sb.AppendLine().AppendFormat("{0} depth of queue maximum", ATAID.MaxQueueDepth + 1); + + if(atapi) + { + if(ATAID.PacketBusRelease != 0) + sb.AppendLine().AppendFormat("{0} ns. typical to release bus from receipt of PACKET", + ATAID.PacketBusRelease); + + if(ATAID.ServiceBusyClear != 0) + sb.AppendLine().AppendFormat("{0} ns. typical to clear BSY bit from receipt of SERVICE", + ATAID.ServiceBusyClear); + } + + if((ATAID.TransportMajorVersion & 0xF000) >> 12 == 0x1 || + (ATAID.TransportMajorVersion & 0xF000) >> 12 == 0xE) + { + if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.Clear)) + { + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + Gen1Speed)) + sb.AppendLine().Append("SATA 1.5Gb/s is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + Gen2Speed)) + sb.AppendLine().Append("SATA 3.0Gb/s is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + Gen3Speed)) + sb.AppendLine().Append("SATA 6.0Gb/s is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + PowerReceipt)) + sb.AppendLine().Append("Receipt of host initiated power management requests is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + PHYEventCounter)) + sb.AppendLine().Append("PHY Event counters are supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + HostSlumbTrans)) + sb.AppendLine().Append("Supports host automatic partial to slumber transitions is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + DevSlumbTrans)) + sb.AppendLine().Append("Supports device automatic partial to slumber transitions is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.NCQ)) + { + sb.AppendLine().Append("NCQ is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + NCQPriority)) + sb.AppendLine().Append("NCQ priority is supported"); + + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + UnloadNCQ)) + sb.AppendLine().Append("Unload is supported with outstanding NCQ commands"); + } + } + + if(!ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2. + Clear)) + { + if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + Clear) && + ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.NCQ)) + { + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SATACapabilitiesBit2.NCQMgmt)) + sb.AppendLine().Append("NCQ queue management is supported"); + + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SATACapabilitiesBit2.NCQStream)) + sb.AppendLine().Append("NCQ streaming is supported"); + } + + if(atapi) + { + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SATACapabilitiesBit2.HostEnvDetect)) + sb.AppendLine().Append("ATAPI device supports host environment detection"); + + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SATACapabilitiesBit2.DevAttSlimline)) + sb.AppendLine().Append("ATAPI device supports attention on slimline connected devices"); + } + + //sb.AppendFormat("Negotiated speed = {0}", ((ushort)ATAID.SATACapabilities2 & 0x000E) >> 1); + } + } + + if(ATAID.InterseekDelay != 0x0000 && + ATAID.InterseekDelay != 0xFFFF) + sb.AppendLine().AppendFormat("{0} microseconds of interseek delay for ISO-7779 acoustic testing", + ATAID.InterseekDelay); + + if((ushort)ATAID.DeviceFormFactor != 0x0000 && + (ushort)ATAID.DeviceFormFactor != 0xFFFF) + switch(ATAID.DeviceFormFactor) + { + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.FiveAndQuarter: + sb.AppendLine().Append("Device nominal size is 5.25\""); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.ThreeAndHalf: + sb.AppendLine().Append("Device nominal size is 3.5\""); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.TwoAndHalf: + sb.AppendLine().Append("Device nominal size is 2.5\""); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.OnePointEight: + sb.AppendLine().Append("Device nominal size is 1.8\""); + + break; + case CommonTypes.Structs.Devices.ATA.Identify.DeviceFormFactorEnum.LessThanOnePointEight: + sb.AppendLine().Append("Device nominal size is smaller than 1.8\""); + + break; + default: + sb.AppendLine().AppendFormat("Device nominal size field value {0} is unknown", + ATAID.DeviceFormFactor); + + break; + } + + if(atapi) + if(ATAID.ATAPIByteCount > 0) + sb.AppendLine().AppendFormat("{0} bytes count limit for ATAPI", ATAID.ATAPIByteCount); + + if(cfa) + if((ATAID.CFAPowerMode & 0x8000) == 0x8000) + { + sb.AppendLine().Append("CompactFlash device supports power mode 1"); + + if((ATAID.CFAPowerMode & 0x2000) == 0x2000) + sb.AppendLine().Append("CompactFlash power mode 1 required for one or more commands"); + + if((ATAID.CFAPowerMode & 0x1000) == 0x1000) + sb.AppendLine().Append("CompactFlash power mode 1 is disabled"); + + sb.AppendLine().AppendFormat("CompactFlash device uses a maximum of {0} mA", + ATAID.CFAPowerMode & 0x0FFF); + } + + sb.AppendLine(); + + sb.AppendLine().Append("Command set and features:"); + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Nop)) + { + sb.AppendLine().Append("NOP is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Nop)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.ReadBuffer)) + { + sb.AppendLine().Append("READ BUFFER is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.ReadBuffer)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteBuffer)) + { + sb.AppendLine().Append("WRITE BUFFER is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteBuffer)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.HPA)) + { + sb.AppendLine().Append("Host Protected Area is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.HPA)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.DeviceReset)) + { + sb.AppendLine().Append("DEVICE RESET is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.DeviceReset)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Service)) + { + sb.AppendLine().Append("SERVICE interrupt is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Service)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Release)) + { + sb.AppendLine().Append("Release is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Release)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.LookAhead)) + { + sb.AppendLine().Append("Look-ahead read is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.LookAhead)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteCache)) + { + sb.AppendLine().Append("Write cache is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.WriteCache)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Packet)) + { + sb.AppendLine().Append("PACKET is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.Packet)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.PowerManagement)) + { + sb.AppendLine().Append("Power management is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit. + PowerManagement)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.RemovableMedia)) + { + sb.AppendLine().Append("Removable media feature set is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit. + RemovableMedia)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SecurityMode)) + { + sb.AppendLine().Append("Security mode is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SecurityMode)) + sb.Append(" and enabled"); + } + + if(ATAID.Capabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit.LBASupport)) + sb.AppendLine().Append("28-bit LBA is supported"); + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.MustBeSet) && + !ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.MustBeClear)) + { + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) + { + sb.AppendLine().Append("48-bit LBA is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.LBA48)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.FlushCache)) + { + sb.AppendLine().Append("FLUSH CACHE is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + FlushCache)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.FlushCacheExt)) + { + sb.AppendLine().Append("FLUSH CACHE EXT is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + FlushCacheExt)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DCO)) + { + sb.AppendLine().Append("Device Configuration Overlay feature set is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DCO)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.AAM)) + { + sb.AppendLine().Append("Automatic Acoustic Management is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.AAM)) + sb.AppendFormat(" and enabled with value {0} (vendor recommends {1}", ATAID.CurrentAAM, + ATAID.RecommendedAAM); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.SetMax)) + { + sb.AppendLine().Append("SET MAX security extension is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.SetMax)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + AddressOffsetReservedAreaBoot)) + { + sb.AppendLine().Append("Address Offset Reserved Area Boot is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + AddressOffsetReservedAreaBoot)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + SetFeaturesRequired)) + sb.AppendLine().Append("SET FEATURES is required before spin-up"); + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.PowerUpInStandby)) + { + sb.AppendLine().Append("Power-up in standby is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + PowerUpInStandby)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + RemovableNotification)) + { + sb.AppendLine().Append("Removable Media Status Notification is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + RemovableNotification)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.APM)) + { + sb.AppendLine().Append("Advanced Power Management is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.APM)) + sb.AppendFormat(" and enabled with value {0}", ATAID.CurrentAPM); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.CompactFlash)) + { + sb.AppendLine().Append("CompactFlash feature set is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + CompactFlash)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.RWQueuedDMA)) + { + sb.AppendLine().Append("READ DMA QUEUED and WRITE DMA QUEUED are supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + RWQueuedDMA)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2.DownloadMicrocode)) + { + sb.AppendLine().Append("DOWNLOAD MICROCODE is supported"); + + if(ATAID.EnabledCommandSet2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit2. + DownloadMicrocode)) + sb.Append(" and enabled"); + } + } + + if(ATAID.CommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SMART)) + { + sb.AppendLine().Append("S.M.A.R.T. is supported"); + + if(ATAID.EnabledCommandSet.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit.SMART)) + sb.Append(" and enabled"); + } + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. + Supported)) + sb.AppendLine().Append("S.M.A.R.T. Command Transport is supported"); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && + !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear)) + { + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.SMARTSelfTest)) + { + sb.AppendLine().Append("S.M.A.R.T. self-testing is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + SMARTSelfTest)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.SMARTLog)) + { + sb.AppendLine().Append("S.M.A.R.T. error logging is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + SMARTLog)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.IdleImmediate)) + { + sb.AppendLine().Append("IDLE IMMEDIATE with UNLOAD FEATURE is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + IdleImmediate)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WriteURG)) + sb.AppendLine().Append("URG bit is supported in WRITE STREAM DMA EXT and WRITE STREAM EXT"); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.ReadURG)) + sb.AppendLine().Append("URG bit is supported in READ STREAM DMA EXT and READ STREAM EXT"); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.WWN)) + sb.AppendLine().Append("Device has a World Wide Name"); + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.FUAWriteQ)) + { + sb.AppendLine().Append("WRITE DMA QUEUED FUA EXT is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + FUAWriteQ)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.FUAWrite)) + { + sb.AppendLine().Append("WRITE DMA FUA EXT and WRITE MULTIPLE FUA EXT are supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + FUAWrite)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.GPL)) + { + sb.AppendLine().Append("General Purpose Logging is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.GPL)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.Streaming)) + { + sb.AppendLine().Append("Streaming feature set is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + Streaming)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MCPT)) + { + sb.AppendLine().Append("Media Card Pass Through command set is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MCPT)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MediaSerial)) + { + sb.AppendLine().Append("Media Serial is supported"); + + if(ATAID.EnabledCommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3. + MediaSerial)) + sb.Append(" and valid"); + } + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.MustBeSet) && + !ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.MustBeClear)) + { + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DSN)) + { + sb.AppendLine().Append("DSN feature set is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DSN)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.AMAC)) + { + sb.AppendLine().Append("Accessible Max Address Configuration is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.AMAC)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.ExtPowerCond)) + { + sb.AppendLine().Append("Extended Power Conditions are supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. + ExtPowerCond)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.ExtStatusReport)) + { + sb.AppendLine().Append("Extended Status Reporting is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. + ExtStatusReport)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.FreeFallControl)) + { + sb.AppendLine().Append("Free-fall control feature set is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. + FreeFallControl)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. + SegmentedDownloadMicrocode)) + { + sb.AppendLine().Append("Segmented feature in DOWNLOAD MICROCODE is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. + SegmentedDownloadMicrocode)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.RWDMAExtGpl)) + { + sb.AppendLine().Append("READ/WRITE DMA EXT GPL are supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. + RWDMAExtGpl)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WriteUnc)) + { + sb.AppendLine().Append("WRITE UNCORRECTABLE is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4. + WriteUnc)) + sb.Append(" and enabled"); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) + { + sb.AppendLine().Append("Write/Read/Verify is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) + sb.Append(" and enabled"); + + sb.AppendLine().AppendFormat("{0} sectors for Write/Read/Verify mode 2", ATAID.WRVSectorCountMode2); + sb.AppendLine().AppendFormat("{0} sectors for Write/Read/Verify mode 3", ATAID.WRVSectorCountMode3); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.WRV)) + sb.AppendLine().AppendFormat("Current Write/Read/Verify mode: {0}", ATAID.WRVMode); + } + + if(ATAID.CommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DT1825)) + { + sb.AppendLine().Append("DT1825 is supported"); + + if(ATAID.EnabledCommandSet4.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit4.DT1825)) + sb.Append(" and enabled"); + } + } + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.BlockErase)) + sb.AppendLine().Append("BLOCK ERASE EXT is supported"); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.Overwrite)) + sb.AppendLine().Append("OVERWRITE EXT is supported"); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.CryptoScramble)) + sb.AppendLine().Append("CRYPTO SCRAMBLE EXT is supported"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DeviceConfDMA)) + sb.AppendLine(). + Append("DEVICE CONFIGURATION IDENTIFY DMA and DEVICE CONFIGURATION SET DMA are supported"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ReadBufferDMA)) + sb.AppendLine().Append("READ BUFFER DMA is supported"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.WriteBufferDMA)) + sb.AppendLine().Append("WRITE BUFFER DMA is supported"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DownloadMicroCodeDMA)) + sb.AppendLine().Append("DOWNLOAD MICROCODE DMA is supported"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.SetMaxDMA)) + sb.AppendLine().Append("SET PASSWORD DMA and SET UNLOCK DMA are supported"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.Ata28)) + sb.AppendLine().Append("Not all 28-bit commands are supported"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.CFast)) + sb.AppendLine().Append("Device follows CFast specification"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.IEEE1667)) + sb.AppendLine().Append("Device follows IEEE-1667"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.DeterministicTrim)) + { + sb.AppendLine().Append("Read after TRIM is deterministic"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ReadZeroTrim)) + sb.AppendLine().Append("Read after TRIM returns empty data"); + } + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5. + LongPhysSectorAligError)) + sb.AppendLine().Append("Device supports Long Physical Sector Alignment Error Reporting Control"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.Encrypted)) + sb.AppendLine().Append("Device encrypts all user data"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.AllCacheNV)) + sb.AppendLine().Append("Device's write cache is non-volatile"); + + if(ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ZonedBit0) || + ATAID.CommandSet5.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit5.ZonedBit1)) + sb.AppendLine().Append("Device is zoned"); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3.Sanitize)) + { + sb.AppendLine().Append("Sanitize feature set is supported"); + + sb.AppendLine(). + Append(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3. + SanitizeCommands) + ? "Sanitize commands are specified by ACS-3 or higher" + : "Sanitize commands are specified by ACS-2"); + + if(ATAID.Capabilities3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CapabilitiesBit3. + SanitizeAntifreeze)) + sb.AppendLine().Append("SANITIZE ANTIFREEZE LOCK EXT is supported"); + } + + if(!ata1 && + maxatalevel >= 8) + if(ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit.Set) && + !ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit. + Clear) && + ATAID.TrustedComputing.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.TrustedComputingBit. + TrustedComputing)) + sb.AppendLine().Append("Trusted Computing feature set is supported"); + + if((ATAID.TransportMajorVersion & 0xF000) >> 12 == 0x1 || + (ATAID.TransportMajorVersion & 0xF000) >> 12 == 0xE) + { + if(!ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit.Clear)) + if(ATAID.SATACapabilities.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit. + ReadLogDMAExt)) + sb.AppendLine().Append("READ LOG DMA EXT is supported"); + + if(!ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2. + Clear)) + if(ATAID.SATACapabilities2.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATACapabilitiesBit2. + FPDMAQ)) + sb.AppendLine().Append("RECEIVE FPDMA QUEUED and SEND FPDMA QUEUED are supported"); + + if(!ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.Clear)) + { + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + NonZeroBufferOffset)) + { + sb.AppendLine().Append("Non-zero buffer offsets are supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + NonZeroBufferOffset)) + sb.Append(" and enabled"); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.DMASetup)) + { + sb.AppendLine().Append("DMA Setup auto-activation is supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + DMASetup)) + sb.Append(" and enabled"); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + InitPowerMgmt)) + { + sb.AppendLine().Append("Device-initiated power management is supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + InitPowerMgmt)) + sb.Append(" and enabled"); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit.InOrderData)) + { + sb.AppendLine().Append("In-order data delivery is supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + InOrderData)) + sb.Append(" and enabled"); + } + + if(!atapi) + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + HardwareFeatureControl)) + { + sb.AppendLine().Append("Hardware Feature Control is supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SATAFeaturesBit.HardwareFeatureControl)) + sb.Append(" and enabled"); + } + + if(atapi) + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + AsyncNotification)) + { + sb.AppendLine().Append("Asynchronous notification is supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SATAFeaturesBit.AsyncNotification)) + sb.Append(" and enabled"); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + SettingsPreserve)) + { + sb.AppendLine().Append("Software Settings Preservation is supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + SettingsPreserve)) + sb.Append(" and enabled"); + } + + if(ATAID.SATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + NCQAutoSense)) + sb.AppendLine().Append("NCQ Autosense is supported"); + + if(ATAID.EnabledSATAFeatures.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SATAFeaturesBit. + EnabledSlumber)) + sb.AppendLine().Append("Automatic Partial to Slumber transitions are enabled"); + } + } + + if((ATAID.RemovableStatusSet & 0x03) > 0) + sb.AppendLine().Append("Removable Media Status Notification feature set is supported"); + + if(ATAID.FreeFallSensitivity != 0x00 && + ATAID.FreeFallSensitivity != 0xFF) + sb.AppendLine().AppendFormat("Free-fall sensitivity set to {0}", ATAID.FreeFallSensitivity); + + if(ATAID.DataSetMgmt.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.DataSetMgmtBit.Trim)) + sb.AppendLine().Append("TRIM is supported"); + + if(ATAID.DataSetMgmtSize > 0) + sb.AppendLine().AppendFormat("DATA SET MANAGEMENT can receive a maximum of {0} blocks of 512 bytes", + ATAID.DataSetMgmtSize); + + sb.AppendLine().AppendLine(); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Supported)) + { + sb.AppendLine("Security:"); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enabled)) + { + sb.AppendLine("Security is enabled"); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SecurityStatusBit.Locked) + ? "Security is locked" : "Security is not locked"); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SecurityStatusBit.Frozen) + ? "Security is frozen" : "Security is not frozen"); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SecurityStatusBit.Expired) + ? "Security count has expired" : "Security count has not expired"); + + sb.AppendLine(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify. + SecurityStatusBit.Maximum) + ? "Security level is maximum" : "Security level is high"); + } + else + sb.AppendLine("Security is not enabled"); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enhanced)) + sb.AppendLine("Supports enhanced security erase"); + + sb.AppendFormat("{0} minutes to complete secure erase", ATAID.SecurityEraseTime * 2).AppendLine(); + + if(ATAID.SecurityStatus.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SecurityStatusBit.Enhanced)) + sb.AppendFormat("{0} minutes to complete enhanced secure erase", + ATAID.EnhancedSecurityEraseTime * 2).AppendLine(); + + sb.AppendFormat("Master password revision code: {0}", ATAID.MasterPasswordRevisionCode).AppendLine(); + } + + if(ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeSet) && + !ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.MustBeClear) && + ATAID.CommandSet3.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.CommandSetBit3.Streaming)) + { + sb.AppendLine().AppendLine("Streaming:"); + sb.AppendFormat("Minimum request size is {0}", ATAID.StreamMinReqSize); + sb.AppendFormat("Streaming transfer time in PIO is {0}", ATAID.StreamTransferTimePIO); + sb.AppendFormat("Streaming transfer time in DMA is {0}", ATAID.StreamTransferTimeDMA); + sb.AppendFormat("Streaming access latency is {0}", ATAID.StreamAccessLatency); + sb.AppendFormat("Streaming performance granularity is {0}", ATAID.StreamPerformanceGranularity); + } + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. + Supported)) + { + sb.AppendLine().AppendLine("S.M.A.R.T. Command Transport (SCT):"); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. + LongSectorAccess)) + sb.AppendLine("SCT Long Sector Address is supported"); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. + WriteSame)) + sb.AppendLine("SCT Write Same is supported"); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. + ErrorRecoveryControl)) + sb.AppendLine("SCT Error Recovery Control is supported"); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. + FeaturesControl)) + sb.AppendLine("SCT Features Control is supported"); + + if(ATAID.SCTCommandTransport.HasFlag(CommonTypes.Structs.Devices.ATA.Identify.SCTCommandTransportBit. + DataTables)) + sb.AppendLine("SCT Data Tables are supported"); + } + + if((ATAID.NVCacheCaps & 0x0010) == 0x0010) + { + sb.AppendLine().AppendLine("Non-Volatile Cache:"); + sb.AppendLine().AppendFormat("Version {0}", (ATAID.NVCacheCaps & 0xF000) >> 12).AppendLine(); + + if((ATAID.NVCacheCaps & 0x0001) == 0x0001) + { + sb.Append("Power mode feature set is supported"); + + if((ATAID.NVCacheCaps & 0x0002) == 0x0002) + sb.Append(" and enabled"); + + sb.AppendLine(); + + sb.AppendLine().AppendFormat("Version {0}", (ATAID.NVCacheCaps & 0x0F00) >> 8).AppendLine(); + } + + sb.AppendLine().AppendFormat("Non-Volatile Cache is {0} bytes", ATAID.NVCacheSize * logicalSectorSize). + AppendLine(); + } + + #if DEBUG + sb.AppendLine(); + + if(ATAID.VendorWord9 != 0x0000 && + ATAID.VendorWord9 != 0xFFFF) + sb.AppendFormat("Word 9: 0x{0:X4}", ATAID.VendorWord9).AppendLine(); + + if((ATAID.VendorWord47 & 0x7F) != 0x7F && + (ATAID.VendorWord47 & 0x7F) != 0x00) + sb.AppendFormat("Word 47 bits 15 to 8: 0x{0:X2}", ATAID.VendorWord47).AppendLine(); + + if(ATAID.VendorWord51 != 0x00 && + ATAID.VendorWord51 != 0xFF) + sb.AppendFormat("Word 51 bits 7 to 0: 0x{0:X2}", ATAID.VendorWord51).AppendLine(); + + if(ATAID.VendorWord52 != 0x00 && + ATAID.VendorWord52 != 0xFF) + sb.AppendFormat("Word 52 bits 7 to 0: 0x{0:X2}", ATAID.VendorWord52).AppendLine(); + + if(ATAID.ReservedWord64 != 0x00 && + ATAID.ReservedWord64 != 0xFF) + sb.AppendFormat("Word 64 bits 15 to 8: 0x{0:X2}", ATAID.ReservedWord64).AppendLine(); + + if(ATAID.ReservedWord70 != 0x0000 && + ATAID.ReservedWord70 != 0xFFFF) + sb.AppendFormat("Word 70: 0x{0:X4}", ATAID.ReservedWord70).AppendLine(); + + if(ATAID.ReservedWord73 != 0x0000 && + ATAID.ReservedWord73 != 0xFFFF) + sb.AppendFormat("Word 73: 0x{0:X4}", ATAID.ReservedWord73).AppendLine(); + + if(ATAID.ReservedWord74 != 0x0000 && + ATAID.ReservedWord74 != 0xFFFF) + sb.AppendFormat("Word 74: 0x{0:X4}", ATAID.ReservedWord74).AppendLine(); + + if(ATAID.ReservedWord116 != 0x0000 && + ATAID.ReservedWord116 != 0xFFFF) + sb.AppendFormat("Word 116: 0x{0:X4}", ATAID.ReservedWord116).AppendLine(); + + for(int i = 0; i < ATAID.ReservedWords121.Length; i++) + if(ATAID.ReservedWords121[i] != 0x0000 && + ATAID.ReservedWords121[i] != 0xFFFF) + sb.AppendFormat("Word {1}: 0x{0:X4}", ATAID.ReservedWords121[i], 121 + i).AppendLine(); + + for(int i = 0; i < ATAID.ReservedWords129.Length; i++) + if(ATAID.ReservedWords129[i] != 0x0000 && + ATAID.ReservedWords129[i] != 0xFFFF) + sb.AppendFormat("Word {1}: 0x{0:X4}", ATAID.ReservedWords129[i], 129 + i).AppendLine(); + + for(int i = 0; i < ATAID.ReservedCFA.Length; i++) + if(ATAID.ReservedCFA[i] != 0x0000 && + ATAID.ReservedCFA[i] != 0xFFFF) + sb.AppendFormat("Word {1} (CFA): 0x{0:X4}", ATAID.ReservedCFA[i], 161 + i).AppendLine(); + + if(ATAID.ReservedWord174 != 0x0000 && + ATAID.ReservedWord174 != 0xFFFF) + sb.AppendFormat("Word 174: 0x{0:X4}", ATAID.ReservedWord174).AppendLine(); + + if(ATAID.ReservedWord175 != 0x0000 && + ATAID.ReservedWord175 != 0xFFFF) + sb.AppendFormat("Word 175: 0x{0:X4}", ATAID.ReservedWord175).AppendLine(); + + if(ATAID.ReservedCEATAWord207 != 0x0000 && + ATAID.ReservedCEATAWord207 != 0xFFFF) + sb.AppendFormat("Word 207 (CE-ATA): 0x{0:X4}", ATAID.ReservedCEATAWord207).AppendLine(); + + if(ATAID.ReservedCEATAWord208 != 0x0000 && + ATAID.ReservedCEATAWord208 != 0xFFFF) + sb.AppendFormat("Word 208 (CE-ATA): 0x{0:X4}", ATAID.ReservedCEATAWord208).AppendLine(); + + if(ATAID.NVReserved != 0x00 && + ATAID.NVReserved != 0xFF) + sb.AppendFormat("Word 219 bits 15 to 8: 0x{0:X2}", ATAID.NVReserved).AppendLine(); + + if(ATAID.WRVReserved != 0x00 && + ATAID.WRVReserved != 0xFF) + sb.AppendFormat("Word 220 bits 15 to 8: 0x{0:X2}", ATAID.WRVReserved).AppendLine(); + + if(ATAID.ReservedWord221 != 0x0000 && + ATAID.ReservedWord221 != 0xFFFF) + sb.AppendFormat("Word 221: 0x{0:X4}", ATAID.ReservedWord221).AppendLine(); + + for(int i = 0; i < ATAID.ReservedCEATA224.Length; i++) + if(ATAID.ReservedCEATA224[i] != 0x0000 && + ATAID.ReservedCEATA224[i] != 0xFFFF) + sb.AppendFormat("Word {1} (CE-ATA): 0x{0:X4}", ATAID.ReservedCEATA224[i], 224 + i).AppendLine(); + + for(int i = 0; i < ATAID.ReservedWords.Length; i++) + if(ATAID.ReservedWords[i] != 0x0000 && + ATAID.ReservedWords[i] != 0xFFFF) + sb.AppendFormat("Word {1}: 0x{0:X4}", ATAID.ReservedWords[i], 236 + i).AppendLine(); + #endif + return sb.ToString(); } } \ No newline at end of file diff --git a/ATA/Registers.cs b/ATA/Registers.cs index 2ff0303..d35f9fc 100644 --- a/ATA/Registers.cs +++ b/ATA/Registers.cs @@ -32,83 +32,82 @@ using System.Runtime.InteropServices; -namespace Aaru.Decoders.ATA +namespace Aaru.Decoders.ATA; + +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaRegistersChs { - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct AtaRegistersChs - { - public byte Feature; - public byte SectorCount; - public byte Sector; - public byte CylinderLow; - public byte CylinderHigh; - public byte DeviceHead; - public byte Command; - } + public byte Feature; + public byte SectorCount; + public byte Sector; + public byte CylinderLow; + public byte CylinderHigh; + public byte DeviceHead; + public byte Command; +} - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct AtaRegistersLba28 - { - public byte Feature; - public byte SectorCount; - public byte LbaLow; - public byte LbaMid; - public byte LbaHigh; - public byte DeviceHead; - public byte Command; - } +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaRegistersLba28 +{ + public byte Feature; + public byte SectorCount; + public byte LbaLow; + public byte LbaMid; + public byte LbaHigh; + public byte DeviceHead; + public byte Command; +} - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct AtaRegistersLba48 - { - public ushort Feature; - public ushort SectorCount; - public byte LbaLowPrevious; - public byte LbaLowCurrent; - public byte LbaMidPrevious; - public byte LbaMidCurrent; - public byte LbaHighPrevious; - public byte LbaHighCurrent; - public byte DeviceHead; - public byte Command; - } +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaRegistersLba48 +{ + public ushort Feature; + public ushort SectorCount; + public byte LbaLowPrevious; + public byte LbaLowCurrent; + public byte LbaMidPrevious; + public byte LbaMidCurrent; + public byte LbaHighPrevious; + public byte LbaHighCurrent; + public byte DeviceHead; + public byte Command; +} - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct AtaErrorRegistersChs - { - public byte Status; - public byte Error; - public byte SectorCount; - public byte Sector; - public byte CylinderLow; - public byte CylinderHigh; - public byte DeviceHead; - } +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaErrorRegistersChs +{ + public byte Status; + public byte Error; + public byte SectorCount; + public byte Sector; + public byte CylinderLow; + public byte CylinderHigh; + public byte DeviceHead; +} - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct AtaErrorRegistersLba28 - { - public byte Status; - public byte Error; - public byte SectorCount; - public byte LbaLow; - public byte LbaMid; - public byte LbaHigh; - public byte DeviceHead; - } +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaErrorRegistersLba28 +{ + public byte Status; + public byte Error; + public byte SectorCount; + public byte LbaLow; + public byte LbaMid; + public byte LbaHigh; + public byte DeviceHead; +} - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - public struct AtaErrorRegistersLba48 - { - public byte Status; - public byte Error; - public ushort SectorCount; - public byte LbaLowPrevious; - public byte LbaLowCurrent; - public byte LbaMidPrevious; - public byte LbaMidCurrent; - public byte LbaHighPrevious; - public byte LbaHighCurrent; - public byte DeviceHead; - } +[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] +public struct AtaErrorRegistersLba48 +{ + public byte Status; + public byte Error; + public ushort SectorCount; + public byte LbaLowPrevious; + public byte LbaLowCurrent; + public byte LbaMidPrevious; + public byte LbaMidCurrent; + public byte LbaHighPrevious; + public byte LbaHighCurrent; + public byte DeviceHead; } \ No newline at end of file diff --git a/Bluray/BCA.cs b/Bluray/BCA.cs index eaef404..2b37d6e 100644 --- a/Bluray/BCA.cs +++ b/Bluray/BCA.cs @@ -36,89 +36,88 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.Bluray +namespace Aaru.Decoders.Bluray; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class BCA { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class BCA + #region Public structures + public struct BurstCuttingArea { - #region Public structures - public struct BurstCuttingArea - { - /// Bytes 0 to 1 Always 66 - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 to 67 BCA data - public byte[] BCA; - } - #endregion Public structures - #region Public methods - public static BurstCuttingArea? Decode(byte[] BCAResponse) - { - if(BCAResponse == null) - return null; - - if(BCAResponse.Length != 68) - { - AaruConsole.DebugWriteLine("BD BCA decoder", "Found incorrect Blu-ray BCA size ({0} bytes)", - BCAResponse.Length); - - return null; - } - - var decoded = new BurstCuttingArea - { - DataLength = BigEndianBitConverter.ToUInt16(BCAResponse, 0), - Reserved1 = BCAResponse[2], - Reserved2 = BCAResponse[3], - BCA = new byte[64] - }; - - Array.Copy(BCAResponse, 4, decoded.BCA, 0, 64); - - return decoded; - } - - public static string Prettify(BurstCuttingArea? BCAResponse) - { - if(BCAResponse == null) - return null; - - BurstCuttingArea response = BCAResponse.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 - - sb.AppendFormat("Blu-ray Burst Cutting Area in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.BCA, 80)); - - return sb.ToString(); - } - - public static string Prettify(byte[] BCAResponse) => Prettify(Decode(BCAResponse)); - #endregion Public methods + /// Bytes 0 to 1 Always 66 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 to 67 BCA data + public byte[] BCA; } + #endregion Public structures + #region Public methods + public static BurstCuttingArea? Decode(byte[] BCAResponse) + { + if(BCAResponse == null) + return null; + + if(BCAResponse.Length != 68) + { + AaruConsole.DebugWriteLine("BD BCA decoder", "Found incorrect Blu-ray BCA size ({0} bytes)", + BCAResponse.Length); + + return null; + } + + var decoded = new BurstCuttingArea + { + DataLength = BigEndianBitConverter.ToUInt16(BCAResponse, 0), + Reserved1 = BCAResponse[2], + Reserved2 = BCAResponse[3], + BCA = new byte[64] + }; + + Array.Copy(BCAResponse, 4, decoded.BCA, 0, 64); + + return decoded; + } + + public static string Prettify(BurstCuttingArea? BCAResponse) + { + if(BCAResponse == null) + return null; + + BurstCuttingArea response = BCAResponse.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 + + sb.AppendFormat("Blu-ray Burst Cutting Area in hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.BCA, 80)); + + return sb.ToString(); + } + + public static string Prettify(byte[] BCAResponse) => Prettify(Decode(BCAResponse)); + #endregion Public methods } \ No newline at end of file diff --git a/Bluray/Cartridge.cs b/Bluray/Cartridge.cs index 83581db..bd65083 100644 --- a/Bluray/Cartridge.cs +++ b/Bluray/Cartridge.cs @@ -36,145 +36,144 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.Bluray +namespace Aaru.Decoders.Bluray; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global"), + SuppressMessage("ReSharper", "UnassignedField.Global")] +public static class Cartridge { - // 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 - [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 { - #region Public structures - public struct CartridgeStatus + /// Bytes 0 to 1 Always 6 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 Medium is inserted in a cartridge + public bool Cartridge; + /// Byte 4, bit 6 Medium taken out / put in a cartridge + public bool OUT; + /// Byte 4, bits 5 to 3 Reserved + public byte Reserved3; + /// Byte 4, bit 2 Cartridge sets write protection + public bool CWP; + /// Byte 4, bits 1 to 0 Reserved + public byte Reserved4; + /// Byte 5 Reserved + public byte Reserved5; + /// Byte 6 Reserved + public byte Reserved6; + /// Byte 7 Reserved + public byte Reserved7; + } + #endregion Public structures + #region Public methods + public static CartridgeStatus? Decode(byte[] CSResponse) + { + if(CSResponse == null) + return null; + + if(CSResponse.Length != 8) { - /// Bytes 0 to 1 Always 6 - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4, bit 7 Medium is inserted in a cartridge - public bool Cartridge; - /// Byte 4, bit 6 Medium taken out / put in a cartridge - public bool OUT; - /// Byte 4, bits 5 to 3 Reserved - public byte Reserved3; - /// Byte 4, bit 2 Cartridge sets write protection - public bool CWP; - /// Byte 4, bits 1 to 0 Reserved - public byte Reserved4; - /// Byte 5 Reserved - public byte Reserved5; - /// Byte 6 Reserved - public byte Reserved6; - /// Byte 7 Reserved - public byte Reserved7; - } - #endregion Public structures - #region Public methods - public static CartridgeStatus? Decode(byte[] CSResponse) - { - if(CSResponse == null) - return null; + AaruConsole.DebugWriteLine("BD Cartridge Status decoder", + "Found incorrect Blu-ray Cartridge Status size ({0} bytes)", + CSResponse.Length); - if(CSResponse.Length != 8) - { - AaruConsole.DebugWriteLine("BD Cartridge Status decoder", - "Found incorrect Blu-ray Cartridge Status size ({0} bytes)", - CSResponse.Length); - - return null; - } - - var decoded = new CartridgeStatus - { - 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] - }; - - return decoded; + return null; } - public static string Prettify(CartridgeStatus? CSResponse) + var decoded = new CartridgeStatus { - if(CSResponse == null) - return null; + 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] + }; - CartridgeStatus response = CSResponse.Value; + return decoded; + } - var sb = new StringBuilder(); + public static string Prettify(CartridgeStatus? CSResponse) + { + if(CSResponse == null) + return null; + + CartridgeStatus response = CSResponse.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(); + + 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"); + } + else + { + sb.AppendLine("Media is not in a cartridge"); #if DEBUG - if(response.Reserved1 != 0) - sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine(); + if(response.OUT) + sb.AppendLine("Media has out bit marked, shouldn't"); - 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(); + if(response.CWP) + sb.AppendLine("Media has write protection bit marked, shouldn't"); #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"); - } - 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 - } - - return sb.ToString(); } - public static string Prettify(byte[] CSResponse) => Prettify(Decode(CSResponse)); - #endregion Public methods + return sb.ToString(); } + + public static string Prettify(byte[] CSResponse) => Prettify(Decode(CSResponse)); + #endregion Public methods } \ No newline at end of file diff --git a/Bluray/DDS.cs b/Bluray/DDS.cs index a4edf77..e2c0cf4 100644 --- a/Bluray/DDS.cs +++ b/Bluray/DDS.cs @@ -36,194 +36,193 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.Bluray +namespace Aaru.Decoders.Bluray; + +/// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DDS { - /// 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class DDS + #region Private constants + /// Disc Definition Structure Identifier "DS" + const ushort DDSIdentifier = 0x4453; + #endregion Private constants + + #region Public structures + public struct DiscDefinitionStructure { - #region Private constants - /// Disc Definition Structure Identifier "DS" - const ushort DDSIdentifier = 0x4453; - #endregion Private constants - - #region Public structures - public struct DiscDefinitionStructure - { - /// Bytes 0 to 1 Data Length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 5 "DS" - public ushort Signature; - /// Byte 6 DDS format - public byte Format; - /// Byte 7 Reserved - public byte Reserved3; - /// Bytes 8 to 11 DDS update count - public uint UpdateCount; - /// Bytes 12 to 19 Reserved - public ulong Reserved4; - /// Bytes 20 to 23 First PSN of Drive Area - public uint DriveAreaPSN; - /// Bytes 24 to 27 Reserved - public uint Reserved5; - /// Bytes 28 to 31 First PSN of Defect List - public uint DefectListPSN; - /// Bytes 32 to 35 Reserved - public uint Reserved6; - /// Bytes 36 to 39 PSN of LSN 0 of user data area - public uint PSNofLSNZero; - /// Bytes 40 to 43 Last LSN of user data area - public uint LastUserAreaLSN; - /// Bytes 44 to 47 ISA0 size - public uint ISA0; - /// Bytes 48 to 51 OSA size - public uint OSA; - /// Bytes 52 to 55 ISA1 size - public uint ISA1; - /// Byte 56 Spare Area full flags - public byte SpareAreaFullFlags; - /// Byte 57 Reserved - public byte Reserved7; - /// Byte 58 Disc type specific field - public byte DiscTypeSpecificField1; - /// Byte 59 Reserved - public byte Reserved8; - /// Byte 60 to 63 Disc type specific field - public uint DiscTypeSpecificField2; - /// Byte 64 to 67 Reserved - public uint Reserved9; - /// Bytes 68 to 99 Status bits of INFO1/2 and PAC1/2 on L0 and L1 - public byte[] StatusBits; - /// Bytes 100 to end Disc type specific data - public byte[] DiscTypeSpecificData; - } - #endregion Public structures - - #region Public methods - public static DiscDefinitionStructure? Decode(byte[] DDSResponse) - { - if(DDSResponse == null) - return null; - - var decoded = new DiscDefinitionStructure - { - DataLength = BigEndianBitConverter.ToUInt16(DDSResponse, 0), - Reserved1 = DDSResponse[2], - Reserved2 = DDSResponse[3], - Signature = BigEndianBitConverter.ToUInt16(DDSResponse, 4) - }; - - if(decoded.Signature != DDSIdentifier) - { - AaruConsole.DebugWriteLine("BD DDS decoder", "Found incorrect DDS signature (0x{0:X4})", - decoded.Signature); - - return null; - } - - decoded.Format = DDSResponse[6]; - decoded.Reserved3 = DDSResponse[7]; - decoded.UpdateCount = BigEndianBitConverter.ToUInt32(DDSResponse, 8); - decoded.Reserved4 = BigEndianBitConverter.ToUInt64(DDSResponse, 12); - decoded.DriveAreaPSN = BigEndianBitConverter.ToUInt32(DDSResponse, 20); - decoded.Reserved5 = BigEndianBitConverter.ToUInt32(DDSResponse, 24); - decoded.DefectListPSN = BigEndianBitConverter.ToUInt32(DDSResponse, 28); - decoded.Reserved6 = BigEndianBitConverter.ToUInt32(DDSResponse, 32); - decoded.PSNofLSNZero = BigEndianBitConverter.ToUInt32(DDSResponse, 36); - decoded.LastUserAreaLSN = BigEndianBitConverter.ToUInt32(DDSResponse, 40); - decoded.ISA0 = BigEndianBitConverter.ToUInt32(DDSResponse, 44); - decoded.OSA = BigEndianBitConverter.ToUInt32(DDSResponse, 48); - decoded.ISA1 = BigEndianBitConverter.ToUInt32(DDSResponse, 52); - decoded.SpareAreaFullFlags = DDSResponse[56]; - decoded.Reserved7 = DDSResponse[57]; - decoded.DiscTypeSpecificField1 = DDSResponse[58]; - decoded.Reserved8 = DDSResponse[59]; - decoded.DiscTypeSpecificField2 = BigEndianBitConverter.ToUInt32(DDSResponse, 60); - decoded.Reserved9 = BigEndianBitConverter.ToUInt32(DDSResponse, 64); - decoded.StatusBits = new byte[32]; - Array.Copy(DDSResponse, 68, decoded.StatusBits, 0, 32); - decoded.DiscTypeSpecificData = new byte[DDSResponse.Length - 100]; - Array.Copy(DDSResponse, 100, decoded.DiscTypeSpecificData, 0, DDSResponse.Length - 100); - - return decoded; - } - - public static string Prettify(DiscDefinitionStructure? DDSResponse) - { - if(DDSResponse == null) - return null; - - DiscDefinitionStructure response = DDSResponse.Value; - - 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(); - sb.AppendFormat("First PSN of Drive Area: 0x{0:X8}", response.DriveAreaPSN).AppendLine(); - sb.AppendFormat("First PSN of Defect List: 0x{0:X8}", response.DefectListPSN).AppendLine(); - sb.AppendFormat("PSN of User Data Area's LSN 0: 0x{0:X8}", response.PSNofLSNZero).AppendLine(); - sb.AppendFormat("Last User Data Area's LSN 0: 0x{0:X8}", response.LastUserAreaLSN).AppendLine(); - sb.AppendFormat("ISA0 size: {0}", response.ISA0).AppendLine(); - sb.AppendFormat("OSA size: {0}", response.OSA).AppendLine(); - sb.AppendFormat("ISA1 size: {0}", response.ISA1).AppendLine(); - sb.AppendFormat("Spare Area Full Flags: 0x{0:X2}", response.SpareAreaFullFlags).AppendLine(); - sb.AppendFormat("Disc Type Specific Field 1: 0x{0:X2}", response.DiscTypeSpecificField1).AppendLine(); - sb.AppendFormat("Disc Type Specific Field 2: 0x{0:X8}", response.DiscTypeSpecificField2).AppendLine(); - sb.AppendFormat("Blu-ray DDS Status Bits in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.StatusBits, 80)); - 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 - - return sb.ToString(); - } - - public static string Prettify(byte[] DDSResponse) => Prettify(Decode(DDSResponse)); - #endregion Public methods + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 5 "DS" + public ushort Signature; + /// Byte 6 DDS format + public byte Format; + /// Byte 7 Reserved + public byte Reserved3; + /// Bytes 8 to 11 DDS update count + public uint UpdateCount; + /// Bytes 12 to 19 Reserved + public ulong Reserved4; + /// Bytes 20 to 23 First PSN of Drive Area + public uint DriveAreaPSN; + /// Bytes 24 to 27 Reserved + public uint Reserved5; + /// Bytes 28 to 31 First PSN of Defect List + public uint DefectListPSN; + /// Bytes 32 to 35 Reserved + public uint Reserved6; + /// Bytes 36 to 39 PSN of LSN 0 of user data area + public uint PSNofLSNZero; + /// Bytes 40 to 43 Last LSN of user data area + public uint LastUserAreaLSN; + /// Bytes 44 to 47 ISA0 size + public uint ISA0; + /// Bytes 48 to 51 OSA size + public uint OSA; + /// Bytes 52 to 55 ISA1 size + public uint ISA1; + /// Byte 56 Spare Area full flags + public byte SpareAreaFullFlags; + /// Byte 57 Reserved + public byte Reserved7; + /// Byte 58 Disc type specific field + public byte DiscTypeSpecificField1; + /// Byte 59 Reserved + public byte Reserved8; + /// Byte 60 to 63 Disc type specific field + public uint DiscTypeSpecificField2; + /// Byte 64 to 67 Reserved + public uint Reserved9; + /// Bytes 68 to 99 Status bits of INFO1/2 and PAC1/2 on L0 and L1 + public byte[] StatusBits; + /// Bytes 100 to end Disc type specific data + public byte[] DiscTypeSpecificData; } + #endregion Public structures + + #region Public methods + public static DiscDefinitionStructure? Decode(byte[] DDSResponse) + { + if(DDSResponse == null) + return null; + + var decoded = new DiscDefinitionStructure + { + DataLength = BigEndianBitConverter.ToUInt16(DDSResponse, 0), + Reserved1 = DDSResponse[2], + Reserved2 = DDSResponse[3], + Signature = BigEndianBitConverter.ToUInt16(DDSResponse, 4) + }; + + if(decoded.Signature != DDSIdentifier) + { + AaruConsole.DebugWriteLine("BD DDS decoder", "Found incorrect DDS signature (0x{0:X4})", + decoded.Signature); + + return null; + } + + decoded.Format = DDSResponse[6]; + decoded.Reserved3 = DDSResponse[7]; + decoded.UpdateCount = BigEndianBitConverter.ToUInt32(DDSResponse, 8); + decoded.Reserved4 = BigEndianBitConverter.ToUInt64(DDSResponse, 12); + decoded.DriveAreaPSN = BigEndianBitConverter.ToUInt32(DDSResponse, 20); + decoded.Reserved5 = BigEndianBitConverter.ToUInt32(DDSResponse, 24); + decoded.DefectListPSN = BigEndianBitConverter.ToUInt32(DDSResponse, 28); + decoded.Reserved6 = BigEndianBitConverter.ToUInt32(DDSResponse, 32); + decoded.PSNofLSNZero = BigEndianBitConverter.ToUInt32(DDSResponse, 36); + decoded.LastUserAreaLSN = BigEndianBitConverter.ToUInt32(DDSResponse, 40); + decoded.ISA0 = BigEndianBitConverter.ToUInt32(DDSResponse, 44); + decoded.OSA = BigEndianBitConverter.ToUInt32(DDSResponse, 48); + decoded.ISA1 = BigEndianBitConverter.ToUInt32(DDSResponse, 52); + decoded.SpareAreaFullFlags = DDSResponse[56]; + decoded.Reserved7 = DDSResponse[57]; + decoded.DiscTypeSpecificField1 = DDSResponse[58]; + decoded.Reserved8 = DDSResponse[59]; + decoded.DiscTypeSpecificField2 = BigEndianBitConverter.ToUInt32(DDSResponse, 60); + decoded.Reserved9 = BigEndianBitConverter.ToUInt32(DDSResponse, 64); + decoded.StatusBits = new byte[32]; + Array.Copy(DDSResponse, 68, decoded.StatusBits, 0, 32); + decoded.DiscTypeSpecificData = new byte[DDSResponse.Length - 100]; + Array.Copy(DDSResponse, 100, decoded.DiscTypeSpecificData, 0, DDSResponse.Length - 100); + + return decoded; + } + + public static string Prettify(DiscDefinitionStructure? DDSResponse) + { + if(DDSResponse == null) + return null; + + DiscDefinitionStructure response = DDSResponse.Value; + + 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(); + sb.AppendFormat("First PSN of Drive Area: 0x{0:X8}", response.DriveAreaPSN).AppendLine(); + sb.AppendFormat("First PSN of Defect List: 0x{0:X8}", response.DefectListPSN).AppendLine(); + sb.AppendFormat("PSN of User Data Area's LSN 0: 0x{0:X8}", response.PSNofLSNZero).AppendLine(); + sb.AppendFormat("Last User Data Area's LSN 0: 0x{0:X8}", response.LastUserAreaLSN).AppendLine(); + sb.AppendFormat("ISA0 size: {0}", response.ISA0).AppendLine(); + sb.AppendFormat("OSA size: {0}", response.OSA).AppendLine(); + sb.AppendFormat("ISA1 size: {0}", response.ISA1).AppendLine(); + sb.AppendFormat("Spare Area Full Flags: 0x{0:X2}", response.SpareAreaFullFlags).AppendLine(); + sb.AppendFormat("Disc Type Specific Field 1: 0x{0:X2}", response.DiscTypeSpecificField1).AppendLine(); + sb.AppendFormat("Disc Type Specific Field 2: 0x{0:X8}", response.DiscTypeSpecificField2).AppendLine(); + sb.AppendFormat("Blu-ray DDS Status Bits in hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.StatusBits, 80)); + 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 + + return sb.ToString(); + } + + public static string Prettify(byte[] DDSResponse) => Prettify(Decode(DDSResponse)); + #endregion Public methods } \ No newline at end of file diff --git a/Bluray/DI.cs b/Bluray/DI.cs index dcfb593..7e7c909 100644 --- a/Bluray/DI.cs +++ b/Bluray/DI.cs @@ -37,544 +37,543 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.Bluray +namespace Aaru.Decoders.Bluray; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DI { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class DI + public enum BluSize : byte { - public enum BluSize : byte + /// 120mm + OneTwenty = 0, + /// 80mm + Eighty = 1 + } + + public enum ChannelLength : byte + { + /// 74.5nm channel or 25Gb/layer + Seventy = 1, + /// 69.0nm channel or 27Gb/layer + Sixty = 2 + } + + public enum HybridLayer : byte + { + /// No hybrid layer + None = 0, + /// -ROM layer + ReadOnly = 1, + /// -R layer + Recordable = 2, + /// -RW layer + Rewritable = 3 + } + + #region Private constants + const string DiscTypeBDROM = "BDO"; + const string DiscTypeBDRE = "BDW"; + const string DiscTypeBDR = "BDR"; + + /// Disc Information Unit Identifier "DI" + const ushort DIUIdentifier = 0x4449; + #endregion Private constants + + #region Public methods + public static DiscInformation? Decode(byte[] DIResponse) + { + if(DIResponse == null) + return null; + + if(DIResponse.Length != 4100) { - /// 120mm - OneTwenty = 0, - /// 80mm - Eighty = 1 + AaruConsole.DebugWriteLine("BD Disc Information decoder", + "Found incorrect Blu-ray Disc Information size ({0} bytes)", + DIResponse.Length); + + return null; } - public enum ChannelLength : byte + var decoded = new DiscInformation { - /// 74.5nm channel or 25Gb/layer - Seventy = 1, - /// 69.0nm channel or 27Gb/layer - Sixty = 2 - } + DataLength = BigEndianBitConverter.ToUInt16(DIResponse, 0), + Reserved1 = DIResponse[2], + Reserved2 = DIResponse[3] + }; - public enum HybridLayer : byte + int offset = 4; + List units = new List(); + + while(true) { - /// No hybrid layer - None = 0, - /// -ROM layer - ReadOnly = 1, - /// -R layer - Recordable = 2, - /// -RW layer - Rewritable = 3 - } + if(offset >= 4100) + break; - #region Private constants - const string DiscTypeBDROM = "BDO"; - const string DiscTypeBDRE = "BDW"; - const string DiscTypeBDR = "BDR"; - - /// Disc Information Unit Identifier "DI" - const ushort DIUIdentifier = 0x4449; - #endregion Private constants - - #region Public methods - public static DiscInformation? Decode(byte[] DIResponse) - { - if(DIResponse == null) - return null; - - if(DIResponse.Length != 4100) + var unit = new DiscInformationUnits { - AaruConsole.DebugWriteLine("BD Disc Information decoder", - "Found incorrect Blu-ray Disc Information size ({0} bytes)", - DIResponse.Length); - - return null; - } - - var decoded = new DiscInformation - { - DataLength = BigEndianBitConverter.ToUInt16(DIResponse, 0), - Reserved1 = DIResponse[2], - Reserved2 = DIResponse[3] + Signature = BigEndianBitConverter.ToUInt16(DIResponse, 0 + offset) }; - int offset = 4; - List units = new List(); + if(unit.Signature != DIUIdentifier) + break; - while(true) + unit.Format = DIResponse[2 + offset]; + unit.UnitsPerBlock = (byte)((DIResponse[3 + offset] & 0xF8) >> 3); + unit.Layer = (byte)(DIResponse[3 + offset] & 0x07); + unit.Legacy = DIResponse[4 + offset]; + unit.Sequence = DIResponse[5 + offset]; + unit.Continuation = (DIResponse[6 + offset] & 0x80) == 0x80; + unit.Length = (byte)(DIResponse[6 + offset] & 0x7F); + unit.Reserved = DIResponse[7 + offset]; + unit.DiscTypeIdentifier = new byte[3]; + Array.Copy(DIResponse, 8 + offset, unit.DiscTypeIdentifier, 0, 3); + unit.DiscSize = (BluSize)((DIResponse[11 + offset] & 0xC0) >> 6); + unit.DiscClass = (byte)((DIResponse[11 + offset] & 0x30) >> 4); + unit.DiscVersion = (byte)(DIResponse[11 + offset] & 0x0F); + unit.Layers = (byte)((DIResponse[12 + offset] & 0xF0) >> 4); + unit.DvdLayer = (HybridLayer)((DIResponse[13 + offset] & 0xC0) >> 6); + unit.CdLayer = (HybridLayer)((DIResponse[13 + offset] & 0x30) >> 4); + unit.ChannelLength = (ChannelLength)(DIResponse[13 + offset] & 0x0F); + unit.Polarity = DIResponse[14 + offset]; + 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)) { - if(offset >= 4100) - break; - - var unit = new DiscInformationUnits + case DiscTypeBDROM: { - Signature = BigEndianBitConverter.ToUInt16(DIResponse, 0 + offset) - }; + unit.FormatDependentContents = new byte[32]; + Array.Copy(DIResponse, 32 + offset, unit.FormatDependentContents, 0, 32); - if(unit.Signature != DIUIdentifier) break; - - unit.Format = DIResponse[2 + offset]; - unit.UnitsPerBlock = (byte)((DIResponse[3 + offset] & 0xF8) >> 3); - unit.Layer = (byte)(DIResponse[3 + offset] & 0x07); - unit.Legacy = DIResponse[4 + offset]; - unit.Sequence = DIResponse[5 + offset]; - unit.Continuation = (DIResponse[6 + offset] & 0x80) == 0x80; - unit.Length = (byte)(DIResponse[6 + offset] & 0x7F); - unit.Reserved = DIResponse[7 + offset]; - unit.DiscTypeIdentifier = new byte[3]; - Array.Copy(DIResponse, 8 + offset, unit.DiscTypeIdentifier, 0, 3); - unit.DiscSize = (BluSize)((DIResponse[11 + offset] & 0xC0) >> 6); - unit.DiscClass = (byte)((DIResponse[11 + offset] & 0x30) >> 4); - unit.DiscVersion = (byte)(DIResponse[11 + offset] & 0x0F); - unit.Layers = (byte)((DIResponse[12 + offset] & 0xF0) >> 4); - unit.DvdLayer = (HybridLayer)((DIResponse[13 + offset] & 0xC0) >> 6); - unit.CdLayer = (HybridLayer)((DIResponse[13 + offset] & 0x30) >> 4); - unit.ChannelLength = (ChannelLength)(DIResponse[13 + offset] & 0x0F); - unit.Polarity = DIResponse[14 + offset]; - 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; - } - - case DiscTypeBDRE: - case DiscTypeBDR: - { - unit.FormatDependentContents = new byte[66]; - Array.Copy(DIResponse, 32 + offset, unit.FormatDependentContents, 0, 66); - unit.ManufacturerID = new byte[6]; - Array.Copy(DIResponse, 100 + offset, unit.ManufacturerID, 0, 6); - unit.MediaTypeID = new byte[3]; - Array.Copy(DIResponse, 106 + offset, unit.MediaTypeID, 0, 3); - unit.TimeStamp = BigEndianBitConverter.ToUInt16(DIResponse, 109 + offset); - unit.ProductRevisionNumber = DIResponse[111 + offset]; - - offset += 14; - - break; - } - - default: - { - AaruConsole.DebugWriteLine("BD Disc Information decoder", - "Found unknown disc type identifier \"{0}\"", - Encoding.ASCII.GetString(unit.DiscTypeIdentifier)); - - break; - } } - units.Add(unit); + case DiscTypeBDRE: + case DiscTypeBDR: + { + unit.FormatDependentContents = new byte[66]; + Array.Copy(DIResponse, 32 + offset, unit.FormatDependentContents, 0, 66); + unit.ManufacturerID = new byte[6]; + Array.Copy(DIResponse, 100 + offset, unit.ManufacturerID, 0, 6); + unit.MediaTypeID = new byte[3]; + Array.Copy(DIResponse, 106 + offset, unit.MediaTypeID, 0, 3); + unit.TimeStamp = BigEndianBitConverter.ToUInt16(DIResponse, 109 + offset); + unit.ProductRevisionNumber = DIResponse[111 + offset]; - offset += unit.Length; + offset += 14; + + break; + } + + default: + { + AaruConsole.DebugWriteLine("BD Disc Information decoder", + "Found unknown disc type identifier \"{0}\"", + Encoding.ASCII.GetString(unit.DiscTypeIdentifier)); + + break; + } } - if(units.Count <= 0) - return decoded; + units.Add(unit); - decoded.Units = new DiscInformationUnits[units.Count]; - - for(int i = 0; i < units.Count; i++) - decoded.Units[i] = units[i]; + offset += unit.Length; + } + if(units.Count <= 0) return decoded; - } - public static string Prettify(DiscInformation? DIResponse) - { - if(DIResponse == null) - return null; + decoded.Units = new DiscInformationUnits[units.Count]; - DiscInformation response = DIResponse.Value; + for(int i = 0; i < units.Count; i++) + decoded.Units[i] = units[i]; - var sb = new StringBuilder(); - - foreach(DiscInformationUnits unit in response.Units) - { - sb.AppendFormat("DI Unit Sequence: {0}", unit.Sequence).AppendLine(); - 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(); - - 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; - } - - switch(unit.CdLayer) - { - 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; - } - - switch(unit.ChannelLength) - { - 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(); - - break; - } - - switch(unit.Polarity) - { - 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; - } - - if(Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDR) - switch(unit.RecordedPolarity) - { - 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; - } - - switch(unit.Bca) - { - 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."); - - 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("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 timestamp: 0x{0:X2}", unit.TimeStamp).AppendLine(); - sb.AppendFormat("Disc product revison number: {0}", unit.ProductRevisionNumber).AppendLine(); - } - - sb.AppendFormat("Blu-ray DI Unit format dependent contents as hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(unit.FormatDependentContents, 80)); - } - - return sb.ToString(); - } - - public static string Prettify(byte[] DIResponse) => Prettify(Decode(DIResponse)); - - public static string ManufacturerFromDI(string manufacturerId) - { - string manufacturer = ""; - - switch(manufacturerId) - { - case "AMESOB": - case "OTCBDR": - manufacturer = "Amethystum Storage Technology Co., Ltd."; - - break; - case "UMEBDR": - case "ANWELL": - manufacturer = "Avic Umedisc HK Ltd."; - - break; - case "MAXELL": - manufacturer = "Hitachi Maxell, Ltd."; - - break; - case "CMCMAG": - manufacturer = "CMC Magnetics Corporation"; - - break; - case "ISMMBD": - manufacturer = "Info Source Digital Media (Zhong Shan) Co., Ltd."; - - break; - case "LGEBRA": - manufacturer = "LG Electronics Inc."; - - break; - case "MILLEN": - manufacturer = "Millenniata, Inc."; - - break; - case "VERBAT": - case "VAMKM": - manufacturer = "Mitsubishi Chemical Media Co., Ltd."; - - break; - case "PHILIP": - case "MBI": - manufacturer = "Moser Baer India Ltd."; - - break; - case "MEI": - case "PAN": - manufacturer = "Matsushita Electric Industrial Co., Ltd."; - - break; - case "PRODIS": - manufacturer = "Prodisc Technology Inc."; - - break; - case "RITEK": - manufacturer = "Ritek Co."; - - break; - case "SONY": - manufacturer = "Sony Corporation"; - - break; - case "TYG-BD": - manufacturer = "Taiyo Yuden Company Ltd."; - - break; - case "TDKBLD": - manufacturer = "TDK Corporation"; - - break; - case "JVC-AM": - case "JVCVAM": - manufacturer = "Victor Advanced media Co., Ltd."; - - break; - case "JVCRE1": - manufacturer = "JVC KENWOOD Corporation"; - - break; - case "INFOME": - manufacturer = "InfoMedia Inc."; - - break; - } - - return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; - } - #endregion Public methods - - #region Public structures - public struct DiscInformation - { - /// Bytes 0 to 1 Always 4098 - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 to 4099 Disc information units - public DiscInformationUnits[] Units; - } - - public struct DiscInformationUnits - { - /// Byte 0 "DI" - public ushort Signature; - /// Byte 2 Disc information format - public byte Format; - /// Byte 3, bits 7 to 3 Number of DI units per block - public byte UnitsPerBlock; - /// Byte 3, bits 2 to 0 Layer this DI refers to - public byte Layer; - /// Byte 4 Reserved for BD-ROM, legacy information for BD-R/-RE - public byte Legacy; - /// Byte 5 Sequence number for this DI unit - public byte Sequence; - /// Byte 6, bit 7 If set this DI is a continuation of the previous one - public bool Continuation; - /// 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 - public byte Length; - /// Byte 7 Reserved - public byte Reserved; - /// Bytes 8 to 10 Disc type identifier - public byte[] DiscTypeIdentifier; - /// Byte 11, bits 7 to 6 Disc size - public BluSize DiscSize; - /// Byte 11, bits 5 to 4 Disc class - public byte DiscClass; - /// Byte 11, bits 3 to 0 Disc version - public byte DiscVersion; - /// Byte 12, bits 7 to 4 Layers in this disc - public byte Layers; - /// Byte 12, bits 3 to 0 Reserved - public byte Reserved2; - /// Byte 13, bits 7 to 6 DVD layer - public HybridLayer DvdLayer; - /// Byte 13, bits 5 to 4 CD layer - public HybridLayer CdLayer; - /// Byte 13, bits 3 to 0 Channel length - public ChannelLength ChannelLength; - /// Byte 14 Polarity - public byte Polarity; - /// Byte 15 Recorded polarity - public byte RecordedPolarity; - /// Byte 16, bits 7 to 4 Reserved - public byte Reserved3; - /// Byte 16, bits 3 to 0 If 0 no BCA, if 1 BCA, rest not defined - public byte Bca; - /// Byte 17 Maximum transfer speed in megabits/second, 0 if no maximum - public byte MaxTransfer; - /// Bytes 18 to 19 Reserved - public ushort Reserved4; - /// Bytes 20 to 23 Last user data PSN for disc - public uint LastPsn; - /// Bytes 24 to 27 First address unit number of data zone in this layer - public uint FirstAun; - /// Bytes 28 to 31 Last address unit number of data zone in this layer - public uint LastAun; - /// - /// Bytes 32 to 63 for BD-ROM, bytes 32 to 99 for BD-R/-RE Format dependent contents, disclosed in private blu-ray - /// specifications - /// - public byte[] FormatDependentContents; - /// Bytes 100 to 105, BD-R/-RE only Manufacturer ID - public byte[] ManufacturerID; - /// Bytes 106 to 108, BD-R/-RE only Media type ID - public byte[] MediaTypeID; - /// Bytes 109 to 110, BD-R/-RE only Timestamp - public ushort TimeStamp; - /// Byte 111 Product revision number - public byte ProductRevisionNumber; - } - #endregion Public structures + return decoded; } + + public static string Prettify(DiscInformation? DIResponse) + { + if(DIResponse == null) + return null; + + DiscInformation response = DIResponse.Value; + + var sb = new StringBuilder(); + + foreach(DiscInformationUnits unit in response.Units) + { + sb.AppendFormat("DI Unit Sequence: {0}", unit.Sequence).AppendLine(); + 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(); + + 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; + } + + switch(unit.CdLayer) + { + 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; + } + + switch(unit.ChannelLength) + { + 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(); + + break; + } + + switch(unit.Polarity) + { + 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; + } + + if(Encoding.ASCII.GetString(unit.DiscTypeIdentifier) == DiscTypeBDR) + switch(unit.RecordedPolarity) + { + 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; + } + + switch(unit.Bca) + { + 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."); + + 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("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 timestamp: 0x{0:X2}", unit.TimeStamp).AppendLine(); + sb.AppendFormat("Disc product revison number: {0}", unit.ProductRevisionNumber).AppendLine(); + } + + sb.AppendFormat("Blu-ray DI Unit format dependent contents as hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(unit.FormatDependentContents, 80)); + } + + return sb.ToString(); + } + + public static string Prettify(byte[] DIResponse) => Prettify(Decode(DIResponse)); + + public static string ManufacturerFromDI(string manufacturerId) + { + string manufacturer = ""; + + switch(manufacturerId) + { + case "AMESOB": + case "OTCBDR": + manufacturer = "Amethystum Storage Technology Co., Ltd."; + + break; + case "UMEBDR": + case "ANWELL": + manufacturer = "Avic Umedisc HK Ltd."; + + break; + case "MAXELL": + manufacturer = "Hitachi Maxell, Ltd."; + + break; + case "CMCMAG": + manufacturer = "CMC Magnetics Corporation"; + + break; + case "ISMMBD": + manufacturer = "Info Source Digital Media (Zhong Shan) Co., Ltd."; + + break; + case "LGEBRA": + manufacturer = "LG Electronics Inc."; + + break; + case "MILLEN": + manufacturer = "Millenniata, Inc."; + + break; + case "VERBAT": + case "VAMKM": + manufacturer = "Mitsubishi Chemical Media Co., Ltd."; + + break; + case "PHILIP": + case "MBI": + manufacturer = "Moser Baer India Ltd."; + + break; + case "MEI": + case "PAN": + manufacturer = "Matsushita Electric Industrial Co., Ltd."; + + break; + case "PRODIS": + manufacturer = "Prodisc Technology Inc."; + + break; + case "RITEK": + manufacturer = "Ritek Co."; + + break; + case "SONY": + manufacturer = "Sony Corporation"; + + break; + case "TYG-BD": + manufacturer = "Taiyo Yuden Company Ltd."; + + break; + case "TDKBLD": + manufacturer = "TDK Corporation"; + + break; + case "JVC-AM": + case "JVCVAM": + manufacturer = "Victor Advanced media Co., Ltd."; + + break; + case "JVCRE1": + manufacturer = "JVC KENWOOD Corporation"; + + break; + case "INFOME": + manufacturer = "InfoMedia Inc."; + + break; + } + + return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; + } + #endregion Public methods + + #region Public structures + public struct DiscInformation + { + /// Bytes 0 to 1 Always 4098 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 to 4099 Disc information units + public DiscInformationUnits[] Units; + } + + public struct DiscInformationUnits + { + /// Byte 0 "DI" + public ushort Signature; + /// Byte 2 Disc information format + public byte Format; + /// Byte 3, bits 7 to 3 Number of DI units per block + public byte UnitsPerBlock; + /// Byte 3, bits 2 to 0 Layer this DI refers to + public byte Layer; + /// Byte 4 Reserved for BD-ROM, legacy information for BD-R/-RE + public byte Legacy; + /// Byte 5 Sequence number for this DI unit + public byte Sequence; + /// Byte 6, bit 7 If set this DI is a continuation of the previous one + public bool Continuation; + /// 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 + public byte Length; + /// Byte 7 Reserved + public byte Reserved; + /// Bytes 8 to 10 Disc type identifier + public byte[] DiscTypeIdentifier; + /// Byte 11, bits 7 to 6 Disc size + public BluSize DiscSize; + /// Byte 11, bits 5 to 4 Disc class + public byte DiscClass; + /// Byte 11, bits 3 to 0 Disc version + public byte DiscVersion; + /// Byte 12, bits 7 to 4 Layers in this disc + public byte Layers; + /// Byte 12, bits 3 to 0 Reserved + public byte Reserved2; + /// Byte 13, bits 7 to 6 DVD layer + public HybridLayer DvdLayer; + /// Byte 13, bits 5 to 4 CD layer + public HybridLayer CdLayer; + /// Byte 13, bits 3 to 0 Channel length + public ChannelLength ChannelLength; + /// Byte 14 Polarity + public byte Polarity; + /// Byte 15 Recorded polarity + public byte RecordedPolarity; + /// Byte 16, bits 7 to 4 Reserved + public byte Reserved3; + /// Byte 16, bits 3 to 0 If 0 no BCA, if 1 BCA, rest not defined + public byte Bca; + /// Byte 17 Maximum transfer speed in megabits/second, 0 if no maximum + public byte MaxTransfer; + /// Bytes 18 to 19 Reserved + public ushort Reserved4; + /// Bytes 20 to 23 Last user data PSN for disc + public uint LastPsn; + /// Bytes 24 to 27 First address unit number of data zone in this layer + public uint FirstAun; + /// Bytes 28 to 31 Last address unit number of data zone in this layer + public uint LastAun; + /// + /// Bytes 32 to 63 for BD-ROM, bytes 32 to 99 for BD-R/-RE Format dependent contents, disclosed in private blu-ray + /// specifications + /// + public byte[] FormatDependentContents; + /// Bytes 100 to 105, BD-R/-RE only Manufacturer ID + public byte[] ManufacturerID; + /// Bytes 106 to 108, BD-R/-RE only Media type ID + public byte[] MediaTypeID; + /// Bytes 109 to 110, BD-R/-RE only Timestamp + public ushort TimeStamp; + /// Byte 111 Product revision number + public byte ProductRevisionNumber; + } + #endregion Public structures } \ No newline at end of file diff --git a/Bluray/Spare.cs b/Bluray/Spare.cs index 842e2ea..39cc685 100644 --- a/Bluray/Spare.cs +++ b/Bluray/Spare.cs @@ -35,96 +35,95 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.Bluray +namespace Aaru.Decoders.Bluray; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class Spare { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class Spare + #region Public structures + public struct SpareAreaInformation { - #region Public structures - public struct SpareAreaInformation - { - /// Bytes 0 to 1 Always 14 - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 7 Reserved - public uint Reserved3; - /// Bytes 8 to 11 Free spare blocks - public uint FreeSpareBlocks; - /// Bytes 12 to 15 Allocated spare blocks - public uint AllocatedSpareBlocks; - } - #endregion Public structures - #region Public methods - public static SpareAreaInformation? Decode(byte[] SAIResponse) - { - if(SAIResponse == null) - return null; - - if(SAIResponse.Length != 16) - { - AaruConsole.DebugWriteLine("BD Spare Area Information decoder", - "Found incorrect Blu-ray Spare Area Information size ({0} bytes)", - SAIResponse.Length); - - return null; - } - - var decoded = new SpareAreaInformation - { - DataLength = BigEndianBitConverter.ToUInt16(SAIResponse, 0), - Reserved1 = SAIResponse[2], - Reserved2 = SAIResponse[3], - Reserved3 = BigEndianBitConverter.ToUInt32(SAIResponse, 4), - FreeSpareBlocks = BigEndianBitConverter.ToUInt32(SAIResponse, 8), - AllocatedSpareBlocks = BigEndianBitConverter.ToUInt32(SAIResponse, 12) - }; - - return decoded; - } - - public static string Prettify(SpareAreaInformation? SAIResponse) - { - if(SAIResponse == null) - return null; - - SpareAreaInformation response = SAIResponse.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(); - - 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(); - - return sb.ToString(); - } - - public static string Prettify(byte[] SAIResponse) => Prettify(Decode(SAIResponse)); - #endregion Public methods + /// Bytes 0 to 1 Always 14 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 Reserved + public uint Reserved3; + /// Bytes 8 to 11 Free spare blocks + public uint FreeSpareBlocks; + /// Bytes 12 to 15 Allocated spare blocks + public uint AllocatedSpareBlocks; } + #endregion Public structures + #region Public methods + public static SpareAreaInformation? Decode(byte[] SAIResponse) + { + if(SAIResponse == null) + return null; + + if(SAIResponse.Length != 16) + { + AaruConsole.DebugWriteLine("BD Spare Area Information decoder", + "Found incorrect Blu-ray Spare Area Information size ({0} bytes)", + SAIResponse.Length); + + return null; + } + + var decoded = new SpareAreaInformation + { + DataLength = BigEndianBitConverter.ToUInt16(SAIResponse, 0), + Reserved1 = SAIResponse[2], + Reserved2 = SAIResponse[3], + Reserved3 = BigEndianBitConverter.ToUInt32(SAIResponse, 4), + FreeSpareBlocks = BigEndianBitConverter.ToUInt32(SAIResponse, 8), + AllocatedSpareBlocks = BigEndianBitConverter.ToUInt32(SAIResponse, 12) + }; + + return decoded; + } + + public static string Prettify(SpareAreaInformation? SAIResponse) + { + if(SAIResponse == null) + return null; + + SpareAreaInformation response = SAIResponse.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(); + + 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(); + + return sb.ToString(); + } + + public static string Prettify(byte[] SAIResponse) => Prettify(Decode(SAIResponse)); + #endregion Public methods } \ No newline at end of file diff --git a/CD/ATIP.cs b/CD/ATIP.cs index 816d7d5..23e65d8 100644 --- a/CD/ATIP.cs +++ b/CD/ATIP.cs @@ -36,644 +36,643 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class ATIP { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class ATIP + public static CDATIP Decode(byte[] CDATIPResponse) { - public static CDATIP Decode(byte[] CDATIPResponse) + if(CDATIPResponse == null || + CDATIPResponse.Length <= 4) + return null; + + var decoded = new CDATIP(); + + if(CDATIPResponse.Length != 32 && + CDATIPResponse.Length != 28) { - if(CDATIPResponse == null || - CDATIPResponse.Length <= 4) - return null; + AaruConsole.DebugWriteLine("CD ATIP decoder", + "Expected CD ATIP size (32 bytes) is not received size ({0} bytes), not decoding", + CDATIPResponse.Length); - var decoded = new CDATIP(); - - if(CDATIPResponse.Length != 32 && - CDATIPResponse.Length != 28) - { - AaruConsole.DebugWriteLine("CD ATIP decoder", - "Expected CD ATIP size (32 bytes) is not received size ({0} bytes), not decoding", - CDATIPResponse.Length); - - return null; - } - - decoded.DataLength = BigEndianBitConverter.ToUInt16(CDATIPResponse, 0); - decoded.Reserved1 = CDATIPResponse[2]; - decoded.Reserved2 = CDATIPResponse[3]; - decoded.ITWP = (byte)((CDATIPResponse[4] & 0xF0) >> 4); - decoded.DDCD = Convert.ToBoolean(CDATIPResponse[4] & 0x08); - decoded.ReferenceSpeed = (byte)(CDATIPResponse[4] & 0x07); - decoded.AlwaysZero = Convert.ToBoolean(CDATIPResponse[5] & 0x80); - decoded.URU = Convert.ToBoolean(CDATIPResponse[5] & 0x40); - decoded.Reserved3 = (byte)(CDATIPResponse[5] & 0x3F); - - decoded.AlwaysOne = Convert.ToBoolean(CDATIPResponse[6] & 0x80); - decoded.DiscType = Convert.ToBoolean(CDATIPResponse[6] & 0x40); - decoded.DiscSubType = (byte)((CDATIPResponse[6] & 0x38) >> 3); - decoded.A1Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x04); - decoded.A2Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x02); - decoded.A3Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x01); - - decoded.Reserved4 = CDATIPResponse[7]; - decoded.LeadInStartMin = CDATIPResponse[8]; - decoded.LeadInStartSec = CDATIPResponse[9]; - decoded.LeadInStartFrame = CDATIPResponse[10]; - decoded.Reserved5 = CDATIPResponse[11]; - decoded.LeadOutStartMin = CDATIPResponse[12]; - decoded.LeadOutStartSec = CDATIPResponse[13]; - decoded.LeadOutStartFrame = CDATIPResponse[14]; - decoded.Reserved6 = CDATIPResponse[15]; - - decoded.A1Values = new byte[3]; - decoded.A2Values = new byte[3]; - decoded.A3Values = new byte[3]; - - Array.Copy(CDATIPResponse, 16, decoded.A1Values, 0, 3); - Array.Copy(CDATIPResponse, 20, decoded.A2Values, 0, 3); - Array.Copy(CDATIPResponse, 24, decoded.A3Values, 0, 3); - - decoded.Reserved7 = CDATIPResponse[19]; - decoded.Reserved8 = CDATIPResponse[23]; - decoded.Reserved9 = CDATIPResponse[27]; - - if(CDATIPResponse.Length < 32) - return decoded.AlwaysOne ? decoded : null; - - decoded.S4Values = new byte[3]; - Array.Copy(CDATIPResponse, 28, decoded.S4Values, 0, 3); - decoded.Reserved10 = CDATIPResponse[31]; - - return decoded.AlwaysOne ? decoded : null; + return null; } - public static string Prettify(CDATIP response) + decoded.DataLength = BigEndianBitConverter.ToUInt16(CDATIPResponse, 0); + decoded.Reserved1 = CDATIPResponse[2]; + decoded.Reserved2 = CDATIPResponse[3]; + decoded.ITWP = (byte)((CDATIPResponse[4] & 0xF0) >> 4); + decoded.DDCD = Convert.ToBoolean(CDATIPResponse[4] & 0x08); + decoded.ReferenceSpeed = (byte)(CDATIPResponse[4] & 0x07); + decoded.AlwaysZero = Convert.ToBoolean(CDATIPResponse[5] & 0x80); + decoded.URU = Convert.ToBoolean(CDATIPResponse[5] & 0x40); + decoded.Reserved3 = (byte)(CDATIPResponse[5] & 0x3F); + + decoded.AlwaysOne = Convert.ToBoolean(CDATIPResponse[6] & 0x80); + decoded.DiscType = Convert.ToBoolean(CDATIPResponse[6] & 0x40); + decoded.DiscSubType = (byte)((CDATIPResponse[6] & 0x38) >> 3); + decoded.A1Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x04); + decoded.A2Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x02); + decoded.A3Valid = Convert.ToBoolean(CDATIPResponse[6] & 0x01); + + decoded.Reserved4 = CDATIPResponse[7]; + decoded.LeadInStartMin = CDATIPResponse[8]; + decoded.LeadInStartSec = CDATIPResponse[9]; + decoded.LeadInStartFrame = CDATIPResponse[10]; + decoded.Reserved5 = CDATIPResponse[11]; + decoded.LeadOutStartMin = CDATIPResponse[12]; + decoded.LeadOutStartSec = CDATIPResponse[13]; + decoded.LeadOutStartFrame = CDATIPResponse[14]; + decoded.Reserved6 = CDATIPResponse[15]; + + decoded.A1Values = new byte[3]; + decoded.A2Values = new byte[3]; + decoded.A3Values = new byte[3]; + + Array.Copy(CDATIPResponse, 16, decoded.A1Values, 0, 3); + Array.Copy(CDATIPResponse, 20, decoded.A2Values, 0, 3); + Array.Copy(CDATIPResponse, 24, decoded.A3Values, 0, 3); + + decoded.Reserved7 = CDATIPResponse[19]; + decoded.Reserved8 = CDATIPResponse[23]; + decoded.Reserved9 = CDATIPResponse[27]; + + if(CDATIPResponse.Length < 32) + return decoded.AlwaysOne ? decoded : null; + + decoded.S4Values = new byte[3]; + Array.Copy(CDATIPResponse, 28, decoded.S4Values, 0, 3); + decoded.Reserved10 = CDATIPResponse[31]; + + return decoded.AlwaysOne ? decoded : null; + } + + public static string Prettify(CDATIP response) + { + if(response == null) + return null; + + var sb = new StringBuilder(); + + if(response.DDCD) { - if(response == null) - return null; + sb.AppendFormat("Indicative Target Writing Power: 0x{0:X2}", response.ITWP).AppendLine(); + sb.AppendLine(response.DiscType ? "Disc is DDCD-RW" : "Disc is DDCD-R"); - var sb = new StringBuilder(); - - if(response.DDCD) + switch(response.ReferenceSpeed) { - sb.AppendFormat("Indicative Target Writing Power: 0x{0:X2}", response.ITWP).AppendLine(); - sb.AppendLine(response.DiscType ? "Disc is DDCD-RW" : "Disc is DDCD-R"); + case 2: + sb.AppendLine("Reference speed is 4x"); - switch(response.ReferenceSpeed) + 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(); + } + 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("Reference speed is 4x"); + sb.AppendLine("Disc is Ultra-Speed CD-RW"); break; case 3: - sb.AppendLine("Reference speed is 8x"); + 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("Reference speed set is unknown: {0}", response.ReferenceSpeed).AppendLine(); + sb.AppendFormat("Unknown CD-RW disc subtype: {0}", response.DiscSubType).AppendLine(); break; } - sb.AppendFormat("ATIP Start time of Lead-in: 0x{0:X6}", - (response.LeadInStartMin << 16) + (response.LeadInStartSec << 8) + - response.LeadInStartFrame).AppendLine(); + switch(response.ReferenceSpeed) + { + case 1: + sb.AppendLine("Reference speed is 2x"); - sb.AppendFormat("ATIP Last possible start time of Lead-out: 0x{0:X6}", - (response.LeadOutStartMin << 16) + (response.LeadOutStartSec << 8) + - response.LeadOutStartFrame).AppendLine(); + break; + default: + 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; + } + } + + sb.AppendLine(response.URU ? "Disc use is unrestricted" : "Disc use is restricted"); + + 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(); + + if(response.A1Valid) + sb.AppendFormat("A1 value: 0x{0:X6}", + (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(); + + if(response.A3Valid) + sb.AppendFormat("A3 value: 0x{0:X6}", + (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(); - } - 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; - } - - switch(response.ReferenceSpeed) - { - case 1: - sb.AppendLine("Reference speed is 2x"); - - break; - default: - 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; - } - } - - sb.AppendLine(response.URU ? "Disc use is unrestricted" : "Disc use is restricted"); - - 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(); - - if(response.A1Valid) - sb.AppendFormat("A1 value: 0x{0:X6}", - (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(); - - if(response.A3Valid) - sb.AppendFormat("A3 value: 0x{0:X6}", - (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(); - } - - 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"); - else - 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(response.LeadInStartMin != 97) return sb.ToString(); - } - public static string Prettify(byte[] CDATIPResponse) + int type = response.LeadInStartFrame % 10; + int frm = response.LeadInStartFrame - type; + + if(response.DiscType) + sb.AppendLine("Disc uses phase change"); + else + 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(); + + return sb.ToString(); + } + + public static string Prettify(byte[] CDATIPResponse) + { + CDATIP decoded = Decode(CDATIPResponse); + + return Prettify(decoded); + } + + public static string ManufacturerFromATIP(byte sec, int frm) + { + switch(sec) { - CDATIP decoded = Decode(CDATIPResponse); + case 10: + switch(frm) + { + case 00: return "Ritek Co."; + } - return Prettify(decoded); + break; + 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"; + } + + break; + case 16: + switch(frm) + { + 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 Ltd."; + + break; + case 18: + switch(frm) + { + 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"; + + break; + case 21: + switch(frm) + { + case 10: return "Grupo Condor S.L."; + case 20: return "E-TOP Mediatek Inc."; + 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."; + } + + 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"; + } + + 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."; + } + + 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."; + } + + 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"; + } + + 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."; + } + + 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."; + } + + 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."; + } + + break; + case 30: + 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."; + } + + break; + case 32: + switch(frm) + { + case 00: return "TDK Corporation"; + case 10: return "Prodisc Technology Inc."; + } + + break; + case 34: + switch(frm) + { + case 20: + case 22: return "Mitsubishi Chemical Corporation"; + } + + break; + case 36: + switch(frm) + { + case 00: return "Gish International Co., Ltd."; + } + + break; + case 42: + 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."; + } + + 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"; + } + + 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."; + } + + 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."; + } + + 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."; + } + + 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"; + } + + 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."; + } + + break; } - public static string ManufacturerFromATIP(byte sec, int frm) - { - switch(sec) - { - case 10: - switch(frm) - { - case 00: return "Ritek Co."; - } + return ""; + } - break; - 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"; - } - - break; - case 16: - switch(frm) - { - 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 Ltd."; - - break; - case 18: - switch(frm) - { - 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"; - - break; - case 21: - switch(frm) - { - case 10: return "Grupo Condor S.L."; - case 20: return "E-TOP Mediatek Inc."; - 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."; - } - - 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"; - } - - 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."; - } - - 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."; - } - - 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"; - } - - 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."; - } - - 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."; - } - - 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."; - } - - break; - case 30: - 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."; - } - - break; - case 32: - switch(frm) - { - case 00: return "TDK Corporation"; - case 10: return "Prodisc Technology Inc."; - } - - break; - case 34: - switch(frm) - { - case 20: - case 22: return "Mitsubishi Chemical Corporation"; - } - - break; - case 36: - switch(frm) - { - case 00: return "Gish International Co., Ltd."; - } - - break; - case 42: - 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."; - } - - 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"; - } - - 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."; - } - - 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."; - } - - 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."; - } - - 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"; - } - - 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."; - } - - break; - } - - return ""; - } - - public class CDATIP - { - /// Byte 6, bit 2 A1 values are valid - public bool A1Valid; - /// Bytes 16 to 18 A1 values - public byte[] A1Values; - /// Byte 6, bit 1 A2 values are valid - public bool A2Valid; - /// Bytes 20 to 22 A2 values - public byte[] A2Values; - /// Byte 6, bit 0 A3 values are valid - public bool A3Valid; - /// Bytes 24 to 26 A3 values - public byte[] A3Values; - /// Byte 6, bit 7 Always set - public bool AlwaysOne; - /// Byte 5, bit 7 Always unset - public bool AlwaysZero; - /// Bytes 1 to 0 Total size of returned session information minus this field - public ushort DataLength; - /// Byte 4, bit 3 Set if DDCD - public bool DDCD; - /// Byte 6, bits 5 to 3 Disc subtype - public byte DiscSubType; - /// Byte 6, bit 6 Set if rewritable (CD-RW or DDCD-RW) - public bool DiscType; - /// Byte 4, bits 7 to 4 Indicative target writing power - public byte ITWP; - /// Byte 10 ATIP Start time of Lead-In (Frame) - public byte LeadInStartFrame; - /// Byte 8 ATIP Start time of Lead-In (Minute) - public byte LeadInStartMin; - /// Byte 9 ATIP Start time of Lead-In (Second) - public byte LeadInStartSec; - /// Byte 14 ATIP Last possible start time of Lead-Out (Frame) - public byte LeadOutStartFrame; - /// Byte 12 ATIP Last possible start time of Lead-Out (Minute) - public byte LeadOutStartMin; - /// Byte 13 ATIP Last possible start time of Lead-Out (Second) - public byte LeadOutStartSec; - /// Byte 4, bits 2 to 0 Reference speed - public byte ReferenceSpeed; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 31 Reserved - public byte Reserved10; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 5, bits 5 to 0 Reserved - public byte Reserved3; - /// Byte 7 Reserved - public byte Reserved4; - /// Byte 11 Reserved - public byte Reserved5; - /// Byte 15 Reserved - public byte Reserved6; - /// Byte 19 Reserved - public byte Reserved7; - /// Byte 23 Reserved - public byte Reserved8; - /// Byte 27 Reserved - public byte Reserved9; - /// Bytes 28 to 30 S4 values - public byte[] S4Values; - /// Byte 5, bit 6 Unrestricted media - public bool URU; - } + public class CDATIP + { + /// Byte 6, bit 2 A1 values are valid + public bool A1Valid; + /// Bytes 16 to 18 A1 values + public byte[] A1Values; + /// Byte 6, bit 1 A2 values are valid + public bool A2Valid; + /// Bytes 20 to 22 A2 values + public byte[] A2Values; + /// Byte 6, bit 0 A3 values are valid + public bool A3Valid; + /// Bytes 24 to 26 A3 values + public byte[] A3Values; + /// Byte 6, bit 7 Always set + public bool AlwaysOne; + /// Byte 5, bit 7 Always unset + public bool AlwaysZero; + /// Bytes 1 to 0 Total size of returned session information minus this field + public ushort DataLength; + /// Byte 4, bit 3 Set if DDCD + public bool DDCD; + /// Byte 6, bits 5 to 3 Disc subtype + public byte DiscSubType; + /// Byte 6, bit 6 Set if rewritable (CD-RW or DDCD-RW) + public bool DiscType; + /// Byte 4, bits 7 to 4 Indicative target writing power + public byte ITWP; + /// Byte 10 ATIP Start time of Lead-In (Frame) + public byte LeadInStartFrame; + /// Byte 8 ATIP Start time of Lead-In (Minute) + public byte LeadInStartMin; + /// Byte 9 ATIP Start time of Lead-In (Second) + public byte LeadInStartSec; + /// Byte 14 ATIP Last possible start time of Lead-Out (Frame) + public byte LeadOutStartFrame; + /// Byte 12 ATIP Last possible start time of Lead-Out (Minute) + public byte LeadOutStartMin; + /// Byte 13 ATIP Last possible start time of Lead-Out (Second) + public byte LeadOutStartSec; + /// Byte 4, bits 2 to 0 Reference speed + public byte ReferenceSpeed; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 31 Reserved + public byte Reserved10; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 5, bits 5 to 0 Reserved + public byte Reserved3; + /// Byte 7 Reserved + public byte Reserved4; + /// Byte 11 Reserved + public byte Reserved5; + /// Byte 15 Reserved + public byte Reserved6; + /// Byte 19 Reserved + public byte Reserved7; + /// Byte 23 Reserved + public byte Reserved8; + /// Byte 27 Reserved + public byte Reserved9; + /// Bytes 28 to 30 S4 values + public byte[] S4Values; + /// Byte 5, bit 6 Unrestricted media + public bool URU; } } \ No newline at end of file diff --git a/CD/CDTextOnLeadIn.cs b/CD/CDTextOnLeadIn.cs index 1a808d5..1448d0e 100644 --- a/CD/CDTextOnLeadIn.cs +++ b/CD/CDTextOnLeadIn.cs @@ -36,342 +36,341 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class CDTextOnLeadIn { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class CDTextOnLeadIn + public enum PackTypeIndicator : byte { - public enum PackTypeIndicator : byte + /// Title of the track (or album if track == 0) + Title = 0x80, + /// Performer + Performer = 0x81, + /// Songwriter + Songwriter = 0x82, + /// Composer + Composer = 0x83, + /// Arranger + Arranger = 0x84, + /// Message from the content provider or artist + Message = 0x85, + /// Disc identification information + DiscIdentification = 0x86, + /// Genre identification + GenreIdentification = 0x87, + /// Table of content information + TOCInformation = 0x88, + /// Second table of content information + SecondTOCInformation = 0x89, + /// Reserved + Reserved1 = 0x8A, + /// Reserved + Reserved2 = 0x8B, + /// Reserved + Reserved3 = 0x8C, + /// Reserved for content provider only + ReservedForContentProvider = 0x8D, + /// UPC of album or ISRC of track + UPCorISRC = 0x8E, + /// Size information of the block + BlockSizeInformation = 0x8F + } + + public static CDText? Decode(byte[] CDTextResponse) + { + if(CDTextResponse == null || + CDTextResponse.Length <= 4) + return null; + + var decoded = new CDText { - /// Title of the track (or album if track == 0) - Title = 0x80, - /// Performer - Performer = 0x81, - /// Songwriter - Songwriter = 0x82, - /// Composer - Composer = 0x83, - /// Arranger - Arranger = 0x84, - /// Message from the content provider or artist - Message = 0x85, - /// Disc identification information - DiscIdentification = 0x86, - /// Genre identification - GenreIdentification = 0x87, - /// Table of content information - TOCInformation = 0x88, - /// Second table of content information - SecondTOCInformation = 0x89, - /// Reserved - Reserved1 = 0x8A, - /// Reserved - Reserved2 = 0x8B, - /// Reserved - Reserved3 = 0x8C, - /// Reserved for content provider only - ReservedForContentProvider = 0x8D, - /// UPC of album or ISRC of track - UPCorISRC = 0x8E, - /// Size information of the block - BlockSizeInformation = 0x8F + 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 != CDTextResponse.Length) + { + AaruConsole.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; } - public static CDText? Decode(byte[] CDTextResponse) + for(int i = 0; i < (decoded.DataLength - 2) / 18; i++) { - if(CDTextResponse == null || - CDTextResponse.Length <= 4) - return null; - - var decoded = new CDText - { - 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 != CDTextResponse.Length) - { - AaruConsole.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; - } - - for(int i = 0; i < (decoded.DataLength - 2) / 18; i++) - { - decoded.DataPacks[i].HeaderID1 = CDTextResponse[0 + (i * 18) + 4]; - decoded.DataPacks[i].HeaderID2 = CDTextResponse[1 + (i * 18) + 4]; - decoded.DataPacks[i].HeaderID3 = CDTextResponse[2 + (i * 18) + 4]; - decoded.DataPacks[i].DBCC = Convert.ToBoolean(CDTextResponse[3 + (i * 18) + 4] & 0x80); - decoded.DataPacks[i].BlockNumber = (byte)((CDTextResponse[3 + (i * 18) + 4] & 0x70) >> 4); - decoded.DataPacks[i].CharacterPosition = (byte)(CDTextResponse[3 + (i * 18) + 4] & 0x0F); - decoded.DataPacks[i].TextDataField = new byte[12]; - Array.Copy(CDTextResponse, 4 + (i * 18) + 4, decoded.DataPacks[i].TextDataField, 0, 12); - decoded.DataPacks[i].CRC = BigEndianBitConverter.ToUInt16(CDTextResponse, 16 + (i * 18) + 4); - } - - return decoded; + decoded.DataPacks[i].HeaderID1 = CDTextResponse[0 + (i * 18) + 4]; + decoded.DataPacks[i].HeaderID2 = CDTextResponse[1 + (i * 18) + 4]; + decoded.DataPacks[i].HeaderID3 = CDTextResponse[2 + (i * 18) + 4]; + decoded.DataPacks[i].DBCC = Convert.ToBoolean(CDTextResponse[3 + (i * 18) + 4] & 0x80); + decoded.DataPacks[i].BlockNumber = (byte)((CDTextResponse[3 + (i * 18) + 4] & 0x70) >> 4); + decoded.DataPacks[i].CharacterPosition = (byte)(CDTextResponse[3 + (i * 18) + 4] & 0x0F); + decoded.DataPacks[i].TextDataField = new byte[12]; + Array.Copy(CDTextResponse, 4 + (i * 18) + 4, decoded.DataPacks[i].TextDataField, 0, 12); + decoded.DataPacks[i].CRC = BigEndianBitConverter.ToUInt16(CDTextResponse, 16 + (i * 18) + 4); } - public static string Prettify(CDText? CDTextResponse) - { - if(CDTextResponse == null) - return null; + return decoded; + } - CDText response = CDTextResponse.Value; - var sb = new StringBuilder(); + public static string Prettify(CDText? CDTextResponse) + { + if(CDTextResponse == null) + return null; - #if DEBUG - if(response.Reserved1 != 0) - sb.AppendFormat("Reserved1 = 0x{0:X2}", response.Reserved1).AppendLine(); + CDText response = CDTextResponse.Value; + var sb = new StringBuilder(); - 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(); - foreach(CDTextPack descriptor in response.DataPacks) - if((descriptor.HeaderID1 & 0x80) != 0x80) + 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(); + } + else + { + switch(descriptor.HeaderID1) { - // Ignore NOPs - if((descriptor.HeaderID1 & 0x80) != 0) - sb.AppendFormat("Incorrect CD-Text pack type {0}, not decoding", descriptor.HeaderID1). + 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(); + + 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(); + + 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(); + + break; + } + + case 0x83: + { + 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(); + + 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(); + + 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; + } + + case 0x8A: + case 0x8B: + 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(); + + break; + } + + case 0x8F: + { + sb.AppendLine("CD-Text pack contains size block information"); + + break; + } + } + + switch(descriptor.HeaderID1) + { + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x8E: + { + 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(); - } - else - { - switch(descriptor.HeaderID1) - { - 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(); - - 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(); - - 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(); - - break; - } - - case 0x83: - { - 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(); - - 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(); - - 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; - } - - case 0x8A: - case 0x8B: - 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(); - - break; - } - - case 0x8F: - { - sb.AppendLine("CD-Text pack contains size block information"); - - break; - } + break; } - - switch(descriptor.HeaderID1) - { - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x8E: - { - 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(); - - break; - } - } - - sb.AppendFormat("CRC: 0x{0:X4}", descriptor.CRC).AppendLine(); } - return sb.ToString(); - } + sb.AppendFormat("CRC: 0x{0:X4}", descriptor.CRC).AppendLine(); + } - public static string Prettify(byte[] CDTextResponse) - { - CDText? decoded = Decode(CDTextResponse); + return sb.ToString(); + } - return Prettify(decoded); - } + public static string Prettify(byte[] CDTextResponse) + { + CDText? decoded = Decode(CDTextResponse); - public struct CDText - { - /// Total size of returned CD-Text information minus this field - public ushort DataLength; - /// Reserved - public byte Reserved1; - /// Reserved - public byte Reserved2; - /// CD-Text data packs - public CDTextPack[] DataPacks; - } + return Prettify(decoded); + } - public struct CDTextPack - { - /// Byte 0 Pack ID1 (Pack Type) - public byte HeaderID1; - /// Byte 1 Pack ID2 (Track number) - public byte HeaderID2; - /// Byte 2 Pack ID3 - public byte HeaderID3; - /// Byte 3, bit 7 Double Byte Character Code - public bool DBCC; - /// Byte 3, bits 6 to 4 Block number - public byte BlockNumber; - /// Byte 3, bits 3 to 0 Character position - public byte CharacterPosition; - /// Bytes 4 to 15 Text data - public byte[] TextDataField; - /// Bytes 16 to 17 CRC16 - public ushort CRC; - } + public struct CDText + { + /// Total size of returned CD-Text information minus this field + public ushort DataLength; + /// Reserved + public byte Reserved1; + /// Reserved + public byte Reserved2; + /// CD-Text data packs + public CDTextPack[] DataPacks; + } + + public struct CDTextPack + { + /// Byte 0 Pack ID1 (Pack Type) + public byte HeaderID1; + /// Byte 1 Pack ID2 (Track number) + public byte HeaderID2; + /// Byte 2 Pack ID3 + public byte HeaderID3; + /// Byte 3, bit 7 Double Byte Character Code + public bool DBCC; + /// Byte 3, bits 6 to 4 Block number + public byte BlockNumber; + /// Byte 3, bits 3 to 0 Character position + public byte CharacterPosition; + /// Bytes 4 to 15 Text data + public byte[] TextDataField; + /// Bytes 16 to 17 CRC16 + public ushort CRC; } } \ No newline at end of file diff --git a/CD/Enums.cs b/CD/Enums.cs index 63746ce..ea42e6c 100644 --- a/CD/Enums.cs +++ b/CD/Enums.cs @@ -32,42 +32,41 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.CD -{ - [SuppressMessage("ReSharper", "MemberCanBeInternal")] - public enum TocAdr : byte - { - /// Q Sub-channel mode information not supplied - NoInformation = 0x00, - /// Q Sub-channel encodes current position data - CurrentPosition = 0x01, - /// Q Sub-channel encodes the media catalog number - MediaCatalogNumber = 0x02, - /// Q Sub-channel encodes the ISRC - ISRC = 0x03, - /// Q Sub-channel encodes the start of an audio/data track (if found in TOC) - TrackPointer = 0x01, - /// Q Sub-channel encodes the start of a video track (if found in TOC) for CD-V - VideoTrackPointer = 0x04 - } +namespace Aaru.Decoders.CD; - public enum TocControl : byte - { - /// Stereo audio, no pre-emphasis - TwoChanNoPreEmph = 0x00, - /// Stereo audio with pre-emphasis - TwoChanPreEmph = 0x01, - /// If mask applied, track can be copied - CopyPermissionMask = 0x02, - /// Data track, recorded uninterrumpted - DataTrack = 0x04, - /// Data track, recorded incrementally - DataTrackIncremental = 0x05, - /// Quadraphonic audio, no pre-emphasis - FourChanNoPreEmph = 0x08, - /// Quadraphonic audio with pre-emphasis - FourChanPreEmph = 0x09, - /// Reserved mask - ReservedMask = 0x0C - } +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +public enum TocAdr : byte +{ + /// Q Sub-channel mode information not supplied + NoInformation = 0x00, + /// Q Sub-channel encodes current position data + CurrentPosition = 0x01, + /// Q Sub-channel encodes the media catalog number + MediaCatalogNumber = 0x02, + /// Q Sub-channel encodes the ISRC + ISRC = 0x03, + /// Q Sub-channel encodes the start of an audio/data track (if found in TOC) + TrackPointer = 0x01, + /// Q Sub-channel encodes the start of a video track (if found in TOC) for CD-V + VideoTrackPointer = 0x04 +} + +public enum TocControl : byte +{ + /// Stereo audio, no pre-emphasis + TwoChanNoPreEmph = 0x00, + /// Stereo audio with pre-emphasis + TwoChanPreEmph = 0x01, + /// If mask applied, track can be copied + CopyPermissionMask = 0x02, + /// Data track, recorded uninterrumpted + DataTrack = 0x04, + /// Data track, recorded incrementally + DataTrackIncremental = 0x05, + /// Quadraphonic audio, no pre-emphasis + FourChanNoPreEmph = 0x08, + /// Quadraphonic audio with pre-emphasis + FourChanPreEmph = 0x09, + /// Reserved mask + ReservedMask = 0x0C } \ No newline at end of file diff --git a/CD/FullTOC.cs b/CD/FullTOC.cs index 5d1471a..6a6ba63 100644 --- a/CD/FullTOC.cs +++ b/CD/FullTOC.cs @@ -39,748 +39,747 @@ using Aaru.CommonTypes.Structs; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class FullTOC { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class FullTOC + const string StereoNoPre = "Stereo audio track with no pre-emphasis"; + const string StereoPreEm = "Stereo audio track with 50/15 μs pre-emphasis"; + const string QuadNoPreEm = "Quadraphonic audio track with no pre-emphasis"; + const string QuadPreEmph = "Quadraphonic audio track with 50/15 μs pre-emphasis"; + const string DataUnintrp = "Data track, recorded uninterrupted"; + const string DataIncrtly = "Data track, recorded incrementally"; + + public static CDFullTOC? Decode(byte[] CDFullTOCResponse) { - const string StereoNoPre = "Stereo audio track with no pre-emphasis"; - const string StereoPreEm = "Stereo audio track with 50/15 μs pre-emphasis"; - const string QuadNoPreEm = "Quadraphonic audio track with no pre-emphasis"; - const string QuadPreEmph = "Quadraphonic audio track with 50/15 μs pre-emphasis"; - const string DataUnintrp = "Data track, recorded uninterrupted"; - const string DataIncrtly = "Data track, recorded incrementally"; + if(CDFullTOCResponse == null || + CDFullTOCResponse.Length <= 4) + return null; - public static CDFullTOC? Decode(byte[] CDFullTOCResponse) + var decoded = new CDFullTOC { - if(CDFullTOCResponse == null || - CDFullTOCResponse.Length <= 4) - return null; + DataLength = BigEndianBitConverter.ToUInt16(CDFullTOCResponse, 0), + FirstCompleteSession = CDFullTOCResponse[2], + LastCompleteSession = CDFullTOCResponse[3] + }; - var decoded = new CDFullTOC - { - DataLength = BigEndianBitConverter.ToUInt16(CDFullTOCResponse, 0), - FirstCompleteSession = CDFullTOCResponse[2], - LastCompleteSession = CDFullTOCResponse[3] - }; + decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 11]; - decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 11]; + if(decoded.DataLength + 2 != CDFullTOCResponse.Length) + { + AaruConsole.DebugWriteLine("CD full TOC decoder", + "Expected CDFullTOC size ({0} bytes) is not received size ({1} bytes), not decoding", + decoded.DataLength + 2, CDFullTOCResponse.Length); - if(decoded.DataLength + 2 != CDFullTOCResponse.Length) - { - AaruConsole.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; - } - - for(int i = 0; i < (decoded.DataLength - 2) / 11; i++) - { - decoded.TrackDescriptors[i].SessionNumber = CDFullTOCResponse[0 + (i * 11) + 4]; - decoded.TrackDescriptors[i].ADR = (byte)((CDFullTOCResponse[1 + (i * 11) + 4] & 0xF0) >> 4); - decoded.TrackDescriptors[i].CONTROL = (byte)(CDFullTOCResponse[1 + (i * 11) + 4] & 0x0F); - decoded.TrackDescriptors[i].TNO = CDFullTOCResponse[2 + (i * 11) + 4]; - decoded.TrackDescriptors[i].POINT = CDFullTOCResponse[3 + (i * 11) + 4]; - decoded.TrackDescriptors[i].Min = CDFullTOCResponse[4 + (i * 11) + 4]; - decoded.TrackDescriptors[i].Sec = CDFullTOCResponse[5 + (i * 11) + 4]; - decoded.TrackDescriptors[i].Frame = CDFullTOCResponse[6 + (i * 11) + 4]; - decoded.TrackDescriptors[i].Zero = CDFullTOCResponse[7 + (i * 11) + 4]; - decoded.TrackDescriptors[i].HOUR = (byte)((CDFullTOCResponse[7 + (i * 11) + 4] & 0xF0) >> 4); - decoded.TrackDescriptors[i].PHOUR = (byte)(CDFullTOCResponse[7 + (i * 11) + 4] & 0x0F); - decoded.TrackDescriptors[i].PMIN = CDFullTOCResponse[8 + (i * 11) + 4]; - decoded.TrackDescriptors[i].PSEC = CDFullTOCResponse[9 + (i * 11) + 4]; - decoded.TrackDescriptors[i].PFRAME = CDFullTOCResponse[10 + (i * 11) + 4]; - } - - return decoded; + return null; } - public static string Prettify(CDFullTOC? CDFullTOCResponse) + for(int i = 0; i < (decoded.DataLength - 2) / 11; i++) { - if(CDFullTOCResponse == null) - return null; + decoded.TrackDescriptors[i].SessionNumber = CDFullTOCResponse[0 + (i * 11) + 4]; + decoded.TrackDescriptors[i].ADR = (byte)((CDFullTOCResponse[1 + (i * 11) + 4] & 0xF0) >> 4); + decoded.TrackDescriptors[i].CONTROL = (byte)(CDFullTOCResponse[1 + (i * 11) + 4] & 0x0F); + decoded.TrackDescriptors[i].TNO = CDFullTOCResponse[2 + (i * 11) + 4]; + decoded.TrackDescriptors[i].POINT = CDFullTOCResponse[3 + (i * 11) + 4]; + decoded.TrackDescriptors[i].Min = CDFullTOCResponse[4 + (i * 11) + 4]; + decoded.TrackDescriptors[i].Sec = CDFullTOCResponse[5 + (i * 11) + 4]; + decoded.TrackDescriptors[i].Frame = CDFullTOCResponse[6 + (i * 11) + 4]; + decoded.TrackDescriptors[i].Zero = CDFullTOCResponse[7 + (i * 11) + 4]; + decoded.TrackDescriptors[i].HOUR = (byte)((CDFullTOCResponse[7 + (i * 11) + 4] & 0xF0) >> 4); + decoded.TrackDescriptors[i].PHOUR = (byte)(CDFullTOCResponse[7 + (i * 11) + 4] & 0x0F); + decoded.TrackDescriptors[i].PMIN = CDFullTOCResponse[8 + (i * 11) + 4]; + decoded.TrackDescriptors[i].PSEC = CDFullTOCResponse[9 + (i * 11) + 4]; + decoded.TrackDescriptors[i].PFRAME = CDFullTOCResponse[10 + (i * 11) + 4]; + } - CDFullTOC response = CDFullTOCResponse.Value; + return decoded; + } - var sb = new StringBuilder(); + public static string Prettify(CDFullTOC? CDFullTOCResponse) + { + if(CDFullTOCResponse == null) + return null; - int lastSession = 0; + CDFullTOC response = CDFullTOCResponse.Value; - sb.AppendFormat("First complete session number: {0}", response.FirstCompleteSession).AppendLine(); - sb.AppendFormat("Last complete session number: {0}", response.LastCompleteSession).AppendLine(); + var sb = new StringBuilder(); - foreach(TrackDataDescriptor descriptor in response.TrackDescriptors) - if((descriptor.CONTROL & 0x08) == 0x08 || - (descriptor.ADR != 1 && descriptor.ADR != 5 && descriptor.ADR != 4 && descriptor.ADR != 6) || - descriptor.TNO != 0) + 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) || + descriptor.TNO != 0) + { + sb.AppendLine("Unknown TOC entry format, printing values as-is"); + sb.AppendFormat("SessionNumber = {0}", descriptor.SessionNumber).AppendLine(); + sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); + sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); + sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); + sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); + sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); + sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); + sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); + sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); + sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); + sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); + sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); + sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); + } + else + { + if(descriptor.SessionNumber > lastSession) { - sb.AppendLine("Unknown TOC entry format, printing values as-is"); - sb.AppendFormat("SessionNumber = {0}", descriptor.SessionNumber).AppendLine(); - sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); - sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); - sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); - sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); - sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); - sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); - sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); - sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); - sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); - sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); - sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); - sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); + sb.AppendFormat("Session {0}", descriptor.SessionNumber).AppendLine(); + lastSession = descriptor.SessionNumber; } - else + + switch(descriptor.ADR) { - if(descriptor.SessionNumber > lastSession) + case 1: + case 4: { - sb.AppendFormat("Session {0}", descriptor.SessionNumber).AppendLine(); - lastSession = descriptor.SessionNumber; - } - - switch(descriptor.ADR) - { - case 1: - case 4: + switch(descriptor.POINT) { - switch(descriptor.POINT) + case 0xA0 when descriptor.ADR == 4: { - case 0xA0 when descriptor.ADR == 4: + sb.AppendFormat("First video track number: {0}", descriptor.PMIN).AppendLine(); + + switch(descriptor.PSEC) { - sb.AppendFormat("First video track number: {0}", descriptor.PMIN).AppendLine(); + case 0x10: + sb.AppendLine("CD-V single in NTSC format with digital stereo sound"); - 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 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 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 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 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 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 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; - case 0x23: - sb.AppendLine("CD-V disc in PAL format with digital bilingual sound"); - - break; - } - - break; + break; } - 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; - } - - case 0xA2: - { - if(descriptor.PHOUR > 0) - sb.AppendFormat("Lead-out start position: {3:D2}:{0:D2}:{1:D2}:{2:D2}", - descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, - descriptor.PHOUR).AppendLine(); - else - sb.AppendFormat("Lead-out start position: {0:D2}:{1:D2}:{2:D2}", - 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)) - { - case TocControl.TwoChanNoPreEmph: - case TocControl.TwoChanPreEmph: - 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; - } - - break; - } - - case 0xF0: - { - 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.ADR == 4) - sb.AppendFormat("Video track {3} starts at: {0:D2}:{1:D2}:{2:D2}", - descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, - descriptor.POINT).AppendLine(); - else - { - string type = "Audio"; - - if((TocControl)(descriptor.CONTROL & 0x0D) == TocControl.DataTrack || - (TocControl)(descriptor.CONTROL & 0x0D) == - TocControl.DataTrackIncremental) - type = "Data"; - - if(descriptor.PHOUR > 0) - sb.AppendFormat("{5} track {3} starts at: {4:D2}:{0:D2}:{1:D2}:{2:D2} (", - descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, - descriptor.POINT, descriptor.PHOUR, type); - else - sb.AppendFormat("{4} track {3} starts at: {0:D2}:{1:D2}:{2:D2} (", - descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, - descriptor.POINT, type); - - 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(")"); - } - else - { - sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); - sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); - sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); - sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); - sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); - sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); - sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); - sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); - sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); - sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); - sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); - sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); - } - - break; - } + break; } - break; - } - - case 5: - { - switch(descriptor.POINT) + case 0xA0 when descriptor.ADR == 1: { - case 0xB0: + sb.AppendFormat("First track number: {0} (", descriptor.PMIN); + + switch((TocControl)(descriptor.CONTROL & 0x0D)) { - 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}", - descriptor.Min, descriptor.Sec, descriptor.Frame, - descriptor.HOUR).AppendLine(); + case TocControl.TwoChanNoPreEmph: + sb.Append(StereoNoPre); - 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}", - descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine(); + break; + case TocControl.TwoChanPreEmph: + sb.Append(StereoPreEm); - 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; + case TocControl.FourChanNoPreEmph: + sb.Append(QuadNoPreEm); - break; + break; + case TocControl.FourChanPreEmph: + sb.Append(QuadPreEmph); + + break; + case TocControl.DataTrack: + sb.Append(DataUnintrp); + + break; + case TocControl.DataTrackIncremental: + sb.Append(DataIncrtly); + + break; } - case 0xB1: + 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)) { - sb.AppendFormat("Number of skip interval pointers: {0}", descriptor.PMIN). + 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; + } + + case 0xA2: + { + if(descriptor.PHOUR > 0) + sb.AppendFormat("Lead-out start position: {3:D2}:{0:D2}:{1:D2}:{2:D2}", + descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, + descriptor.PHOUR).AppendLine(); + else + sb.AppendFormat("Lead-out start position: {0:D2}:{1:D2}:{2:D2}", + descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME). AppendLine(); - sb.AppendFormat("Number of skip track pointers: {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; + switch((TocControl)(descriptor.CONTROL & 0x0D)) + { + case TocControl.TwoChanNoPreEmph: + case TocControl.TwoChanPreEmph: + 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; } - case 0xB2: - case 0xB3: - case 0xB4: - { - sb.AppendFormat("Skip track {0}", descriptor.Min).AppendLine(); - sb.AppendFormat("Skip track {0}", descriptor.Sec).AppendLine(); - sb.AppendFormat("Skip track {0}", descriptor.Frame).AppendLine(); - sb.AppendFormat("Skip track {0}", descriptor.Zero).AppendLine(); - 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; + } - break; - } + case 0xF0: + { + 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); - case 0xC0: - { - sb.AppendFormat("Optimum recording power: 0x{0:X2}", descriptor.Min).AppendLine(); + 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(); - 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}", - descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, - descriptor.PHOUR).AppendLine(); + break; + } + + default: + { + 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, + descriptor.POINT).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(); + { + string type = "Audio"; - break; - } + if((TocControl)(descriptor.CONTROL & 0x0D) == TocControl.DataTrack || + (TocControl)(descriptor.CONTROL & 0x0D) == + TocControl.DataTrackIncremental) + type = "Data"; - case 0xC1: + if(descriptor.PHOUR > 0) + sb.AppendFormat("{5} track {3} starts at: {4:D2}:{0:D2}:{1:D2}:{2:D2} (", + descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, + descriptor.POINT, descriptor.PHOUR, type); + else + sb.AppendFormat("{4} track {3} starts at: {0:D2}:{1:D2}:{2:D2} (", + descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, + descriptor.POINT, type); + + 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(")"); + } + else { - sb.AppendFormat("Copy of information of A1 from ATIP found"); + sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); + sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); + sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); + sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); - sb.AppendFormat("Zero = {0}", descriptor.Zero).AppendLine(); + sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); + sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); - - break; } - case 0xCF: + break; + } + } + + break; + } + + case 5: + { + switch(descriptor.POINT) + { + case 0xB0: + { + if(descriptor.PHOUR > 0) { - if(descriptor.PHOUR > 0) - { - 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("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("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}", - descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine(); - } - - break; + 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(); } - - default: + else { - 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("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("Ending time for interval that should be skipped: {0:D2}:{1:D2}:{2:D2}", - descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine(); - } - else - { - sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); - sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); - sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); - sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); - sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); - sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); - sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); - sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); - sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); - sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); - sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); - sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); - } - - break; + 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; } - break; + case 0xB1: + { + sb.AppendFormat("Number of skip interval pointers: {0}", descriptor.PMIN). + AppendLine(); + + sb.AppendFormat("Number of skip track pointers: {0}", descriptor.PSEC).AppendLine(); + + break; + } + + case 0xB2: + case 0xB3: + case 0xB4: + { + sb.AppendFormat("Skip track {0}", descriptor.Min).AppendLine(); + sb.AppendFormat("Skip track {0}", descriptor.Sec).AppendLine(); + sb.AppendFormat("Skip track {0}", descriptor.Frame).AppendLine(); + sb.AppendFormat("Skip track {0}", descriptor.Zero).AppendLine(); + 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}", + 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(); + + break; + } + + case 0xC1: + { + sb.AppendFormat("Copy of information of A1 from ATIP found"); + sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); + sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); + sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); + sb.AppendFormat("Zero = {0}", descriptor.Zero).AppendLine(); + sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); + sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); + sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); + + break; + } + + case 0xCF: + { + if(descriptor.PHOUR > 0) + { + 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}", + 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}", + descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine(); + } + + break; + } + + default: + { + 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}", + descriptor.Min, descriptor.Sec, descriptor.Frame).AppendLine(); + } + else + { + sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); + sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); + sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); + sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); + sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); + sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); + sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); + sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); + sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); + sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); + sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); + sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); + } + + break; + } } - case 6: - { - uint id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame); - sb.AppendFormat("Disc ID: {0:X6}", id & 0x00FFFFFF).AppendLine(); + break; + } - break; - } + case 6: + { + uint id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame); + sb.AppendFormat("Disc ID: {0:X6}", id & 0x00FFFFFF).AppendLine(); + + break; } } - - return sb.ToString(); - } - - public static string Prettify(byte[] CDFullTOCResponse) - { - CDFullTOC? decoded = Decode(CDFullTOCResponse); - - return Prettify(decoded); - } - - public struct CDFullTOC - { - /// Total size of returned session information minus this field - public ushort DataLength; - /// First complete session number in hex - public byte FirstCompleteSession; - /// Last complete session number in hex - public byte LastCompleteSession; - /// Track descriptors - public TrackDataDescriptor[] TrackDescriptors; - } - - public struct TrackDataDescriptor - { - /// Byte 0 Session number in hex - public byte SessionNumber; - /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found - public byte ADR; - /// Byte 1, bits 3 to 0 Track attributes - public byte CONTROL; - /// Byte 2 - public byte TNO; - /// Byte 3 - public byte POINT; - /// Byte 4 - public byte Min; - /// Byte 5 - public byte Sec; - /// Byte 6 - public byte Frame; - /// Byte 7, CD only - public byte Zero; - /// Byte 7, bits 7 to 4, DDCD only - public byte HOUR; - /// Byte 7, bits 3 to 0, DDCD only - public byte PHOUR; - /// Byte 8 - public byte PMIN; - /// Byte 9 - public byte PSEC; - /// Byte 10 - public byte PFRAME; - } - - public static CDFullTOC Create(List tracks, Dictionary trackFlags, - bool createC0Entry = false) - { - var toc = new CDFullTOC(); - Dictionary sessionEndingTrack = new(); - toc.FirstCompleteSession = byte.MaxValue; - toc.LastCompleteSession = byte.MinValue; - List trackDescriptors = new(); - byte currentTrack = 0; - - foreach(Track track in tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence)) - { - if(track.Session < toc.FirstCompleteSession) - toc.FirstCompleteSession = (byte)track.Session; - - if(track.Session <= toc.LastCompleteSession) - { - currentTrack = (byte)track.Sequence; - - continue; - } - - if(toc.LastCompleteSession > 0) - sessionEndingTrack.Add(toc.LastCompleteSession, currentTrack); - - toc.LastCompleteSession = (byte)track.Session; } - if(!sessionEndingTrack.ContainsKey(toc.LastCompleteSession)) - sessionEndingTrack[toc.LastCompleteSession] = (byte)tracks. - Where(t => t.Session == toc.LastCompleteSession). - Max(t => t.Sequence); + return sb.ToString(); + } - byte currentSession = 0; + public static string Prettify(byte[] CDFullTOCResponse) + { + CDFullTOC? decoded = Decode(CDFullTOCResponse); - foreach(Track track in tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence)) + return Prettify(decoded); + } + + public struct CDFullTOC + { + /// Total size of returned session information minus this field + public ushort DataLength; + /// First complete session number in hex + public byte FirstCompleteSession; + /// Last complete session number in hex + public byte LastCompleteSession; + /// Track descriptors + public TrackDataDescriptor[] TrackDescriptors; + } + + public struct TrackDataDescriptor + { + /// Byte 0 Session number in hex + public byte SessionNumber; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 + public byte TNO; + /// Byte 3 + public byte POINT; + /// Byte 4 + public byte Min; + /// Byte 5 + public byte Sec; + /// Byte 6 + public byte Frame; + /// Byte 7, CD only + public byte Zero; + /// Byte 7, bits 7 to 4, DDCD only + public byte HOUR; + /// Byte 7, bits 3 to 0, DDCD only + public byte PHOUR; + /// Byte 8 + public byte PMIN; + /// Byte 9 + public byte PSEC; + /// Byte 10 + public byte PFRAME; + } + + public static CDFullTOC Create(List tracks, Dictionary trackFlags, + bool createC0Entry = false) + { + var toc = new CDFullTOC(); + Dictionary sessionEndingTrack = new(); + toc.FirstCompleteSession = byte.MaxValue; + toc.LastCompleteSession = byte.MinValue; + List trackDescriptors = new(); + byte currentTrack = 0; + + foreach(Track track in tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence)) + { + if(track.Session < toc.FirstCompleteSession) + toc.FirstCompleteSession = (byte)track.Session; + + if(track.Session <= toc.LastCompleteSession) { - trackFlags.TryGetValue((byte)track.Sequence, out byte trackControl); + currentTrack = (byte)track.Sequence; - if(trackControl == 0 && - track.Type != TrackType.Audio) - trackControl = (byte)CdFlags.DataTrack; + continue; + } - // Lead-Out - if(track.Session > currentSession && - currentSession != 0) - { - (byte minute, byte second, byte frame) leadoutAmsf = LbaToMsf(track.StartSector - 150); + if(toc.LastCompleteSession > 0) + sessionEndingTrack.Add(toc.LastCompleteSession, currentTrack); - (byte minute, byte second, byte frame) leadoutPmsf = - LbaToMsf(tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence).Last().StartSector); + toc.LastCompleteSession = (byte)track.Session; + } - // Lead-out - trackDescriptors.Add(new TrackDataDescriptor - { - SessionNumber = currentSession, - POINT = 0xB0, - ADR = 5, - CONTROL = 0, - HOUR = 0, - Min = leadoutAmsf.minute, - Sec = leadoutAmsf.second, - Frame = leadoutAmsf.frame, - PHOUR = 2, - PMIN = leadoutPmsf.minute, - PSEC = leadoutPmsf.second, - PFRAME = leadoutPmsf.frame - }); + if(!sessionEndingTrack.ContainsKey(toc.LastCompleteSession)) + sessionEndingTrack[toc.LastCompleteSession] = (byte)tracks. + Where(t => t.Session == toc.LastCompleteSession). + Max(t => t.Sequence); - // This seems to be constant? It should not exist on CD-ROM but CloneCD creates them anyway - // Format seems like ATIP, but ATIP should not be as 0xC0 in TOC... - if(createC0Entry) - trackDescriptors.Add(new TrackDataDescriptor - { - SessionNumber = currentSession, - POINT = 0xC0, - ADR = 5, - CONTROL = 0, - Min = 128, - PMIN = 97, - PSEC = 25 - }); - } + byte currentSession = 0; - // Lead-in - if(track.Session > currentSession) - { - currentSession = (byte)track.Session; - sessionEndingTrack.TryGetValue(currentSession, out byte endingTrackNumber); + foreach(Track track in tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence)) + { + trackFlags.TryGetValue((byte)track.Sequence, out byte trackControl); - (byte minute, byte second, byte frame) leadinPmsf = - LbaToMsf((tracks.FirstOrDefault(t => t.Sequence == endingTrackNumber)?.EndSector ?? 0) + 1); + if(trackControl == 0 && + track.Type != TrackType.Audio) + trackControl = (byte)CdFlags.DataTrack; - // Starting track - trackDescriptors.Add(new TrackDataDescriptor - { - SessionNumber = currentSession, - POINT = 0xA0, - ADR = 1, - CONTROL = trackControl, - PMIN = (byte)track.Sequence - }); + // Lead-Out + if(track.Session > currentSession && + currentSession != 0) + { + (byte minute, byte second, byte frame) leadoutAmsf = LbaToMsf(track.StartSector - 150); - // Ending track - trackDescriptors.Add(new TrackDataDescriptor - { - SessionNumber = currentSession, - POINT = 0xA1, - ADR = 1, - CONTROL = trackControl, - PMIN = endingTrackNumber - }); + (byte minute, byte second, byte frame) leadoutPmsf = + LbaToMsf(tracks.OrderBy(t => t.Session).ThenBy(t => t.Sequence).Last().StartSector); - // Lead-out start - trackDescriptors.Add(new TrackDataDescriptor - { - SessionNumber = currentSession, - POINT = 0xA2, - ADR = 1, - CONTROL = trackControl, - PHOUR = 0, - PMIN = leadinPmsf.minute, - PSEC = leadinPmsf.second, - PFRAME = leadinPmsf.frame - }); - } - - (byte minute, byte second, byte frame) pmsf = LbaToMsf((ulong)track.Indexes[1]); - - // Track + // Lead-out trackDescriptors.Add(new TrackDataDescriptor { - SessionNumber = (byte)track.Session, - POINT = (byte)track.Sequence, + SessionNumber = currentSession, + POINT = 0xB0, + ADR = 5, + CONTROL = 0, + HOUR = 0, + Min = leadoutAmsf.minute, + Sec = leadoutAmsf.second, + Frame = leadoutAmsf.frame, + PHOUR = 2, + PMIN = leadoutPmsf.minute, + PSEC = leadoutPmsf.second, + PFRAME = leadoutPmsf.frame + }); + + // This seems to be constant? It should not exist on CD-ROM but CloneCD creates them anyway + // Format seems like ATIP, but ATIP should not be as 0xC0 in TOC... + if(createC0Entry) + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xC0, + ADR = 5, + CONTROL = 0, + Min = 128, + PMIN = 97, + PSEC = 25 + }); + } + + // Lead-in + if(track.Session > currentSession) + { + currentSession = (byte)track.Session; + sessionEndingTrack.TryGetValue(currentSession, out byte endingTrackNumber); + + (byte minute, byte second, byte frame) leadinPmsf = + LbaToMsf((tracks.FirstOrDefault(t => t.Sequence == endingTrackNumber)?.EndSector ?? 0) + 1); + + // Starting track + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xA0, + ADR = 1, + CONTROL = trackControl, + PMIN = (byte)track.Sequence + }); + + // Ending track + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xA1, + ADR = 1, + CONTROL = trackControl, + PMIN = endingTrackNumber + }); + + // Lead-out start + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = currentSession, + POINT = 0xA2, ADR = 1, CONTROL = trackControl, PHOUR = 0, - PMIN = pmsf.minute, - PSEC = pmsf.second, - PFRAME = pmsf.frame + PMIN = leadinPmsf.minute, + PSEC = leadinPmsf.second, + PFRAME = leadinPmsf.frame }); } - toc.TrackDescriptors = trackDescriptors.ToArray(); + (byte minute, byte second, byte frame) pmsf = LbaToMsf((ulong)track.Indexes[1]); - return toc; + // Track + trackDescriptors.Add(new TrackDataDescriptor + { + SessionNumber = (byte)track.Session, + POINT = (byte)track.Sequence, + ADR = 1, + CONTROL = trackControl, + PHOUR = 0, + PMIN = pmsf.minute, + PSEC = pmsf.second, + PFRAME = pmsf.frame + }); } - static (byte minute, byte second, byte frame) LbaToMsf(ulong sector) => - ((byte)((sector + 150) / 75 / 60), (byte)((sector + 150) / 75 % 60), (byte)((sector + 150) % 75)); + toc.TrackDescriptors = trackDescriptors.ToArray(); + + return toc; } + + static (byte minute, byte second, byte frame) LbaToMsf(ulong sector) => + ((byte)((sector + 150) / 75 / 60), (byte)((sector + 150) / 75 % 60), (byte)((sector + 150) % 75)); } \ No newline at end of file diff --git a/CD/PMA.cs b/CD/PMA.cs index f1c2dc3..6fde8f3 100644 --- a/CD/PMA.cs +++ b/CD/PMA.cs @@ -35,311 +35,310 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class PMA { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class PMA + public static CDPMA? Decode(byte[] CDPMAResponse) { - public static CDPMA? Decode(byte[] CDPMAResponse) + if(CDPMAResponse == null || + CDPMAResponse.Length <= 4) + return null; + + var decoded = new CDPMA { - if(CDPMAResponse == null || - CDPMAResponse.Length <= 4) - return null; + DataLength = BigEndianBitConverter.ToUInt16(CDPMAResponse, 0), + Reserved1 = CDPMAResponse[2], + Reserved2 = CDPMAResponse[3] + }; - var decoded = new CDPMA - { - DataLength = BigEndianBitConverter.ToUInt16(CDPMAResponse, 0), - Reserved1 = CDPMAResponse[2], - Reserved2 = CDPMAResponse[3] - }; + decoded.PMADescriptors = new CDPMADescriptors[(decoded.DataLength - 2) / 11]; - decoded.PMADescriptors = new CDPMADescriptors[(decoded.DataLength - 2) / 11]; + if(decoded.PMADescriptors.Length == 0) + return null; - if(decoded.PMADescriptors.Length == 0) - return null; + if(decoded.DataLength + 2 != CDPMAResponse.Length) + { + AaruConsole.DebugWriteLine("CD PMA decoder", + "Expected CDPMA size ({0} bytes) is not received size ({1} bytes), not decoding", + decoded.DataLength + 2, CDPMAResponse.Length); - if(decoded.DataLength + 2 != CDPMAResponse.Length) - { - AaruConsole.DebugWriteLine("CD PMA decoder", - "Expected CDPMA size ({0} bytes) is not received size ({1} bytes), not decoding", - decoded.DataLength + 2, CDPMAResponse.Length); - - return null; - } - - for(int i = 0; i < (decoded.DataLength - 2) / 11; i++) - { - decoded.PMADescriptors[i].Reserved = CDPMAResponse[0 + (i * 11) + 4]; - decoded.PMADescriptors[i].ADR = (byte)((CDPMAResponse[1 + (i * 11) + 4] & 0xF0) >> 4); - decoded.PMADescriptors[i].CONTROL = (byte)(CDPMAResponse[1 + (i * 11) + 4] & 0x0F); - decoded.PMADescriptors[i].TNO = CDPMAResponse[2 + (i * 11) + 4]; - decoded.PMADescriptors[i].POINT = CDPMAResponse[3 + (i * 11) + 4]; - decoded.PMADescriptors[i].Min = CDPMAResponse[4 + (i * 11) + 4]; - decoded.PMADescriptors[i].Sec = CDPMAResponse[5 + (i * 11) + 4]; - decoded.PMADescriptors[i].Frame = CDPMAResponse[6 + (i * 11) + 4]; - decoded.PMADescriptors[i].HOUR = (byte)((CDPMAResponse[7 + (i * 11) + 4] & 0xF0) >> 4); - decoded.PMADescriptors[i].PHOUR = (byte)(CDPMAResponse[7 + (i * 11) + 4] & 0x0F); - decoded.PMADescriptors[i].PMIN = CDPMAResponse[8 + (i * 11) + 4]; - decoded.PMADescriptors[i].PSEC = CDPMAResponse[9 + (i * 11) + 4]; - decoded.PMADescriptors[i].PFRAME = CDPMAResponse[10 + (i * 11) + 4]; - } - - return decoded; + return null; } - public static string Prettify(CDPMA? CDPMAResponse) + for(int i = 0; i < (decoded.DataLength - 2) / 11; i++) { - if(CDPMAResponse == null) - return null; + decoded.PMADescriptors[i].Reserved = CDPMAResponse[0 + (i * 11) + 4]; + decoded.PMADescriptors[i].ADR = (byte)((CDPMAResponse[1 + (i * 11) + 4] & 0xF0) >> 4); + decoded.PMADescriptors[i].CONTROL = (byte)(CDPMAResponse[1 + (i * 11) + 4] & 0x0F); + decoded.PMADescriptors[i].TNO = CDPMAResponse[2 + (i * 11) + 4]; + decoded.PMADescriptors[i].POINT = CDPMAResponse[3 + (i * 11) + 4]; + decoded.PMADescriptors[i].Min = CDPMAResponse[4 + (i * 11) + 4]; + decoded.PMADescriptors[i].Sec = CDPMAResponse[5 + (i * 11) + 4]; + decoded.PMADescriptors[i].Frame = CDPMAResponse[6 + (i * 11) + 4]; + decoded.PMADescriptors[i].HOUR = (byte)((CDPMAResponse[7 + (i * 11) + 4] & 0xF0) >> 4); + decoded.PMADescriptors[i].PHOUR = (byte)(CDPMAResponse[7 + (i * 11) + 4] & 0x0F); + decoded.PMADescriptors[i].PMIN = CDPMAResponse[8 + (i * 11) + 4]; + decoded.PMADescriptors[i].PSEC = CDPMAResponse[9 + (i * 11) + 4]; + decoded.PMADescriptors[i].PFRAME = CDPMAResponse[10 + (i * 11) + 4]; + } - CDPMA response = CDPMAResponse.Value; + return decoded; + } - var sb = new StringBuilder(); + public static string Prettify(CDPMA? CDPMAResponse) + { + if(CDPMAResponse == null) + return null; + CDPMA response = CDPMAResponse.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 + + foreach(CDPMADescriptors descriptor in response.PMADescriptors) + { #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(descriptor.Reserved != 0) + sb.AppendFormat("Reserved = 0x{0:X2}", descriptor.Reserved).AppendLine(); #endif - foreach(CDPMADescriptors descriptor in response.PMADescriptors) + switch(descriptor.ADR) { - #if DEBUG - if(descriptor.Reserved != 0) - sb.AppendFormat("Reserved = 0x{0:X2}", descriptor.Reserved).AppendLine(); - #endif + case 1: + if(descriptor.POINT > 0) + { + sb.AppendFormat("Track {0}", descriptor.POINT); - switch(descriptor.ADR) - { - case 1: - if(descriptor.POINT > 0) + switch((TocControl)(descriptor.CONTROL & 0x0D)) { - sb.AppendFormat("Track {0}", descriptor.POINT); + case TocControl.TwoChanNoPreEmph: + sb.Append(" (Stereo audio track with no pre-emphasis)"); - 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.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.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.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.DataTrack: - sb.Append(" (Data track, recorded uninterrupted)"); + break; + case TocControl.DataTrackIncremental: + sb.Append(" (Data track, recorded incrementally)"); - break; - case TocControl.DataTrackIncremental: - sb.Append(" (Data track, recorded incrementally)"); - - break; - } - - if(descriptor.PHOUR > 0) - sb.AppendFormat(" starts at {3}:{0:D2}:{1:D2}:{2:D2}", descriptor.PMIN, descriptor.PSEC, - descriptor.PFRAME, descriptor.PHOUR); - 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); - else - sb.AppendFormat(" and ends at {0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, - descriptor.Frame); - - sb.AppendLine(); + break; } - 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); - - 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); - - 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, + sb.AppendFormat(" starts at {3}:{0:D2}:{1:D2}:{2:D2}", descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME, descriptor.PHOUR); else - sb.AppendFormat("{0:D2}:{1:D2}:{2:D2} to ", descriptor.PMIN, descriptor.PSEC, + sb.AppendFormat(" starts at {0:D2}:{1:D2}:{2:D2}", descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME); if(descriptor.PHOUR > 0) - sb.AppendFormat("{3}:{0:D2}:{1:D2}:{2:D2} ", descriptor.Min, descriptor.Sec, + sb.AppendFormat(" and ends at {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); + sb.AppendFormat(" and ends at {0:D2}:{1:D2}:{2:D2}", descriptor.Min, descriptor.Sec, + descriptor.Frame); - sb.AppendLine("should be skipped"); + sb.AppendLine(); + } + else + goto default; - break; - case 6: - sb.AppendFormat("Unskip time interval assignment {0} says that from ", descriptor.POINT); + break; + case 2: + uint id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame); + sb.AppendFormat("Disc ID: {0:X6}", id & 0x00FFFFFF).AppendLine(); - 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); + break; + case 3: + sb.AppendFormat("Skip track assignment {0} says that tracks ", descriptor.POINT); - 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); + if(descriptor.Min > 0) + sb.AppendFormat("{0} ", descriptor.Min); - sb.AppendLine("should not be skipped"); + if(descriptor.Sec > 0) + sb.AppendFormat("{0} ", descriptor.Sec); - break; - default: + if(descriptor.Frame > 0) + sb.AppendFormat("{0} ", descriptor.Frame); - sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); - sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); - sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); - sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); - sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); - sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); - sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); - sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); - sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); - sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); - sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); - sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); + if(descriptor.PMIN > 0) + sb.AppendFormat("{0} ", descriptor.PMIN); - break; - } + 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); + + 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); + + 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); + + sb.AppendLine("should not be skipped"); + + break; + default: + + sb.AppendFormat("ADR = {0}", descriptor.ADR).AppendLine(); + sb.AppendFormat("CONTROL = {0}", descriptor.CONTROL).AppendLine(); + sb.AppendFormat("TNO = {0}", descriptor.TNO).AppendLine(); + sb.AppendFormat("POINT = {0}", descriptor.POINT).AppendLine(); + sb.AppendFormat("Min = {0}", descriptor.Min).AppendLine(); + sb.AppendFormat("Sec = {0}", descriptor.Sec).AppendLine(); + sb.AppendFormat("Frame = {0}", descriptor.Frame).AppendLine(); + sb.AppendFormat("HOUR = {0}", descriptor.HOUR).AppendLine(); + sb.AppendFormat("PHOUR = {0}", descriptor.PHOUR).AppendLine(); + sb.AppendFormat("PMIN = {0}", descriptor.PMIN).AppendLine(); + sb.AppendFormat("PSEC = {0}", descriptor.PSEC).AppendLine(); + sb.AppendFormat("PFRAME = {0}", descriptor.PFRAME).AppendLine(); + + break; } - - return sb.ToString(); } - public static string Prettify(byte[] CDPMAResponse) - { - CDPMA? decoded = Decode(CDPMAResponse); + return sb.ToString(); + } - return Prettify(decoded); - } + public static string Prettify(byte[] CDPMAResponse) + { + CDPMA? decoded = Decode(CDPMAResponse); - public struct CDPMA - { - /// Total size of returned session information minus this field - public ushort DataLength; - /// Reserved - public byte Reserved1; - /// Reserved - public byte Reserved2; - /// Track descriptors - public CDPMADescriptors[] PMADescriptors; - } + return Prettify(decoded); + } - public struct CDPMADescriptors - { - /// Byte 0 Reserved - public byte Reserved; - /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found - public byte ADR; - /// Byte 1, bits 3 to 0 Track attributes - public byte CONTROL; - /// Byte 2 - public byte TNO; - /// Byte 3 - public byte POINT; - /// Byte 4 - public byte Min; - /// Byte 5 - public byte Sec; - /// Byte 6 - public byte Frame; - /// Byte 7, bits 7 to 4 - public byte HOUR; - /// Byte 7, bits 3 to 0 - public byte PHOUR; - /// Byte 8 - public byte PMIN; - /// Byte 9 - public byte PSEC; - /// Byte 10 - public byte PFRAME; - } + public struct CDPMA + { + /// Total size of returned session information minus this field + public ushort DataLength; + /// Reserved + public byte Reserved1; + /// Reserved + public byte Reserved2; + /// Track descriptors + public CDPMADescriptors[] PMADescriptors; + } + + public struct CDPMADescriptors + { + /// Byte 0 Reserved + public byte Reserved; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 + public byte TNO; + /// Byte 3 + public byte POINT; + /// Byte 4 + public byte Min; + /// Byte 5 + public byte Sec; + /// Byte 6 + public byte Frame; + /// Byte 7, bits 7 to 4 + public byte HOUR; + /// Byte 7, bits 3 to 0 + public byte PHOUR; + /// Byte 8 + public byte PMIN; + /// Byte 9 + public byte PSEC; + /// Byte 10 + public byte PFRAME; } } \ No newline at end of file diff --git a/CD/Sector.cs b/CD/Sector.cs index 15c04bb..f0fc69b 100644 --- a/CD/Sector.cs +++ b/CD/Sector.cs @@ -37,440 +37,439 @@ using System.Runtime.CompilerServices; using System.Text; using Aaru.Checksums; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Sector { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Sector + public static readonly byte[] ScrambleTable = { - 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 = - { - 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 - }; + public static readonly byte[] SyncMark = + { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 + }; - public static byte[] Scramble(byte[] sector) - { - if(sector == null || - sector.Length < 2352) - return sector; + public static byte[] Scramble(byte[] sector) + { + if(sector == null || + sector.Length < 2352) + return sector; - byte[] sync = new byte[12]; - Array.Copy(sector, 0, sync, 0, 12); + 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]; + byte[] scrambled = new byte[sector.Length]; - for(int i = 0; i < 2352; i++) - scrambled[i] = (byte)(sector[i] ^ ScrambleTable[i]); - - if(sector.Length <= 2352) - return scrambled; - - for(int i = 2352; i < sector.Length; i++) - scrambled[i] = sector[i]; + for(int i = 0; i < 2352; i++) + scrambled[i] = (byte)(sector[i] ^ ScrambleTable[i]); + if(sector.Length <= 2352) return scrambled; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] GetUserData(byte[] data, bool interleaved = false, byte fileNumber = 0) + for(int i = 2352; i < sector.Length; i++) + scrambled[i] = sector[i]; + + return scrambled; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetUserData(byte[] data, bool interleaved = false, byte fileNumber = 0) + { + switch(data.Length) { - switch(data.Length) - { - case 2352 when data[0] != 0x00 || data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || - data[4] != 0xFF || data[5] != 0xFF || data[6] != 0xFF || data[7] != 0xFF || - data[8] != 0xFF || data[9] != 0xFF || data[10] != 0xFF || data[11] != 0x00: return data; - case 2352: - switch(data[15]) - { - case 0: return new byte[2048]; - case 1: - byte[] sector = new byte[2048]; - Array.Copy(data, 16, sector, 0, 2048); + case 2352 when data[0] != 0x00 || data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || + data[4] != 0xFF || data[5] != 0xFF || data[6] != 0xFF || data[7] != 0xFF || + data[8] != 0xFF || data[9] != 0xFF || data[10] != 0xFF || data[11] != 0x00: return data; + case 2352: + switch(data[15]) + { + case 0: return new byte[2048]; + case 1: + byte[] sector = new byte[2048]; + Array.Copy(data, 16, sector, 0, 2048); - return sector; - case 2: return GetUserDataFromMode2(data, interleaved, fileNumber); - default: return data; - } - case 2336: return GetUserDataFromMode2(data, interleaved, fileNumber); - default: return data; - } + return sector; + case 2: return GetUserDataFromMode2(data, interleaved, fileNumber); + default: return data; + } + case 2336: return GetUserDataFromMode2(data, interleaved, fileNumber); + default: return data; } + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] GetUserDataFromMode2(byte[] data, bool interleaved = false, byte fileNumber = 0) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetUserDataFromMode2(byte[] data, bool interleaved = false, byte fileNumber = 0) + { + if(data.Length != 2352 && + data.Length != 2336) + return data; + + int pos = 0; + + if(data.Length == 2352) { - if(data.Length != 2352 && - data.Length != 2336) + if(data[0] != 0x00 || + data[1] != 0xFF || + data[2] != 0xFF || + data[3] != 0xFF || + data[4] != 0xFF || + data[5] != 0xFF || + data[6] != 0xFF || + data[7] != 0xFF || + data[8] != 0xFF || + data[9] != 0xFF || + data[10] != 0xFF || + data[11] != 0x00 || + data[15] != 0x02) return data; - int pos = 0; - - if(data.Length == 2352) - { - if(data[0] != 0x00 || - data[1] != 0xFF || - data[2] != 0xFF || - data[3] != 0xFF || - data[4] != 0xFF || - data[5] != 0xFF || - data[6] != 0xFF || - data[7] != 0xFF || - data[8] != 0xFF || - data[9] != 0xFF || - data[10] != 0xFF || - data[11] != 0x00 || - data[15] != 0x02) - return data; - - pos = 16; - } - - // This is not the sector you are looking for - if(interleaved && data[pos] != fileNumber) - return null; - - int len = (data[pos + 2] & 0x20) == 0x20 ? 2324 : 2048; - pos += 8; - - byte[] sector = new byte[len]; - Array.Copy(data, pos, sector, 0, len); - - return sector; + pos = 16; } - public static string Prettify(byte[] buffer) + // This is not the sector you are looking for + if(interleaved && data[pos] != fileNumber) + return null; + + int len = (data[pos + 2] & 0x20) == 0x20 ? 2324 : 2048; + pos += 8; + + byte[] sector = new byte[len]; + Array.Copy(data, pos, sector, 0, len); + + return sector; + } + + public static string Prettify(byte[] buffer) + { + if(buffer is null || + buffer.Length <= 0) + return null; + + if(buffer[0] != 0x00 || + buffer[1] != 0xFF || + buffer[2] != 0xFF || + buffer[3] != 0xFF || + buffer[4] != 0xFF || + buffer[5] != 0xFF || + buffer[6] != 0xFF || + buffer[7] != 0xFF || + buffer[8] != 0xFF || + buffer[9] != 0xFF || + buffer[10] != 0xFF || + buffer[11] != 0x00) + return "CD sector."; + + var sb = new StringBuilder(); + + sb.AppendLine("CD-ROM sector."); + + byte min = buffer[12]; + byte sec = buffer[13]; + byte frame = buffer[14]; + int lba = 0; + bool moreThan90 = false; + + if(min > 0x90) { - if(buffer is null || - buffer.Length <= 0) - return null; + lba += 405000; + min -= 0x90; + moreThan90 = true; + } - if(buffer[0] != 0x00 || - buffer[1] != 0xFF || - buffer[2] != 0xFF || - buffer[3] != 0xFF || - buffer[4] != 0xFF || - buffer[5] != 0xFF || - buffer[6] != 0xFF || - buffer[7] != 0xFF || - buffer[8] != 0xFF || - buffer[9] != 0xFF || - buffer[10] != 0xFF || - buffer[11] != 0x00) - return "CD sector."; + lba += (((min >> 4) * 10) + (min & 0x0F)) * 75 * 60; + lba += (((sec >> 4) * 10) + (sec & 0x0F)) * 75; + lba += ((frame >> 4) * 10) + (frame & 0x0F); + lba -= 150; - var sb = new StringBuilder(); + if(moreThan90) + min += 0x90; - sb.AppendLine("CD-ROM sector."); + sb.AppendFormat("Position {0:X2}:{1:X2}:{2:X2} (LBA {3})", min, sec, frame, lba).AppendLine(); - byte min = buffer[12]; - byte sec = buffer[13]; - byte frame = buffer[14]; - int lba = 0; - bool moreThan90 = false; + switch(buffer[15] & 0x03) + { + case 0: + sb.AppendLine("Mode 0."); - if(min > 0x90) - { - lba += 405000; - min -= 0x90; - moreThan90 = true; - } + break; + case 1: + sb.AppendLine("Mode 1."); - lba += (((min >> 4) * 10) + (min & 0x0F)) * 75 * 60; - lba += (((sec >> 4) * 10) + (sec & 0x0F)) * 75; - lba += ((frame >> 4) * 10) + (frame & 0x0F); - lba -= 150; + break; + case 2: + sb.AppendLine("Mode 2."); - if(moreThan90) - min += 0x90; + break; + case 3: + sb.AppendLine("Invalid mode 0."); - sb.AppendFormat("Position {0:X2}:{1:X2}:{2:X2} (LBA {3})", min, sec, frame, lba).AppendLine(); + break; + } - switch(buffer[15] & 0x03) - { - case 0: - sb.AppendLine("Mode 0."); + switch((buffer[15] & 0xE0) >> 5) + { + case 0: + sb.AppendLine("User data block"); - break; - case 1: - sb.AppendLine("Mode 1."); + break; + case 1: + sb.AppendLine("Fourth run-in block"); - break; - case 2: - sb.AppendLine("Mode 2."); + break; + case 2: + sb.AppendLine("Third run-in block"); - break; - case 3: - sb.AppendLine("Invalid mode 0."); + break; + case 3: + sb.AppendLine("Second run-in block"); - break; - } + break; + case 4: + sb.AppendLine("First run-in block"); - switch((buffer[15] & 0xE0) >> 5) - { - case 0: - sb.AppendLine("User data block"); + break; + case 5: + sb.AppendLine("Link block"); - break; - case 1: - sb.AppendLine("Fourth run-in block"); + break; + case 6: + sb.AppendLine("Second run-out block"); - break; - case 2: - sb.AppendLine("Third run-in block"); + break; + case 7: + sb.AppendLine("First run-out block"); - break; - case 3: - sb.AppendLine("Second run-in block"); + break; + } - break; - case 4: - sb.AppendLine("First run-in block"); + CdChecksums.CheckCdSector(buffer, out bool? correctEccP, out bool? correctEccQ, out bool? correctEdc); - break; - case 5: - sb.AppendLine("Link block"); + bool empty = true; - break; - case 6: - sb.AppendLine("Second run-out block"); + switch(buffer[15] & 0x03) + { + case 0: - break; - case 7: - sb.AppendLine("First run-out block"); - - break; - } - - CdChecksums.CheckCdSector(buffer, out bool? correctEccP, out bool? correctEccQ, out bool? correctEdc); - - bool empty = true; - - switch(buffer[15] & 0x03) - { - case 0: - - for(int i = 16; i < 2352; i++) + for(int i = 16; i < 2352; i++) + { + if(buffer[i] != 0x00) { - if(buffer[i] != 0x00) - { - empty = false; + empty = false; - break; - } + break; } + } - sb.AppendLine(empty ? "Correct sector contents." : "Incorrect sector contents."); + sb.AppendLine(empty ? "Correct sector contents." : "Incorrect sector contents."); - break; - case 1: + break; + case 1: + sb.AppendLine(correctEdc == true ? "Correct EDC." : "Incorrect EDC."); + sb.AppendLine(correctEccP == true ? "Correct ECC P." : "Incorrect ECC P."); + sb.AppendLine(correctEccQ == true ? "Correct ECC Q." : "Incorrect ECC Q."); + + for(int i = 2068; i < 2076; i++) + { + if(buffer[i] != 0x00) + { + empty = false; + + break; + } + } + + sb.AppendLine(empty ? "Correct zero fill." : "Incorrect zero fill."); + + break; + case 2: + if(buffer[16] != buffer[20] || + buffer[17] != buffer[21] || + buffer[18] != buffer[22] || + buffer[19] != buffer[23]) + { + sb.AppendLine("Subheader copies differ."); sb.AppendLine(correctEdc == true ? "Correct EDC." : "Incorrect EDC."); sb.AppendLine(correctEccP == true ? "Correct ECC P." : "Incorrect ECC P."); sb.AppendLine(correctEccQ == true ? "Correct ECC Q." : "Incorrect ECC Q."); - for(int i = 2068; i < 2076; i++) - { - if(buffer[i] != 0x00) - { - empty = false; - - break; - } - } - - sb.AppendLine(empty ? "Correct zero fill." : "Incorrect zero fill."); - break; - case 2: - if(buffer[16] != buffer[20] || - buffer[17] != buffer[21] || - buffer[18] != buffer[22] || - buffer[19] != buffer[23]) - { - sb.AppendLine("Subheader copies differ."); - sb.AppendLine(correctEdc == true ? "Correct EDC." : "Incorrect EDC."); - sb.AppendLine(correctEccP == true ? "Correct ECC P." : "Incorrect ECC P."); - sb.AppendLine(correctEccQ == true ? "Correct ECC Q." : "Incorrect ECC Q."); + } - break; - } + sb.AppendFormat("File number: {0}", buffer[16]).AppendLine(); + sb.AppendFormat("Channel number: {0}", buffer[17]).AppendLine(); + sb.AppendFormat("Coding information number: {0}", buffer[19]).AppendLine(); - sb.AppendFormat("File number: {0}", buffer[16]).AppendLine(); - sb.AppendFormat("Channel number: {0}", buffer[17]).AppendLine(); - sb.AppendFormat("Coding information number: {0}", buffer[19]).AppendLine(); + if((buffer[18] & 0x80) == 0x80) + sb.AppendLine("End of file."); - if((buffer[18] & 0x80) == 0x80) - sb.AppendLine("End of file."); + if((buffer[18] & 0x40) == 0x40) + sb.AppendLine("Real-time block."); - if((buffer[18] & 0x40) == 0x40) - sb.AppendLine("Real-time block."); + sb.AppendLine((buffer[18] & 0x20) == 0x20 ? "Form 2." : "Form 1."); - sb.AppendLine((buffer[18] & 0x20) == 0x20 ? "Form 2." : "Form 1."); + if((buffer[18] & 0x10) == 0x10) + sb.AppendLine("Trigger block."); - if((buffer[18] & 0x10) == 0x10) - sb.AppendLine("Trigger block."); + if((buffer[18] & 0x08) == 0x08) + sb.AppendLine("Data block."); - if((buffer[18] & 0x08) == 0x08) - sb.AppendLine("Data block."); + if((buffer[18] & 0x04) == 0x04) + sb.AppendLine("Audio block."); - if((buffer[18] & 0x04) == 0x04) - sb.AppendLine("Audio block."); + if((buffer[18] & 0x02) == 0x02) + sb.AppendLine("Video block."); - if((buffer[18] & 0x02) == 0x02) - sb.AppendLine("Video block."); + if((buffer[18] & 0x01) == 0x01) + sb.AppendLine("End of record."); - if((buffer[18] & 0x01) == 0x01) - sb.AppendLine("End of record."); + if((buffer[18] & 0x20) != 0x20) + { + sb.AppendLine(correctEccP == true ? "Correct ECC P." : "Incorrect ECC P."); + sb.AppendLine(correctEccQ == true ? "Correct ECC Q." : "Incorrect ECC Q."); + } - if((buffer[18] & 0x20) != 0x20) - { - sb.AppendLine(correctEccP == true ? "Correct ECC P." : "Incorrect ECC P."); - sb.AppendLine(correctEccQ == true ? "Correct ECC Q." : "Incorrect ECC Q."); - } + sb.AppendLine(correctEdc == true ? "Correct EDC." : "Incorrect EDC."); - sb.AppendLine(correctEdc == true ? "Correct EDC." : "Incorrect EDC."); - - break; - } - - return sb.ToString(); + break; } + + return sb.ToString(); } } \ No newline at end of file diff --git a/CD/SectorBuilder.cs b/CD/SectorBuilder.cs index a3ac1b9..cbdc397 100644 --- a/CD/SectorBuilder.cs +++ b/CD/SectorBuilder.cs @@ -29,210 +29,209 @@ using System; using Aaru.CommonTypes.Enums; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +public class SectorBuilder { - public class SectorBuilder + readonly byte[] _eccBTable; + readonly byte[] _eccFTable; + readonly uint[] _edcTable; + + public SectorBuilder() { - readonly byte[] _eccBTable; - readonly byte[] _eccFTable; - readonly uint[] _edcTable; + _eccFTable = new byte[256]; + _eccBTable = new byte[256]; + _edcTable = new uint[256]; - public SectorBuilder() + for(uint i = 0; i < 256; i++) { - _eccFTable = new byte[256]; - _eccBTable = new byte[256]; - _edcTable = new uint[256]; + uint edc = i; + uint j = (uint)((i << 1) ^ ((i & 0x80) == 0x80 ? 0x11D : 0)); + _eccFTable[i] = (byte)j; + _eccBTable[i ^ j] = (byte)i; - for(uint i = 0; i < 256; i++) - { - uint edc = i; - uint j = (uint)((i << 1) ^ ((i & 0x80) == 0x80 ? 0x11D : 0)); - _eccFTable[i] = (byte)j; - _eccBTable[i ^ j] = (byte)i; + for(j = 0; j < 8; j++) + edc = (edc >> 1) ^ ((edc & 1) > 0 ? 0xD8018001 : 0); - for(j = 0; j < 8; j++) - edc = (edc >> 1) ^ ((edc & 1) > 0 ? 0xD8018001 : 0); - - _edcTable[i] = edc; - } + _edcTable[i] = edc; } + } - static (byte minute, byte second, byte frame) LbaToMsf(long pos) => - ((byte)((pos + 150) / 75 / 60), (byte)((pos + 150) / 75 % 60), (byte)((pos + 150) % 75)); + static (byte minute, byte second, byte frame) LbaToMsf(long pos) => + ((byte)((pos + 150) / 75 / 60), (byte)((pos + 150) / 75 % 60), (byte)((pos + 150) % 75)); - public void ReconstructPrefix(ref byte[] sector, // must point to a full 2352-byte sector - TrackType type, long lba) + public void ReconstructPrefix(ref byte[] sector, // must point to a full 2352-byte sector + TrackType type, long lba) + { + // + // Sync + // + sector[0x000] = 0x00; + sector[0x001] = 0xFF; + sector[0x002] = 0xFF; + sector[0x003] = 0xFF; + sector[0x004] = 0xFF; + sector[0x005] = 0xFF; + sector[0x006] = 0xFF; + sector[0x007] = 0xFF; + sector[0x008] = 0xFF; + sector[0x009] = 0xFF; + sector[0x00A] = 0xFF; + sector[0x00B] = 0x00; + + (byte minute, byte second, byte frame) msf = LbaToMsf(lba); + + sector[0x00C] = (byte)(((msf.minute / 10) << 4) + (msf.minute % 10)); + sector[0x00D] = (byte)(((msf.second / 10) << 4) + (msf.second % 10)); + sector[0x00E] = (byte)(((msf.frame / 10) << 4) + (msf.frame % 10)); + + switch(type) + { + case TrackType.CdMode1: + // + // Mode + // + sector[0x00F] = 0x01; + + break; + case TrackType.CdMode2Form1: + case TrackType.CdMode2Form2: + case TrackType.CdMode2Formless: + // + // Mode + // + sector[0x00F] = 0x02; + + // + // Flags + // + sector[0x010] = sector[0x014]; + sector[0x011] = sector[0x015]; + sector[0x012] = sector[0x016]; + sector[0x013] = sector[0x017]; + + break; + default: return; + } + } + + uint ComputeEdc(uint edc, byte[] src, int size, int srcOffset = 0) + { + int pos = srcOffset; + + for(; size > 0; size--) + edc = (edc >> 8) ^ _edcTable[(edc ^ src[pos++]) & 0xFF]; + + return edc; + } + + public void ReconstructEcc(ref byte[] sector, // must point to a full 2352-byte sector + TrackType type) + { + byte[] computedEdc; + + switch(type) { // - // Sync + // Compute EDC // - sector[0x000] = 0x00; - sector[0x001] = 0xFF; - sector[0x002] = 0xFF; - sector[0x003] = 0xFF; - sector[0x004] = 0xFF; - sector[0x005] = 0xFF; - sector[0x006] = 0xFF; - sector[0x007] = 0xFF; - sector[0x008] = 0xFF; - sector[0x009] = 0xFF; - sector[0x00A] = 0xFF; - sector[0x00B] = 0x00; + case TrackType.CdMode1: + computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x810)); + sector[0x810] = computedEdc[0]; + sector[0x811] = computedEdc[1]; + sector[0x812] = computedEdc[2]; + sector[0x813] = computedEdc[3]; - (byte minute, byte second, byte frame) msf = LbaToMsf(lba); + break; + case TrackType.CdMode2Form1: + computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x808, 0x10)); + sector[0x818] = computedEdc[0]; + sector[0x819] = computedEdc[1]; + sector[0x81A] = computedEdc[2]; + sector[0x81B] = computedEdc[3]; - sector[0x00C] = (byte)(((msf.minute / 10) << 4) + (msf.minute % 10)); - sector[0x00D] = (byte)(((msf.second / 10) << 4) + (msf.second % 10)); - sector[0x00E] = (byte)(((msf.frame / 10) << 4) + (msf.frame % 10)); + break; + case TrackType.CdMode2Form2: + computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x91C, 0x10)); + sector[0x92C] = computedEdc[0]; + sector[0x92D] = computedEdc[1]; + sector[0x92E] = computedEdc[2]; + sector[0x92F] = computedEdc[3]; - switch(type) - { - case TrackType.CdMode1: - // - // Mode - // - sector[0x00F] = 0x01; - - break; - case TrackType.CdMode2Form1: - case TrackType.CdMode2Form2: - case TrackType.CdMode2Formless: - // - // Mode - // - sector[0x00F] = 0x02; - - // - // Flags - // - sector[0x010] = sector[0x014]; - sector[0x011] = sector[0x015]; - sector[0x012] = sector[0x016]; - sector[0x013] = sector[0x017]; - - break; - default: return; - } + break; + default: return; } - uint ComputeEdc(uint edc, byte[] src, int size, int srcOffset = 0) + byte[] zeroaddress = new byte[4]; + + switch(type) { - int pos = srcOffset; - - for(; size > 0; size--) - edc = (edc >> 8) ^ _edcTable[(edc ^ src[pos++]) & 0xFF]; - - return edc; - } - - public void ReconstructEcc(ref byte[] sector, // must point to a full 2352-byte sector - TrackType type) - { - byte[] computedEdc; - - switch(type) - { - // - // Compute EDC - // - case TrackType.CdMode1: - computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x810)); - sector[0x810] = computedEdc[0]; - sector[0x811] = computedEdc[1]; - sector[0x812] = computedEdc[2]; - sector[0x813] = computedEdc[3]; - - break; - case TrackType.CdMode2Form1: - computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x808, 0x10)); - sector[0x818] = computedEdc[0]; - sector[0x819] = computedEdc[1]; - sector[0x81A] = computedEdc[2]; - sector[0x81B] = computedEdc[3]; - - break; - case TrackType.CdMode2Form2: - computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x91C, 0x10)); - sector[0x92C] = computedEdc[0]; - sector[0x92D] = computedEdc[1]; - sector[0x92E] = computedEdc[2]; - sector[0x92F] = computedEdc[3]; - - break; - default: return; - } - - byte[] zeroaddress = new byte[4]; - - switch(type) - { - // - // Compute ECC - // - case TrackType.CdMode1: - // - // Reserved - // - sector[0x814] = 0x00; - sector[0x815] = 0x00; - sector[0x816] = 0x00; - sector[0x817] = 0x00; - sector[0x818] = 0x00; - sector[0x819] = 0x00; - sector[0x81A] = 0x00; - sector[0x81B] = 0x00; - EccWriteSector(sector, sector, ref sector, 0xC, 0x10, 0x81C); - - break; - case TrackType.CdMode2Form1: - EccWriteSector(zeroaddress, sector, ref sector, 0, 0x10, 0x81C); - - break; - default: return; - } - // - // Done + // Compute ECC // + case TrackType.CdMode1: + // + // Reserved + // + sector[0x814] = 0x00; + sector[0x815] = 0x00; + sector[0x816] = 0x00; + sector[0x817] = 0x00; + sector[0x818] = 0x00; + sector[0x819] = 0x00; + sector[0x81A] = 0x00; + sector[0x81B] = 0x00; + EccWriteSector(sector, sector, ref sector, 0xC, 0x10, 0x81C); + + break; + case TrackType.CdMode2Form1: + EccWriteSector(zeroaddress, sector, ref sector, 0, 0x10, 0x81C); + + break; + default: return; } - void EccWriteSector(byte[] address, byte[] data, ref byte[] ecc, int addressOffset, int dataOffset, - int eccOffset) - { - WriteEcc(address, data, 86, 24, 2, 86, ref ecc, addressOffset, dataOffset, eccOffset); // P - WriteEcc(address, data, 52, 43, 86, 88, ref ecc, addressOffset, dataOffset, eccOffset + 0xAC); // Q - } + // + // Done + // + } - void WriteEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc, - ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset) - { - uint size = majorCount * minorCount; - uint major; + void EccWriteSector(byte[] address, byte[] data, ref byte[] ecc, int addressOffset, int dataOffset, + int eccOffset) + { + WriteEcc(address, data, 86, 24, 2, 86, ref ecc, addressOffset, dataOffset, eccOffset); // P + WriteEcc(address, data, 52, 43, 86, 88, ref ecc, addressOffset, dataOffset, eccOffset + 0xAC); // Q + } - for(major = 0; major < majorCount; major++) + void WriteEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc, + ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset) + { + uint size = majorCount * minorCount; + uint major; + + for(major = 0; major < majorCount; major++) + { + uint idx = ((major >> 1) * majorMult) + (major & 1); + byte eccA = 0; + byte eccB = 0; + uint minor; + + for(minor = 0; minor < minorCount; minor++) { - uint idx = ((major >> 1) * majorMult) + (major & 1); - byte eccA = 0; - byte eccB = 0; - uint minor; + byte temp = idx < 4 ? address[idx + addressOffset] : data[idx + dataOffset - 4]; + idx += minorInc; - for(minor = 0; minor < minorCount; minor++) - { - byte temp = idx < 4 ? address[idx + addressOffset] : data[idx + dataOffset - 4]; - idx += minorInc; + if(idx >= size) + idx -= size; - if(idx >= size) - idx -= size; - - eccA ^= temp; - eccB ^= temp; - eccA = _eccFTable[eccA]; - } - - eccA = _eccBTable[_eccFTable[eccA] ^ eccB]; - ecc[major + eccOffset] = eccA; - ecc[major + majorCount + eccOffset] = (byte)(eccA ^ eccB); + eccA ^= temp; + eccB ^= temp; + eccA = _eccFTable[eccA]; } + + eccA = _eccBTable[_eccFTable[eccA] ^ eccB]; + ecc[major + eccOffset] = eccA; + ecc[major + majorCount + eccOffset] = (byte)(eccA ^ eccB); } } } \ No newline at end of file diff --git a/CD/Session.cs b/CD/Session.cs index d8e1dc3..88c7607 100644 --- a/CD/Session.cs +++ b/CD/Session.cs @@ -35,189 +35,188 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Session { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Session + public static CDSessionInfo? Decode(byte[] CDSessionInfoResponse) { - public static CDSessionInfo? Decode(byte[] CDSessionInfoResponse) + if(CDSessionInfoResponse == null || + CDSessionInfoResponse.Length <= 4) + return null; + + var decoded = new CDSessionInfo { - if(CDSessionInfoResponse == null || - CDSessionInfoResponse.Length <= 4) - return null; + DataLength = BigEndianBitConverter.ToUInt16(CDSessionInfoResponse, 0), + FirstCompleteSession = CDSessionInfoResponse[2], + LastCompleteSession = CDSessionInfoResponse[3] + }; - var decoded = new CDSessionInfo - { - DataLength = BigEndianBitConverter.ToUInt16(CDSessionInfoResponse, 0), - FirstCompleteSession = CDSessionInfoResponse[2], - LastCompleteSession = CDSessionInfoResponse[3] - }; + decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 8]; - decoded.TrackDescriptors = new TrackDataDescriptor[(decoded.DataLength - 2) / 8]; + if(decoded.DataLength + 2 != CDSessionInfoResponse.Length) + { + AaruConsole.DebugWriteLine("CD Session Info decoder", + "Expected CDSessionInfo size ({0} bytes) is not received size ({1} bytes), not decoding", + decoded.DataLength + 2, CDSessionInfoResponse.Length); - if(decoded.DataLength + 2 != CDSessionInfoResponse.Length) - { - AaruConsole.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; - } - - for(int i = 0; i < (decoded.DataLength - 2) / 8; i++) - { - decoded.TrackDescriptors[i].Reserved1 = CDSessionInfoResponse[0 + (i * 8) + 4]; - decoded.TrackDescriptors[i].ADR = (byte)((CDSessionInfoResponse[1 + (i * 8) + 4] & 0xF0) >> 4); - 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); - } - - return decoded; + return null; } - public static string Prettify(CDSessionInfo? CDSessionInfoResponse) + for(int i = 0; i < (decoded.DataLength - 2) / 8; i++) { - if(CDSessionInfoResponse == null) - return null; + decoded.TrackDescriptors[i].Reserved1 = CDSessionInfoResponse[0 + (i * 8) + 4]; + decoded.TrackDescriptors[i].ADR = (byte)((CDSessionInfoResponse[1 + (i * 8) + 4] & 0xF0) >> 4); + 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]; - CDSessionInfo response = CDSessionInfoResponse.Value; + decoded.TrackDescriptors[i].TrackStartAddress = + BigEndianBitConverter.ToUInt32(CDSessionInfoResponse, 4 + (i * 8) + 4); + } - var sb = new StringBuilder(); + return decoded; + } - sb.AppendFormat("First complete session number: {0}", response.FirstCompleteSession).AppendLine(); - sb.AppendFormat("Last complete session number: {0}", response.LastCompleteSession).AppendLine(); + public static string Prettify(CDSessionInfo? CDSessionInfoResponse) + { + if(CDSessionInfoResponse == null) + return null; - foreach(TrackDataDescriptor descriptor in response.TrackDescriptors) + CDSessionInfo response = CDSessionInfoResponse.Value; + + 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("Track starts at LBA {0}, or MSF {1:X2}:{2:X2}:{3:X2}", descriptor.TrackStartAddress, + (descriptor.TrackStartAddress & 0x0000FF00) >> 8, + (descriptor.TrackStartAddress & 0x00FF0000) >> 16, + (descriptor.TrackStartAddress & 0xFF000000) >> 24).AppendLine(); + + switch((TocAdr)descriptor.ADR) { - sb.AppendFormat("First track number in last complete session: {0}", descriptor.TrackNumber). - AppendLine(); + case TocAdr.NoInformation: + sb.AppendLine("Q subchannel mode not given"); - 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, - (descriptor.TrackStartAddress & 0xFF000000) >> 24).AppendLine(); + break; + case TocAdr.CurrentPosition: + sb.AppendLine("Q subchannel stores current position"); - switch((TocAdr)descriptor.ADR) + break; + case TocAdr.ISRC: + sb.AppendLine("Q subchannel stores ISRC"); + + break; + case TocAdr.MediaCatalogNumber: + sb.AppendLine("Q subchannel stores media catalog number"); + + break; + } + + if((descriptor.CONTROL & (byte)TocControl.ReservedMask) == (byte)TocControl.ReservedMask) + sb.AppendFormat("Reserved flags 0x{0:X2} set", descriptor.CONTROL).AppendLine(); + else + { + switch((TocControl)(descriptor.CONTROL & 0x0D)) { - case TocAdr.NoInformation: - sb.AppendLine("Q subchannel mode not given"); + case TocControl.TwoChanNoPreEmph: + sb.AppendLine("Stereo audio track with no pre-emphasis"); break; - case TocAdr.CurrentPosition: - sb.AppendLine("Q subchannel stores current position"); + case TocControl.TwoChanPreEmph: + sb.AppendLine("Stereo audio track with 50/15 μs pre-emphasis"); break; - case TocAdr.ISRC: - sb.AppendLine("Q subchannel stores ISRC"); + case TocControl.FourChanNoPreEmph: + sb.AppendLine("Quadraphonic audio track with no pre-emphasis"); break; - case TocAdr.MediaCatalogNumber: - sb.AppendLine("Q subchannel stores media catalog number"); + 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; } - if((descriptor.CONTROL & (byte)TocControl.ReservedMask) == (byte)TocControl.ReservedMask) - sb.AppendFormat("Reserved flags 0x{0:X2} set", descriptor.CONTROL).AppendLine(); - else - { - switch((TocControl)(descriptor.CONTROL & 0x0D)) - { - case TocControl.TwoChanNoPreEmph: - sb.AppendLine("Stereo audio track with no pre-emphasis"); + sb.AppendLine((descriptor.CONTROL & (byte)TocControl.CopyPermissionMask) == + (byte)TocControl.CopyPermissionMask ? "Digital copy of track is permitted" + : "Digital copy of track is prohibited"); - break; - case TocControl.TwoChanPreEmph: - sb.AppendLine("Stereo audio track with 50/15 μs pre-emphasis"); + #if DEBUG + if(descriptor.Reserved1 != 0) + sb.AppendFormat("Reserved1 = 0x{0:X2}", descriptor.Reserved1).AppendLine(); - break; - case TocControl.FourChanNoPreEmph: - sb.AppendLine("Quadraphonic audio track with no pre-emphasis"); + if(descriptor.Reserved2 != 0) + sb.AppendFormat("Reserved2 = 0x{0:X2}", descriptor.Reserved2).AppendLine(); + #endif - 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" - : "Digital copy of track is prohibited"); - - #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 - - sb.AppendLine(); - } + sb.AppendLine(); } - - return sb.ToString(); } - public static string Prettify(byte[] CDSessionInfoResponse) - { - CDSessionInfo? decoded = Decode(CDSessionInfoResponse); + return sb.ToString(); + } - return Prettify(decoded); - } + public static string Prettify(byte[] CDSessionInfoResponse) + { + CDSessionInfo? decoded = Decode(CDSessionInfoResponse); - public struct CDSessionInfo - { - /// Total size of returned session information minus this field - public ushort DataLength; - /// First track number in hex - public byte FirstCompleteSession; - /// Last track number in hex - public byte LastCompleteSession; - /// Track descriptors - public TrackDataDescriptor[] TrackDescriptors; - } + return Prettify(decoded); + } - public struct TrackDataDescriptor - { - /// Byte 0 Reserved - public byte Reserved1; - /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found - public byte ADR; - /// Byte 1, bits 3 to 0 Track attributes - public byte CONTROL; - /// Byte 2 First track number in last complete session - public byte TrackNumber; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 7 First track number in last complete session start address in LBA or in MSF - public uint TrackStartAddress; - } + public struct CDSessionInfo + { + /// Total size of returned session information minus this field + public ushort DataLength; + /// First track number in hex + public byte FirstCompleteSession; + /// Last track number in hex + public byte LastCompleteSession; + /// Track descriptors + public TrackDataDescriptor[] TrackDescriptors; + } + + public struct TrackDataDescriptor + { + /// Byte 0 Reserved + public byte Reserved1; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 First track number in last complete session + public byte TrackNumber; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 First track number in last complete session start address in LBA or in MSF + public uint TrackStartAddress; } } \ No newline at end of file diff --git a/CD/Subchannel.cs b/CD/Subchannel.cs index b04aa34..10ab868 100644 --- a/CD/Subchannel.cs +++ b/CD/Subchannel.cs @@ -29,548 +29,30 @@ using System; using Aaru.Checksums; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +public static class Subchannel { - public static class Subchannel + static readonly string[] _isrcTable = { - static readonly string[] _isrcTable = + // 0x00 + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "", "", "", "", "", + + // 0x10 + "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + + // 0x20 + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "", "", "", "", "", + + // 0x30 + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" + }; + + public static void BinaryToBcdQ(byte[] q) + { + if((q[0] & 0xF) == 1 || + (q[0] & 0xF) == 5) { - // 0x00 - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "", "", "", "", "", - - // 0x10 - "", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", - - // 0x20 - "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "", "", "", "", "", - - // 0x30 - "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" - }; - - public static void BinaryToBcdQ(byte[] q) - { - if((q[0] & 0xF) == 1 || - (q[0] & 0xF) == 5) - { - q[1] = (byte)(((q[1] / 10) << 4) + (q[1] % 10)); - q[2] = (byte)(((q[2] / 10) << 4) + (q[2] % 10)); - q[3] = (byte)(((q[3] / 10) << 4) + (q[3] % 10)); - q[4] = (byte)(((q[4] / 10) << 4) + (q[4] % 10)); - q[5] = (byte)(((q[5] / 10) << 4) + (q[5] % 10)); - q[6] = (byte)(((q[6] / 10) << 4) + (q[6] % 10)); - q[7] = (byte)(((q[7] / 10) << 4) + (q[7] % 10)); - q[8] = (byte)(((q[8] / 10) << 4) + (q[8] % 10)); - } - - q[9] = (byte)(((q[9] / 10) << 4) + (q[9] % 10)); - } - - public static void BcdToBinaryQ(byte[] q) - { - if((q[0] & 0xF) == 1 || - (q[0] & 0xF) == 5) - { - q[1] = (byte)((q[1] / 16 * 10) + (q[1] & 0x0F)); - q[2] = (byte)((q[2] / 16 * 10) + (q[2] & 0x0F)); - q[3] = (byte)((q[3] / 16 * 10) + (q[3] & 0x0F)); - q[4] = (byte)((q[4] / 16 * 10) + (q[4] & 0x0F)); - q[5] = (byte)((q[5] / 16 * 10) + (q[5] & 0x0F)); - q[6] = (byte)((q[6] / 16 * 10) + (q[6] & 0x0F)); - q[7] = (byte)((q[7] / 16 * 10) + (q[7] & 0x0F)); - q[8] = (byte)((q[8] / 16 * 10) + (q[8] & 0x0F)); - } - - q[9] = (byte)((q[9] / 16 * 10) + (q[9] & 0x0F)); - } - - public static byte[] ConvertQToRaw(byte[] subchannel) - { - int pos = 0; - byte[] subBuf = new byte[subchannel.Length * 6]; - - for(int i = 0; i < subchannel.Length; i += 16) - { - // P - if((subchannel[i + 15] & 0x80) <= 0) - { - pos += 12; - } - else - { - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - subBuf[pos++] = 0xFF; - } - - // Q - subBuf[pos++] = subchannel[i + 0]; - subBuf[pos++] = subchannel[i + 1]; - subBuf[pos++] = subchannel[i + 2]; - subBuf[pos++] = subchannel[i + 3]; - subBuf[pos++] = subchannel[i + 4]; - subBuf[pos++] = subchannel[i + 5]; - subBuf[pos++] = subchannel[i + 6]; - subBuf[pos++] = subchannel[i + 7]; - subBuf[pos++] = subchannel[i + 8]; - subBuf[pos++] = subchannel[i + 9]; - subBuf[pos++] = subchannel[i + 10]; - subBuf[pos++] = subchannel[i + 11]; - - // R to W - pos += 72; - } - - return Interleave(subBuf); - } - - public static byte[] Interleave(byte[] subchannel) - { - byte[] subBuf = new byte[subchannel.Length]; - - int outPos = 0; - - for(int inPos = 0; inPos < subchannel.Length; inPos += 96) - { - for(int i = 0; i < 12; i++) - { - // P - subBuf[outPos + 0] += (byte)(subchannel[inPos + i + 0] & 0x80); - subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 0] & 0x40) << 1); - subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 0] & 0x20) << 2); - subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 0] & 0x10) << 3); - subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 0] & 0x08) << 4); - subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 0] & 0x04) << 5); - subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 0] & 0x02) << 6); - subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 0] & 0x01) << 7); - - // Q - subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 12] & 0x80) >> 1); - subBuf[outPos + 1] += (byte)(subchannel[inPos + i + 12] & 0x40); - subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 12] & 0x20) << 1); - subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 12] & 0x10) << 2); - subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 12] & 0x08) << 3); - subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 12] & 0x04) << 4); - subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 12] & 0x02) << 5); - subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 12] & 0x01) << 6); - - // R - subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 24] & 0x80) >> 2); - subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 24] & 0x40) >> 1); - subBuf[outPos + 2] += (byte)(subchannel[inPos + i + 24] & 0x20); - subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 24] & 0x10) << 1); - subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 24] & 0x08) << 2); - subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 24] & 0x04) << 3); - subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 24] & 0x02) << 4); - subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 24] & 0x01) << 5); - - // S - subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 36] & 0x80) >> 3); - subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 36] & 0x40) >> 2); - subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 36] & 0x20) >> 1); - subBuf[outPos + 3] += (byte)(subchannel[inPos + i + 36] & 0x10); - subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 36] & 0x08) << 1); - subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 36] & 0x04) << 2); - subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 36] & 0x02) << 3); - subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 36] & 0x01) << 4); - - // T - subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 48] & 0x80) >> 4); - subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 48] & 0x40) >> 3); - subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 48] & 0x20) >> 2); - subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 48] & 0x10) >> 1); - subBuf[outPos + 4] += (byte)(subchannel[inPos + i + 48] & 0x08); - subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 48] & 0x04) << 1); - subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 48] & 0x02) << 2); - subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 48] & 0x01) << 3); - - // U - subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 60] & 0x80) >> 5); - subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 60] & 0x40) >> 4); - subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 60] & 0x20) >> 3); - subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 60] & 0x10) >> 2); - subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 60] & 0x08) >> 1); - subBuf[outPos + 5] += (byte)(subchannel[inPos + i + 60] & 0x04); - subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 60] & 0x02) << 1); - subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 60] & 0x01) << 2); - - // V - subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 72] & 0x80) >> 6); - subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 72] & 0x40) >> 5); - subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 72] & 0x20) >> 4); - subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 72] & 0x10) >> 3); - subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 72] & 0x08) >> 2); - subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 72] & 0x04) >> 1); - subBuf[outPos + 6] += (byte)(subchannel[inPos + i + 72] & 0x02); - subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 72] & 0x01) << 1); - - // W - subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 84] & 0x80) >> 7); - subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 84] & 0x40) >> 6); - subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 84] & 0x20) >> 5); - subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 84] & 0x10) >> 4); - subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 84] & 0x08) >> 3); - subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 84] & 0x04) >> 2); - subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 84] & 0x02) >> 1); - subBuf[outPos + 7] += (byte)(subchannel[inPos + i + 84] & 0x01); - outPos += 8; - } - } - - return subBuf; - } - - public static byte[] Deinterleave(byte[] subchannel) - { - byte[] subBuf = new byte[subchannel.Length]; - int inPos = 0; - - for(int outPos = 0; outPos < subchannel.Length; outPos += 96) - { - for(int i = 0; i < 12; i++) - { - // P - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 0] & 0x80) >> 0); - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 1] & 0x80) >> 1); - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 2] & 0x80) >> 2); - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 3] & 0x80) >> 3); - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 4] & 0x80) >> 4); - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 5] & 0x80) >> 5); - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 6] & 0x80) >> 6); - subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 7] & 0x80) >> 7); - - // Q - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 0] & 0x40) << 1); - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 1] & 0x40) >> 0); - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 2] & 0x40) >> 1); - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 3] & 0x40) >> 2); - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 4] & 0x40) >> 3); - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 5] & 0x40) >> 4); - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 6] & 0x40) >> 5); - subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 7] & 0x40) >> 6); - - // R - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 0] & 0x20) << 2); - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 1] & 0x20) << 1); - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 2] & 0x20) >> 0); - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 3] & 0x20) >> 1); - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 4] & 0x20) >> 2); - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 5] & 0x20) >> 3); - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 6] & 0x20) >> 4); - subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 7] & 0x20) >> 5); - - // S - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 0] & 0x10) << 3); - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 1] & 0x10) << 2); - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 2] & 0x10) << 1); - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 3] & 0x10) >> 0); - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 4] & 0x10) >> 1); - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 5] & 0x10) >> 2); - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 6] & 0x10) >> 3); - subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 7] & 0x10) >> 4); - - // T - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 0] & 0x8) << 4); - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 1] & 0x8) << 3); - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 2] & 0x8) << 2); - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 3] & 0x8) << 1); - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 4] & 0x8) >> 0); - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 5] & 0x8) >> 1); - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 6] & 0x8) >> 2); - subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 7] & 0x8) >> 3); - - // U - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 0] & 0x4) << 5); - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 1] & 0x4) << 4); - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 2] & 0x4) << 3); - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 3] & 0x4) << 2); - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 4] & 0x4) << 1); - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 5] & 0x4) >> 0); - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 6] & 0x4) >> 1); - subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 7] & 0x4) >> 2); - - // V - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 0] & 0x2) << 6); - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 1] & 0x2) << 5); - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 2] & 0x2) << 4); - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 3] & 0x2) << 3); - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 4] & 0x2) << 2); - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 5] & 0x2) << 1); - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 6] & 0x2) >> 0); - subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 7] & 0x2) >> 1); - - // W - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 0] & 0x1) << 7); - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 1] & 0x1) << 6); - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 2] & 0x1) << 5); - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 3] & 0x1) << 4); - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 4] & 0x1) << 3); - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 5] & 0x1) << 2); - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 6] & 0x1) << 1); - subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 7] & 0x1) >> 0); - - inPos += 8; - } - } - - return subBuf; - } - - public static string PrettifyQ(byte[] subBuf, bool bcd, long lba, bool corruptedPause, bool pause, bool rwEmpty) - { - CRC16CCITTContext.Data(subBuf, 10, out byte[] crc); - - bool crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11]; - long minute = (lba + 150) / 4500; - long second = (lba + 150) % 4500 / 75; - long frame = (lba + 150) % 4500 % 75; - string area; - int control = (subBuf[0] & 0xF0) / 16; - int adr = subBuf[0] & 0x0F; - - string controlInfo = ((control & 0xC) / 4) switch - { - 0 => $"stereo audio {((control & 0x01) == 1 ? "with" : "without")} pre-emphasis", - 1 => $"{((control & 0x01) == 1 ? "incremental" : "uninterrupted")} data", - 2 => $"quadraphonic audio {((control & 0x01) == 1 ? "with" : "without")} pre-emphasis", - _ => $"reserved control value {control & 0x01}" - }; - - string copy = (control & 0x02) > 0 ? "copy permitted" : "copy prohibited"; - - if(bcd) - BcdToBinaryQ(subBuf); - - int qPos = (subBuf[3] * 60 * 75) + (subBuf[4] * 75) + subBuf[5] - 150; - byte pmin = subBuf[7]; - byte psec = subBuf[8]; - - int qStart = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150; - int nextPos = (subBuf[3] * 60 * 75) + (subBuf[4] * 75) + subBuf[5] - 150; - byte zero = subBuf[6]; - int maxOut = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150; - bool final = subBuf[3] == 0xFF && subBuf[4] == 0xFF && subBuf[5] == 0xFF; - - BinaryToBcdQ(subBuf); - - if(lba < 0) - { - area = "Lead-In"; - - switch(adr) - { - case 1 when subBuf[2] < 0xA0: - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} starts at {subBuf[7]:X2}:{subBuf[8]:X2}:{subBuf[9]:X2} (LBA {qStart}), Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - case 1 when subBuf[2] == 0xA0: - { - string format = subBuf[8] switch - { - 0x00 => "CD-DA / CD-ROM", - 0x10 => "CD-i", - 0x20 => "CD-ROM XA", - _ => $"unknown {subBuf[0]:X2}" - }; - - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} is first program area track in {format} format, Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - } - case 1 when subBuf[2] == 0xA1: - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} is last program area track, Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - case 1: - return subBuf[2] == 0xA2 - ? $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} starts at {subBuf[7]:X2}{subBuf[8]:X2}{subBuf[9]:X2} (LBA {qStart}), Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" - : $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - case 2: - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} MCN: {DecodeMcn(subBuf)} frame {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - } - - if(adr != 5) - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - - if(subBuf[2] <= 0x40) - { - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} skip interval start time {subBuf[7]:X2}{subBuf[8]:X2}{subBuf[9]:X2}, skip interval stop time {subBuf[3]:X2}{subBuf[4]:X2}{subBuf[5]:X2}, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - } - - if(subBuf[2] == 0xB0) - { - return final - ? $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} next program area can start at {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {nextPos}), last-session, {zero} mode 5 pointers, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" - : $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} next program area can start at {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {nextPos}), maximum Lead-out at {subBuf[7]:X2}:{subBuf[8]:X2}:{subBuf[9]:X2} (LBA {maxOut}), {zero} mode 5 pointers, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - } - - if(subBuf[2] == 0xB1) - { - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr}, {pmin} skip interval pointers, {psec} skip track assignments, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - } - - if(subBuf[2] != 0xB2 && - subBuf[2] != 0xB3 && - subBuf[2] != 0xB4) - return subBuf[2] == 0xC0 - ? $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr}, ATIP values {subBuf[3]:X2}, {subBuf[4]:X2}, {subBuf[5]:X2}, first disc Lead-in starts at {subBuf[7]:X2}{subBuf[8]:X2}{subBuf[9]:X2} (LBA {qStart}), CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" - : $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - - string skipTracks = $"{subBuf[3]:X2}"; - - if(subBuf[4] > 0) - skipTracks += $", {subBuf[4]:X2}"; - - if(subBuf[5] > 0) - skipTracks += $", {subBuf[4]:X2}"; - - if(subBuf[7] > 0) - skipTracks += $", {subBuf[4]:X2}"; - - if(subBuf[8] > 0) - skipTracks += $", {subBuf[4]:X2}"; - - if(subBuf[9] > 0) - skipTracks += $", {subBuf[4]:X2}"; - - return - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr}, tracks {skipTracks} to be skipped, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; - } - - area = subBuf[1] == 0xAA ? "Lead-out" : "Program"; - - return adr switch - { - 1 => - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: track {subBuf[1]:X} index {subBuf[2]:X} relative position {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos + 150}), absolute position {subBuf[7]:X2}:{subBuf[8]:X2}:{subBuf[9]:X2} (LBA {qStart}), Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}", - 2 => - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} MCN: {DecodeMcn(subBuf)} frame {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}", - 3 => - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} ISRC: {DecodeIsrc(subBuf)} frame {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}", - _ => - $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" - }; - } - - public static string DecodeIsrc(byte[] q) => - $"{_isrcTable[q[1] / 4]}{_isrcTable[((q[1] & 3) * 16) + (q[2] / 16)]}{_isrcTable[((q[2] & 0xF) * 4) + (q[3] / 64)]}{_isrcTable[q[3] & 0x3F]}{_isrcTable[q[4] / 4]}{q[5]:X2}{q[6]:X2}{q[7]:X2}{q[8] / 16:X1}"; - - public static string DecodeMcn(byte[] q) => - $"{q[1]:X2}{q[2]:X2}{q[3]:X2}{q[4]:X2}{q[5]:X2}{q[6]:X2}{q[7] >> 4:X}"; - - public static byte GetIsrcCode(char c) - { - switch(c) - { - case '0': return 0x00; - case '1': return 0x01; - case '2': return 0x02; - case '3': return 0x03; - case '4': return 0x04; - case '5': return 0x05; - case '6': return 0x06; - case '7': return 0x07; - case '8': return 0x08; - case '9': return 0x09; - case 'A': return 0x11; - case 'B': return 0x12; - case 'C': return 0x13; - case 'D': return 0x14; - case 'E': return 0x15; - case 'F': return 0x16; - case 'G': return 0x17; - case 'H': return 0x18; - case 'I': return 0x19; - case 'J': return 0x1A; - case 'K': return 0x1B; - case 'L': return 0x1C; - case 'M': return 0x1D; - case 'N': return 0x1E; - case 'O': return 0x1F; - case 'P': return 0x20; - case 'Q': return 0x21; - case 'R': return 0x22; - case 'S': return 0x23; - case 'T': return 0x24; - case 'U': return 0x25; - case 'V': return 0x26; - case 'W': return 0x27; - case 'X': return 0x28; - case 'Y': return 0x29; - case 'Z': return 0x2A; - default: return 0x00; - } - } - - public static byte[] Generate(int sector, uint trackSequence, int pregap, int trackStart, byte flags, - byte index) - { - bool isPregap = sector < 0 || sector <= trackStart + pregap; - - if(index == 0) - index = (byte)(isPregap ? 0 : 1); - - byte[] sub = new byte[96]; - - // P - if(isPregap) - { - sub[0] = 0xFF; - sub[1] = 0xFF; - sub[2] = 0xFF; - sub[3] = 0xFF; - sub[4] = 0xFF; - sub[5] = 0xFF; - sub[6] = 0xFF; - sub[7] = 0xFF; - sub[8] = 0xFF; - sub[9] = 0xFF; - sub[10] = 0xFF; - sub[11] = 0xFF; - } - - // Q - byte[] q = new byte[12]; - - q[0] = (byte)((flags << 4) + 1); - q[1] = (byte)trackSequence; - q[2] = index; - - int relative; - - if(isPregap) - relative = pregap + trackStart - sector; - else - relative = sector - trackStart; - - sector += 150; - - int min = relative / 60 / 75; - int sec = (relative / 75) - (min * 60); - int frame = relative - (min * 60 * 75) - (sec * 75); - - int amin = sector / 60 / 75; - int asec = (sector / 75) - (amin * 60); - int aframe = sector - (amin * 60 * 75) - (asec * 75); - - q[3] = (byte)min; - q[4] = (byte)sec; - q[5] = (byte)frame; - - q[7] = (byte)amin; - q[8] = (byte)asec; - q[9] = (byte)aframe; - q[1] = (byte)(((q[1] / 10) << 4) + (q[1] % 10)); q[2] = (byte)(((q[2] / 10) << 4) + (q[2] % 10)); q[3] = (byte)(((q[3] / 10) << 4) + (q[3] % 10)); @@ -579,16 +61,533 @@ namespace Aaru.Decoders.CD q[6] = (byte)(((q[6] / 10) << 4) + (q[6] % 10)); q[7] = (byte)(((q[7] / 10) << 4) + (q[7] % 10)); q[8] = (byte)(((q[8] / 10) << 4) + (q[8] % 10)); + } - q[9] = (byte)(((q[9] / 10) << 4) + (q[9] % 10)); + q[9] = (byte)(((q[9] / 10) << 4) + (q[9] % 10)); + } - CRC16CCITTContext.Data(q, 10, out byte[] qCrc); - q[10] = qCrc[0]; - q[11] = qCrc[1]; + public static void BcdToBinaryQ(byte[] q) + { + if((q[0] & 0xF) == 1 || + (q[0] & 0xF) == 5) + { + q[1] = (byte)((q[1] / 16 * 10) + (q[1] & 0x0F)); + q[2] = (byte)((q[2] / 16 * 10) + (q[2] & 0x0F)); + q[3] = (byte)((q[3] / 16 * 10) + (q[3] & 0x0F)); + q[4] = (byte)((q[4] / 16 * 10) + (q[4] & 0x0F)); + q[5] = (byte)((q[5] / 16 * 10) + (q[5] & 0x0F)); + q[6] = (byte)((q[6] / 16 * 10) + (q[6] & 0x0F)); + q[7] = (byte)((q[7] / 16 * 10) + (q[7] & 0x0F)); + q[8] = (byte)((q[8] / 16 * 10) + (q[8] & 0x0F)); + } - Array.Copy(q, 0, sub, 12, 12); + q[9] = (byte)((q[9] / 16 * 10) + (q[9] & 0x0F)); + } - return Interleave(sub); + public static byte[] ConvertQToRaw(byte[] subchannel) + { + int pos = 0; + byte[] subBuf = new byte[subchannel.Length * 6]; + + for(int i = 0; i < subchannel.Length; i += 16) + { + // P + if((subchannel[i + 15] & 0x80) <= 0) + { + pos += 12; + } + else + { + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + subBuf[pos++] = 0xFF; + } + + // Q + subBuf[pos++] = subchannel[i + 0]; + subBuf[pos++] = subchannel[i + 1]; + subBuf[pos++] = subchannel[i + 2]; + subBuf[pos++] = subchannel[i + 3]; + subBuf[pos++] = subchannel[i + 4]; + subBuf[pos++] = subchannel[i + 5]; + subBuf[pos++] = subchannel[i + 6]; + subBuf[pos++] = subchannel[i + 7]; + subBuf[pos++] = subchannel[i + 8]; + subBuf[pos++] = subchannel[i + 9]; + subBuf[pos++] = subchannel[i + 10]; + subBuf[pos++] = subchannel[i + 11]; + + // R to W + pos += 72; + } + + return Interleave(subBuf); + } + + public static byte[] Interleave(byte[] subchannel) + { + byte[] subBuf = new byte[subchannel.Length]; + + int outPos = 0; + + for(int inPos = 0; inPos < subchannel.Length; inPos += 96) + { + for(int i = 0; i < 12; i++) + { + // P + subBuf[outPos + 0] += (byte)(subchannel[inPos + i + 0] & 0x80); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 0] & 0x40) << 1); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 0] & 0x20) << 2); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 0] & 0x10) << 3); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 0] & 0x08) << 4); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 0] & 0x04) << 5); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 0] & 0x02) << 6); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 0] & 0x01) << 7); + + // Q + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 12] & 0x80) >> 1); + subBuf[outPos + 1] += (byte)(subchannel[inPos + i + 12] & 0x40); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 12] & 0x20) << 1); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 12] & 0x10) << 2); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 12] & 0x08) << 3); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 12] & 0x04) << 4); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 12] & 0x02) << 5); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 12] & 0x01) << 6); + + // R + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 24] & 0x80) >> 2); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 24] & 0x40) >> 1); + subBuf[outPos + 2] += (byte)(subchannel[inPos + i + 24] & 0x20); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 24] & 0x10) << 1); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 24] & 0x08) << 2); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 24] & 0x04) << 3); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 24] & 0x02) << 4); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 24] & 0x01) << 5); + + // S + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 36] & 0x80) >> 3); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 36] & 0x40) >> 2); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 36] & 0x20) >> 1); + subBuf[outPos + 3] += (byte)(subchannel[inPos + i + 36] & 0x10); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 36] & 0x08) << 1); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 36] & 0x04) << 2); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 36] & 0x02) << 3); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 36] & 0x01) << 4); + + // T + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 48] & 0x80) >> 4); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 48] & 0x40) >> 3); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 48] & 0x20) >> 2); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 48] & 0x10) >> 1); + subBuf[outPos + 4] += (byte)(subchannel[inPos + i + 48] & 0x08); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 48] & 0x04) << 1); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 48] & 0x02) << 2); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 48] & 0x01) << 3); + + // U + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 60] & 0x80) >> 5); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 60] & 0x40) >> 4); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 60] & 0x20) >> 3); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 60] & 0x10) >> 2); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 60] & 0x08) >> 1); + subBuf[outPos + 5] += (byte)(subchannel[inPos + i + 60] & 0x04); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 60] & 0x02) << 1); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 60] & 0x01) << 2); + + // V + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 72] & 0x80) >> 6); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 72] & 0x40) >> 5); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 72] & 0x20) >> 4); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 72] & 0x10) >> 3); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 72] & 0x08) >> 2); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 72] & 0x04) >> 1); + subBuf[outPos + 6] += (byte)(subchannel[inPos + i + 72] & 0x02); + subBuf[outPos + 7] += (byte)((subchannel[inPos + i + 72] & 0x01) << 1); + + // W + subBuf[outPos + 0] += (byte)((subchannel[inPos + i + 84] & 0x80) >> 7); + subBuf[outPos + 1] += (byte)((subchannel[inPos + i + 84] & 0x40) >> 6); + subBuf[outPos + 2] += (byte)((subchannel[inPos + i + 84] & 0x20) >> 5); + subBuf[outPos + 3] += (byte)((subchannel[inPos + i + 84] & 0x10) >> 4); + subBuf[outPos + 4] += (byte)((subchannel[inPos + i + 84] & 0x08) >> 3); + subBuf[outPos + 5] += (byte)((subchannel[inPos + i + 84] & 0x04) >> 2); + subBuf[outPos + 6] += (byte)((subchannel[inPos + i + 84] & 0x02) >> 1); + subBuf[outPos + 7] += (byte)(subchannel[inPos + i + 84] & 0x01); + outPos += 8; + } + } + + return subBuf; + } + + public static byte[] Deinterleave(byte[] subchannel) + { + byte[] subBuf = new byte[subchannel.Length]; + int inPos = 0; + + for(int outPos = 0; outPos < subchannel.Length; outPos += 96) + { + for(int i = 0; i < 12; i++) + { + // P + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 0] & 0x80) >> 0); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 1] & 0x80) >> 1); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 2] & 0x80) >> 2); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 3] & 0x80) >> 3); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 4] & 0x80) >> 4); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 5] & 0x80) >> 5); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 6] & 0x80) >> 6); + subBuf[outPos + i + 0] += (byte)((subchannel[inPos + 7] & 0x80) >> 7); + + // Q + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 0] & 0x40) << 1); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 1] & 0x40) >> 0); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 2] & 0x40) >> 1); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 3] & 0x40) >> 2); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 4] & 0x40) >> 3); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 5] & 0x40) >> 4); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 6] & 0x40) >> 5); + subBuf[outPos + i + 12] += (byte)((subchannel[inPos + 7] & 0x40) >> 6); + + // R + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 0] & 0x20) << 2); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 1] & 0x20) << 1); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 2] & 0x20) >> 0); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 3] & 0x20) >> 1); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 4] & 0x20) >> 2); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 5] & 0x20) >> 3); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 6] & 0x20) >> 4); + subBuf[outPos + i + 24] += (byte)((subchannel[inPos + 7] & 0x20) >> 5); + + // S + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 0] & 0x10) << 3); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 1] & 0x10) << 2); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 2] & 0x10) << 1); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 3] & 0x10) >> 0); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 4] & 0x10) >> 1); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 5] & 0x10) >> 2); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 6] & 0x10) >> 3); + subBuf[outPos + i + 36] += (byte)((subchannel[inPos + 7] & 0x10) >> 4); + + // T + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 0] & 0x8) << 4); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 1] & 0x8) << 3); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 2] & 0x8) << 2); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 3] & 0x8) << 1); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 4] & 0x8) >> 0); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 5] & 0x8) >> 1); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 6] & 0x8) >> 2); + subBuf[outPos + i + 48] += (byte)((subchannel[inPos + 7] & 0x8) >> 3); + + // U + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 0] & 0x4) << 5); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 1] & 0x4) << 4); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 2] & 0x4) << 3); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 3] & 0x4) << 2); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 4] & 0x4) << 1); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 5] & 0x4) >> 0); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 6] & 0x4) >> 1); + subBuf[outPos + i + 60] += (byte)((subchannel[inPos + 7] & 0x4) >> 2); + + // V + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 0] & 0x2) << 6); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 1] & 0x2) << 5); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 2] & 0x2) << 4); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 3] & 0x2) << 3); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 4] & 0x2) << 2); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 5] & 0x2) << 1); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 6] & 0x2) >> 0); + subBuf[outPos + i + 72] += (byte)((subchannel[inPos + 7] & 0x2) >> 1); + + // W + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 0] & 0x1) << 7); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 1] & 0x1) << 6); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 2] & 0x1) << 5); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 3] & 0x1) << 4); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 4] & 0x1) << 3); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 5] & 0x1) << 2); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 6] & 0x1) << 1); + subBuf[outPos + i + 84] += (byte)((subchannel[inPos + 7] & 0x1) >> 0); + + inPos += 8; + } + } + + return subBuf; + } + + public static string PrettifyQ(byte[] subBuf, bool bcd, long lba, bool corruptedPause, bool pause, bool rwEmpty) + { + CRC16CCITTContext.Data(subBuf, 10, out byte[] crc); + + bool crcOk = crc[0] == subBuf[10] && crc[1] == subBuf[11]; + long minute = (lba + 150) / 4500; + long second = (lba + 150) % 4500 / 75; + long frame = (lba + 150) % 4500 % 75; + string area; + int control = (subBuf[0] & 0xF0) / 16; + int adr = subBuf[0] & 0x0F; + + string controlInfo = ((control & 0xC) / 4) switch + { + 0 => $"stereo audio {((control & 0x01) == 1 ? "with" : "without")} pre-emphasis", + 1 => $"{((control & 0x01) == 1 ? "incremental" : "uninterrupted")} data", + 2 => $"quadraphonic audio {((control & 0x01) == 1 ? "with" : "without")} pre-emphasis", + _ => $"reserved control value {control & 0x01}" + }; + + string copy = (control & 0x02) > 0 ? "copy permitted" : "copy prohibited"; + + if(bcd) + BcdToBinaryQ(subBuf); + + int qPos = (subBuf[3] * 60 * 75) + (subBuf[4] * 75) + subBuf[5] - 150; + byte pmin = subBuf[7]; + byte psec = subBuf[8]; + + int qStart = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150; + int nextPos = (subBuf[3] * 60 * 75) + (subBuf[4] * 75) + subBuf[5] - 150; + byte zero = subBuf[6]; + int maxOut = (subBuf[7] * 60 * 75) + (subBuf[8] * 75) + subBuf[9] - 150; + bool final = subBuf[3] == 0xFF && subBuf[4] == 0xFF && subBuf[5] == 0xFF; + + BinaryToBcdQ(subBuf); + + if(lba < 0) + { + area = "Lead-In"; + + switch(adr) + { + case 1 when subBuf[2] < 0xA0: + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} starts at {subBuf[7]:X2}:{subBuf[8]:X2}:{subBuf[9]:X2} (LBA {qStart}), Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + case 1 when subBuf[2] == 0xA0: + { + string format = subBuf[8] switch + { + 0x00 => "CD-DA / CD-ROM", + 0x10 => "CD-i", + 0x20 => "CD-ROM XA", + _ => $"unknown {subBuf[0]:X2}" + }; + + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} is first program area track in {format} format, Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + } + case 1 when subBuf[2] == 0xA1: + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} is last program area track, Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + case 1: + return subBuf[2] == 0xA2 + ? $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos}), track {subBuf[2]:X} starts at {subBuf[7]:X2}{subBuf[8]:X2}{subBuf[9]:X2} (LBA {qStart}), Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" + : $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + case 2: + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} MCN: {DecodeMcn(subBuf)} frame {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + } + + if(adr != 5) + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + + if(subBuf[2] <= 0x40) + { + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} skip interval start time {subBuf[7]:X2}{subBuf[8]:X2}{subBuf[9]:X2}, skip interval stop time {subBuf[3]:X2}{subBuf[4]:X2}{subBuf[5]:X2}, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + } + + if(subBuf[2] == 0xB0) + { + return final + ? $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} next program area can start at {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {nextPos}), last-session, {zero} mode 5 pointers, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" + : $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} next program area can start at {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {nextPos}), maximum Lead-out at {subBuf[7]:X2}:{subBuf[8]:X2}:{subBuf[9]:X2} (LBA {maxOut}), {zero} mode 5 pointers, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + } + + if(subBuf[2] == 0xB1) + { + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr}, {pmin} skip interval pointers, {psec} skip track assignments, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + } + + if(subBuf[2] != 0xB2 && + subBuf[2] != 0xB3 && + subBuf[2] != 0xB4) + return subBuf[2] == 0xC0 + ? $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr}, ATIP values {subBuf[3]:X2}, {subBuf[4]:X2}, {subBuf[5]:X2}, first disc Lead-in starts at {subBuf[7]:X2}{subBuf[8]:X2}{subBuf[9]:X2} (LBA {qStart}), CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" + : $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + + string skipTracks = $"{subBuf[3]:X2}"; + + if(subBuf[4] > 0) + skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[5] > 0) + skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[7] > 0) + skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[8] > 0) + skipTracks += $", {subBuf[4]:X2}"; + + if(subBuf[9] > 0) + skipTracks += $", {subBuf[4]:X2}"; + + return + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr}, tracks {skipTracks} to be skipped, CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}"; + } + + area = subBuf[1] == 0xAA ? "Lead-out" : "Program"; + + return adr switch + { + 1 => + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} position: track {subBuf[1]:X} index {subBuf[2]:X} relative position {subBuf[3]:X2}:{subBuf[4]:X2}:{subBuf[5]:X2} (LBA {qPos + 150}), absolute position {subBuf[7]:X2}:{subBuf[8]:X2}:{subBuf[9]:X2} (LBA {qStart}), Q CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}", + 2 => + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} MCN: {DecodeMcn(subBuf)} frame {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}", + 3 => + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q mode {adr} ISRC: {DecodeIsrc(subBuf)} frame {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}", + _ => + $"{minute:D2}:{second:D2}:{frame:D2} - LBA {lba,6}: {area} area, {(corruptedPause ? "corrupted pause" : pause ? "pause" : "not pause")}, {controlInfo}, {copy}, Q: {subBuf[0]:X2} {subBuf[1]:X2} {subBuf[2]:X2} {subBuf[3]:X2} {subBuf[4]:X2} {subBuf[5]:X2} {subBuf[6]:X2} {subBuf[7]:X2} {subBuf[8]:X2} {subBuf[9]:X2} CRC 0x{subBuf[10]:X2}{subBuf[11]:X2} ({(crcOk ? "OK" : "BAD")}), R-W {(rwEmpty ? "empty" : "not empty")}" + }; + } + + public static string DecodeIsrc(byte[] q) => + $"{_isrcTable[q[1] / 4]}{_isrcTable[((q[1] & 3) * 16) + (q[2] / 16)]}{_isrcTable[((q[2] & 0xF) * 4) + (q[3] / 64)]}{_isrcTable[q[3] & 0x3F]}{_isrcTable[q[4] / 4]}{q[5]:X2}{q[6]:X2}{q[7]:X2}{q[8] / 16:X1}"; + + public static string DecodeMcn(byte[] q) => + $"{q[1]:X2}{q[2]:X2}{q[3]:X2}{q[4]:X2}{q[5]:X2}{q[6]:X2}{q[7] >> 4:X}"; + + public static byte GetIsrcCode(char c) + { + switch(c) + { + case '0': return 0x00; + case '1': return 0x01; + case '2': return 0x02; + case '3': return 0x03; + case '4': return 0x04; + case '5': return 0x05; + case '6': return 0x06; + case '7': return 0x07; + case '8': return 0x08; + case '9': return 0x09; + case 'A': return 0x11; + case 'B': return 0x12; + case 'C': return 0x13; + case 'D': return 0x14; + case 'E': return 0x15; + case 'F': return 0x16; + case 'G': return 0x17; + case 'H': return 0x18; + case 'I': return 0x19; + case 'J': return 0x1A; + case 'K': return 0x1B; + case 'L': return 0x1C; + case 'M': return 0x1D; + case 'N': return 0x1E; + case 'O': return 0x1F; + case 'P': return 0x20; + case 'Q': return 0x21; + case 'R': return 0x22; + case 'S': return 0x23; + case 'T': return 0x24; + case 'U': return 0x25; + case 'V': return 0x26; + case 'W': return 0x27; + case 'X': return 0x28; + case 'Y': return 0x29; + case 'Z': return 0x2A; + default: return 0x00; } } + + public static byte[] Generate(int sector, uint trackSequence, int pregap, int trackStart, byte flags, + byte index) + { + bool isPregap = sector < 0 || sector <= trackStart + pregap; + + if(index == 0) + index = (byte)(isPregap ? 0 : 1); + + byte[] sub = new byte[96]; + + // P + if(isPregap) + { + sub[0] = 0xFF; + sub[1] = 0xFF; + sub[2] = 0xFF; + sub[3] = 0xFF; + sub[4] = 0xFF; + sub[5] = 0xFF; + sub[6] = 0xFF; + sub[7] = 0xFF; + sub[8] = 0xFF; + sub[9] = 0xFF; + sub[10] = 0xFF; + sub[11] = 0xFF; + } + + // Q + byte[] q = new byte[12]; + + q[0] = (byte)((flags << 4) + 1); + q[1] = (byte)trackSequence; + q[2] = index; + + int relative; + + if(isPregap) + relative = pregap + trackStart - sector; + else + relative = sector - trackStart; + + sector += 150; + + int min = relative / 60 / 75; + int sec = (relative / 75) - (min * 60); + int frame = relative - (min * 60 * 75) - (sec * 75); + + int amin = sector / 60 / 75; + int asec = (sector / 75) - (amin * 60); + int aframe = sector - (amin * 60 * 75) - (asec * 75); + + q[3] = (byte)min; + q[4] = (byte)sec; + q[5] = (byte)frame; + + q[7] = (byte)amin; + q[8] = (byte)asec; + q[9] = (byte)aframe; + + q[1] = (byte)(((q[1] / 10) << 4) + (q[1] % 10)); + q[2] = (byte)(((q[2] / 10) << 4) + (q[2] % 10)); + q[3] = (byte)(((q[3] / 10) << 4) + (q[3] % 10)); + q[4] = (byte)(((q[4] / 10) << 4) + (q[4] % 10)); + q[5] = (byte)(((q[5] / 10) << 4) + (q[5] % 10)); + q[6] = (byte)(((q[6] / 10) << 4) + (q[6] % 10)); + q[7] = (byte)(((q[7] / 10) << 4) + (q[7] % 10)); + q[8] = (byte)(((q[8] / 10) << 4) + (q[8] % 10)); + + q[9] = (byte)(((q[9] / 10) << 4) + (q[9] % 10)); + + CRC16CCITTContext.Data(q, 10, out byte[] qCrc); + q[10] = qCrc[0]; + q[11] = qCrc[1]; + + Array.Copy(q, 0, sub, 12, 12); + + return Interleave(sub); + } } \ No newline at end of file diff --git a/CD/TOC.cs b/CD/TOC.cs index 3d0e32d..41619da 100644 --- a/CD/TOC.cs +++ b/CD/TOC.cs @@ -35,202 +35,201 @@ using System.Text; using Aaru.Console; using Aaru.Helpers; -namespace Aaru.Decoders.CD +namespace Aaru.Decoders.CD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class TOC { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class TOC + public static CDTOC? Decode(byte[] CDTOCResponse) { - public static CDTOC? Decode(byte[] CDTOCResponse) + if(CDTOCResponse == null || + CDTOCResponse.Length <= 4) + return null; + + var decoded = new CDTOC { - if(CDTOCResponse == null || - CDTOCResponse.Length <= 4) - return null; + DataLength = BigEndianBitConverter.ToUInt16(CDTOCResponse, 0), + FirstTrack = CDTOCResponse[2], + LastTrack = CDTOCResponse[3] + }; - var decoded = new CDTOC - { - DataLength = BigEndianBitConverter.ToUInt16(CDTOCResponse, 0), - FirstTrack = CDTOCResponse[2], - LastTrack = CDTOCResponse[3] - }; + decoded.TrackDescriptors = new CDTOCTrackDataDescriptor[(decoded.DataLength - 2) / 8]; - decoded.TrackDescriptors = new CDTOCTrackDataDescriptor[(decoded.DataLength - 2) / 8]; + if(decoded.DataLength + 2 != CDTOCResponse.Length) + { + AaruConsole.DebugWriteLine("CD TOC decoder", + "Expected CDTOC size ({0} bytes) is not received size ({1} bytes), not decoding", + decoded.DataLength + 2, CDTOCResponse.Length); - if(decoded.DataLength + 2 != CDTOCResponse.Length) - { - AaruConsole.DebugWriteLine("CD TOC decoder", - "Expected CDTOC size ({0} bytes) is not received size ({1} bytes), not decoding", - decoded.DataLength + 2, CDTOCResponse.Length); - - return null; - } - - for(int i = 0; i < (decoded.DataLength - 2) / 8; i++) - { - decoded.TrackDescriptors[i].Reserved1 = CDTOCResponse[0 + (i * 8) + 4]; - decoded.TrackDescriptors[i].ADR = (byte)((CDTOCResponse[1 + (i * 8) + 4] & 0xF0) >> 4); - 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); - } - - return decoded; + return null; } - public static string Prettify(CDTOC? CDTOCResponse) + for(int i = 0; i < (decoded.DataLength - 2) / 8; i++) { - if(CDTOCResponse == null) - return null; + decoded.TrackDescriptors[i].Reserved1 = CDTOCResponse[0 + (i * 8) + 4]; + decoded.TrackDescriptors[i].ADR = (byte)((CDTOCResponse[1 + (i * 8) + 4] & 0xF0) >> 4); + 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]; - CDTOC response = CDTOCResponse.Value; + decoded.TrackDescriptors[i].TrackStartAddress = + BigEndianBitConverter.ToUInt32(CDTOCResponse, 4 + (i * 8) + 4); + } - var sb = new StringBuilder(); + return decoded; + } - 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(); + public static string Prettify(CDTOC? CDTOCResponse) + { + if(CDTOCResponse == null) + return null; - foreach(CDTOCTrackDataDescriptor descriptor in response.TrackDescriptors) + CDTOC response = CDTOCResponse.Value; + + 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(); + + 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, + (descriptor.TrackStartAddress & 0xFF000000) >> 24).AppendLine(); + + switch((TocAdr)descriptor.ADR) { - if(descriptor.TrackNumber == 0xAA) - sb.AppendLine("Track number: Lead-Out"); - else - sb.AppendFormat("Track number: {0}", descriptor.TrackNumber).AppendLine(); + case TocAdr.NoInformation: + sb.AppendLine("Q subchannel mode not given"); - 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, - (descriptor.TrackStartAddress & 0xFF000000) >> 24).AppendLine(); + break; + case TocAdr.TrackPointer: + sb.AppendLine("Q subchannel stores track pointer"); - switch((TocAdr)descriptor.ADR) + 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; + } + + if((descriptor.CONTROL & (byte)TocControl.ReservedMask) == (byte)TocControl.ReservedMask) + sb.AppendFormat("Reserved flags 0x{0:X2} set", descriptor.CONTROL).AppendLine(); + else + { + switch((TocControl)(descriptor.CONTROL & 0x0D)) { - case TocAdr.NoInformation: - sb.AppendLine("Q subchannel mode not given"); + case TocControl.TwoChanNoPreEmph: + sb.AppendLine("Stereo audio track with no pre-emphasis"); break; - case TocAdr.TrackPointer: - sb.AppendLine("Q subchannel stores track pointer"); + case TocControl.TwoChanPreEmph: + sb.AppendLine("Stereo audio track with 50/15 μs pre-emphasis"); break; - case TocAdr.VideoTrackPointer: - sb.AppendLine("Q subchannel stores video track pointer"); + case TocControl.FourChanNoPreEmph: + sb.AppendLine("Quadraphonic audio track with no pre-emphasis"); break; - case TocAdr.ISRC: - sb.AppendLine("Q subchannel stores ISRC"); + case TocControl.FourChanPreEmph: + sb.AppendLine("Quadraphonic audio track with 50/15 μs pre-emphasis"); break; - case TocAdr.MediaCatalogNumber: - sb.AppendLine("Q subchannel stores media catalog number"); + case TocControl.DataTrack: + sb.AppendLine("Data track, recorded uninterrupted"); break; - default: - sb.AppendFormat("Q subchannel mode {0}", descriptor.ADR).AppendLine(); + case TocControl.DataTrackIncremental: + sb.AppendLine("Data track, recorded incrementally"); break; } - if((descriptor.CONTROL & (byte)TocControl.ReservedMask) == (byte)TocControl.ReservedMask) - sb.AppendFormat("Reserved flags 0x{0:X2} set", descriptor.CONTROL).AppendLine(); - else - { - switch((TocControl)(descriptor.CONTROL & 0x0D)) - { - case TocControl.TwoChanNoPreEmph: - sb.AppendLine("Stereo audio track with no pre-emphasis"); + sb.AppendLine((descriptor.CONTROL & (byte)TocControl.CopyPermissionMask) == + (byte)TocControl.CopyPermissionMask ? "Digital copy of track is permitted" + : "Digital copy of track is prohibited"); - break; - case TocControl.TwoChanPreEmph: - sb.AppendLine("Stereo audio track with 50/15 μs pre-emphasis"); + #if DEBUG + if(descriptor.Reserved1 != 0) + sb.AppendFormat("Reserved1 = 0x{0:X2}", descriptor.Reserved1).AppendLine(); - break; - case TocControl.FourChanNoPreEmph: - sb.AppendLine("Quadraphonic audio track with no pre-emphasis"); + if(descriptor.Reserved2 != 0) + sb.AppendFormat("Reserved2 = 0x{0:X2}", descriptor.Reserved2).AppendLine(); + #endif - 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" - : "Digital copy of track is prohibited"); - - #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 - - sb.AppendLine(); - } + sb.AppendLine(); } - - return sb.ToString(); } - public static string Prettify(byte[] CDTOCResponse) - { - CDTOC? decoded = Decode(CDTOCResponse); + return sb.ToString(); + } - return Prettify(decoded); - } + public static string Prettify(byte[] CDTOCResponse) + { + CDTOC? decoded = Decode(CDTOCResponse); - public struct CDTOC - { - /// Total size of returned TOC minus this field - public ushort DataLength; - /// First track number in hex - public byte FirstTrack; - /// Last track number in hex - public byte LastTrack; - /// Track descriptors - public CDTOCTrackDataDescriptor[] TrackDescriptors; - } + return Prettify(decoded); + } - public struct CDTOCTrackDataDescriptor - { - /// Byte 0 Reserved - public byte Reserved1; - /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found - public byte ADR; - /// Byte 1, bits 3 to 0 Track attributes - public byte CONTROL; - /// Byte 2 Track number - public byte TrackNumber; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 7 The track start address in LBA or in MSF - public uint TrackStartAddress; - } + public struct CDTOC + { + /// Total size of returned TOC minus this field + public ushort DataLength; + /// First track number in hex + public byte FirstTrack; + /// Last track number in hex + public byte LastTrack; + /// Track descriptors + public CDTOCTrackDataDescriptor[] TrackDescriptors; + } + + public struct CDTOCTrackDataDescriptor + { + /// Byte 0 Reserved + public byte Reserved1; + /// Byte 1, bits 7 to 4 Type of information in Q subchannel of block where this TOC entry was found + public byte ADR; + /// Byte 1, bits 3 to 0 Track attributes + public byte CONTROL; + /// Byte 2 Track number + public byte TrackNumber; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 The track start address in LBA or in MSF + public uint TrackStartAddress; } } \ No newline at end of file diff --git a/DVD/AACS.cs b/DVD/AACS.cs index e77dd43..d6c30ab 100644 --- a/DVD/AACS.cs +++ b/DVD/AACS.cs @@ -32,36 +32,35 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class AACS { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class AACS + public struct HDLeadInCopyright { - public struct HDLeadInCopyright - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 2052 HD DVD Lead-In Copyright Information - public byte[] CopyrightInformation; - } + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 2052 HD DVD Lead-In Copyright Information + public byte[] CopyrightInformation; } } \ No newline at end of file diff --git a/DVD/ADIP.cs b/DVD/ADIP.cs index 3541b8e..6659867 100644 --- a/DVD/ADIP.cs +++ b/DVD/ADIP.cs @@ -32,36 +32,35 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class ADIP { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class ADIP + public struct ADIPInformation { - public struct ADIPInformation - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 259 ADIP, defined in DVD standards - public byte[] ADIP; - } + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 259 ADIP, defined in DVD standards + public byte[] ADIP; } } \ No newline at end of file diff --git a/DVD/BCA.cs b/DVD/BCA.cs index 441e6fe..66f1c70 100644 --- a/DVD/BCA.cs +++ b/DVD/BCA.cs @@ -32,36 +32,35 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class BCA { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class BCA + public struct BurstCuttingArea { - public struct BurstCuttingArea - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end Burst cutting area contents, 12 to 188 bytes - public byte[] BCA; - } + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end Burst cutting area contents, 12 to 188 bytes + public byte[] BCA; } } \ No newline at end of file diff --git a/DVD/CPRM.cs b/DVD/CPRM.cs index f3213e4..5adaf48 100644 --- a/DVD/CPRM.cs +++ b/DVD/CPRM.cs @@ -32,48 +32,47 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD -{ - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class CPRM - { - public struct DiscMediaIdentifier - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end Disc Media Identifier for CPRM - public byte[] MediaIdentifier; - } +namespace Aaru.Decoders.DVD; - public struct DiscMediaKeyBlock - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end Disc Media Key Block for CPRM - public byte[] MediaKeyBlock; - } +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class CPRM +{ + public struct DiscMediaIdentifier + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end Disc Media Identifier for CPRM + public byte[] MediaIdentifier; + } + + public struct DiscMediaKeyBlock + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end Disc Media Key Block for CPRM + public byte[] MediaKeyBlock; } } \ No newline at end of file diff --git a/DVD/CSS&CPRM.cs b/DVD/CSS&CPRM.cs index d8ce35e..9eac0c2 100644 --- a/DVD/CSS&CPRM.cs +++ b/DVD/CSS&CPRM.cs @@ -34,319 +34,318 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class CSS_CPRM { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class CSS_CPRM + public static LeadInCopyright? DecodeLeadInCopyright(byte[] response) { - 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], - RegionInformation = response[5], - Reserved3 = response[6], - Reserved4 = response[7] - }; + return new LeadInCopyright + { + 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] + }; + } + + public static RegionalPlaybackControlState? DecodeRegionalPlaybackControlState(byte[] response) + { + if(response?.Length != 8) + return null; + + return new RegionalPlaybackControlState + { + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + TypeCode_VendorResetsAvailable_UserControlledChangesAvailable = response[4], + RegionMask = response[5], + RPCScheme = response[6], + Reserved3 = response[7] + }; + } + + public static string PrettifyRegionalPlaybackControlState(RegionalPlaybackControlState? rpc) + { + if(rpc == null) + { + return null; } - public static RegionalPlaybackControlState? DecodeRegionalPlaybackControlState(byte[] response) - { - if(response?.Length != 8) - return null; + RegionalPlaybackControlState decoded = rpc.Value; + var sb = new StringBuilder(); - return new RegionalPlaybackControlState - { - DataLength = (ushort)((response[0] << 8) + response[1]), - Reserved1 = response[2], - Reserved2 = response[3], - TypeCode_VendorResetsAvailable_UserControlledChangesAvailable = response[4], - RegionMask = response[5], - RPCScheme = response[6], - Reserved3 = response[7] - }; + var typeCode = + (TypeCode)((decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0xc0) >> 6); + + int vendorResets = (decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0x38) >> 3; + + int userControlledChanges = decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0x7; + + switch(typeCode) + { + case TypeCode.None: + sb.AppendLine("No drive region setting."); + + break; + case TypeCode.Set: + sb.AppendLine("Drive region is set."); + + break; + case TypeCode.LastChance: + sb.AppendLine("Drive region is set, with additional restrictions required to make a change."); + + break; + case TypeCode.Perm: + sb.AppendLine("Drive region has been set permanently, but may be reset by the vendor if necessary."); + + break; } - public static string PrettifyRegionalPlaybackControlState(RegionalPlaybackControlState? rpc) + sb.AppendLine($"Drive has {vendorResets} vendor resets available."); + sb.AppendLine($"Drive has {userControlledChanges} user controlled changes available."); + + if(decoded.RegionMask == 0xFF) + sb.AppendLine("Drive has no region set."); + else if(decoded.RegionMask == 0x00) + sb.AppendLine("Drive is region free."); + else { - if(rpc == null) - { - return null; - } + sb.Append("Drive has the following regions set:"); - RegionalPlaybackControlState decoded = rpc.Value; - var sb = new StringBuilder(); + if((decoded.RegionMask & 0x01) != 0x01) + sb.Append(" 1"); - var typeCode = - (TypeCode)((decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0xc0) >> 6); + if((decoded.RegionMask & 0x02) != 0x02) + sb.Append(" 2"); - int vendorResets = (decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0x38) >> 3; + if((decoded.RegionMask & 0x04) != 0x04) + sb.Append(" 3"); - int userControlledChanges = decoded.TypeCode_VendorResetsAvailable_UserControlledChangesAvailable & 0x7; + if((decoded.RegionMask & 0x08) != 0x08) + sb.Append(" 4"); - switch(typeCode) - { - case TypeCode.None: - sb.AppendLine("No drive region setting."); + if((decoded.RegionMask & 0x10) != 0x10) + sb.Append(" 5"); - break; - case TypeCode.Set: - sb.AppendLine("Drive region is set."); + if((decoded.RegionMask & 0x20) != 0x20) + sb.Append(" 6"); - break; - case TypeCode.LastChance: - sb.AppendLine("Drive region is set, with additional restrictions required to make a change."); + if((decoded.RegionMask & 0x40) != 0x40) + sb.Append(" 7"); - break; - case TypeCode.Perm: - sb.AppendLine("Drive region has been set permanently, but may be reset by the vendor if necessary."); + if((decoded.RegionMask & 0x80) != 0x80) + sb.Append(" 8"); + } - break; - } + sb.AppendLine(""); - sb.AppendLine($"Drive has {vendorResets} vendor resets available."); - sb.AppendLine($"Drive has {userControlledChanges} user controlled changes available."); + switch(decoded.RPCScheme) + { + case 0x00: + sb.AppendLine("The Logical Unit does not enforce Region Playback Controls (RPC)."); - if(decoded.RegionMask == 0xFF) - sb.AppendLine("Drive has no region set."); - else if(decoded.RegionMask == 0x00) - sb.AppendLine("Drive is region free."); - else - { - sb.Append("Drive has the following regions set:"); + break; + case 0x01: + sb.AppendLine("The Logical Unit shall adhere to the specification and all requirements of the CSS license agreement concerning RPC."); - if((decoded.RegionMask & 0x01) != 0x01) - sb.Append(" 1"); + break; + default: + sb.AppendLine("The Logical Unit uses an unknown region enforcement scheme."); - if((decoded.RegionMask & 0x02) != 0x02) - sb.Append(" 2"); + break; + } - if((decoded.RegionMask & 0x04) != 0x04) - sb.Append(" 3"); + return sb.ToString(); + } - if((decoded.RegionMask & 0x08) != 0x08) - sb.Append(" 4"); + public static string PrettifyRegionalPlaybackControlState(byte[] response) => + PrettifyRegionalPlaybackControlState(DecodeRegionalPlaybackControlState(response)); - if((decoded.RegionMask & 0x10) != 0x10) - sb.Append(" 5"); + public static string PrettifyLeadInCopyright(LeadInCopyright? cmi) + { + if(cmi == null) + return null; - if((decoded.RegionMask & 0x20) != 0x20) - sb.Append(" 6"); + LeadInCopyright decoded = cmi.Value; + var sb = new StringBuilder(); - if((decoded.RegionMask & 0x40) != 0x40) - sb.Append(" 7"); + switch(decoded.CopyrightType) + { + case CopyrightType.NoProtection: + sb.AppendLine("Disc has no encryption."); - if((decoded.RegionMask & 0x80) != 0x80) - sb.Append(" 8"); - } + break; + case CopyrightType.CSS: + sb.AppendLine("Disc is encrypted using CSS or CPPM."); - sb.AppendLine(""); + break; + case CopyrightType.CPRM: + sb.AppendLine("Disc is encrypted using CPRM."); - switch(decoded.RPCScheme) - { - case 0x00: - sb.AppendLine("The Logical Unit does not enforce Region Playback Controls (RPC)."); + break; + case CopyrightType.AACS: + sb.AppendLine("Disc is encrypted using AACS."); - break; - case 0x01: - sb.AppendLine("The Logical Unit shall adhere to the specification and all requirements of the CSS license agreement concerning RPC."); + break; + default: + sb.AppendFormat("Disc is encrypted using unknown algorithm with ID {0}.", decoded.CopyrightType); - break; - default: - sb.AppendLine("The Logical Unit uses an unknown region enforcement scheme."); - - break; - } + break; + } + if(decoded.CopyrightType == 0) return sb.ToString(); - } - public static string PrettifyRegionalPlaybackControlState(byte[] response) => - PrettifyRegionalPlaybackControlState(DecodeRegionalPlaybackControlState(response)); - - public static string PrettifyLeadInCopyright(LeadInCopyright? cmi) + 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 { - if(cmi == null) - return null; + sb.Append("Disc can be played in the following regions:"); - LeadInCopyright decoded = cmi.Value; - var sb = new StringBuilder(); + if((decoded.RegionInformation & 0x01) != 0x01) + sb.Append(" 1"); - switch(decoded.CopyrightType) - { - case CopyrightType.NoProtection: - sb.AppendLine("Disc has no encryption."); + if((decoded.RegionInformation & 0x02) != 0x02) + sb.Append(" 2"); - break; - case CopyrightType.CSS: - sb.AppendLine("Disc is encrypted using CSS or CPPM."); + if((decoded.RegionInformation & 0x04) != 0x04) + sb.Append(" 3"); - break; - case CopyrightType.CPRM: - sb.AppendLine("Disc is encrypted using CPRM."); + if((decoded.RegionInformation & 0x08) != 0x08) + sb.Append(" 4"); - break; - case CopyrightType.AACS: - sb.AppendLine("Disc is encrypted using AACS."); + if((decoded.RegionInformation & 0x10) != 0x10) + sb.Append(" 5"); - break; - default: - sb.AppendFormat("Disc is encrypted using unknown algorithm with ID {0}.", decoded.CopyrightType); + if((decoded.RegionInformation & 0x20) != 0x20) + sb.Append(" 6"); - break; - } + if((decoded.RegionInformation & 0x40) != 0x40) + sb.Append(" 7"); - 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."); - else - { - sb.Append("Disc can be played in the following regions:"); - - if((decoded.RegionInformation & 0x01) != 0x01) - sb.Append(" 1"); - - if((decoded.RegionInformation & 0x02) != 0x02) - sb.Append(" 2"); - - if((decoded.RegionInformation & 0x04) != 0x04) - sb.Append(" 3"); - - if((decoded.RegionInformation & 0x08) != 0x08) - sb.Append(" 4"); - - if((decoded.RegionInformation & 0x10) != 0x10) - sb.Append(" 5"); - - if((decoded.RegionInformation & 0x20) != 0x20) - sb.Append(" 6"); - - if((decoded.RegionInformation & 0x40) != 0x40) - sb.Append(" 7"); - - if((decoded.RegionInformation & 0x80) != 0x80) - sb.Append(" 8"); - } - - return sb.ToString(); + if((decoded.RegionInformation & 0x80) != 0x80) + sb.Append(" 8"); } - public static string PrettifyLeadInCopyright(byte[] response) => - PrettifyLeadInCopyright(DecodeLeadInCopyright(response)); + return sb.ToString(); + } - public struct LeadInCopyright - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 Copy protection system type - public CopyrightType CopyrightType; - /// Byte 5 Bitmask of regions where this disc is playable - public byte RegionInformation; - /// Byte 6 Reserved - public byte Reserved3; - /// Byte 7 Reserved - public byte Reserved4; - } + public static string PrettifyLeadInCopyright(byte[] response) => + PrettifyLeadInCopyright(DecodeLeadInCopyright(response)); - public struct DiscKey - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 2052 Disc key for CSS, Album Identifier for CPPM - public byte[] Key; - } + public struct LeadInCopyright + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Copy protection system type + public CopyrightType CopyrightType; + /// Byte 5 Bitmask of regions where this disc is playable + public byte RegionInformation; + /// Byte 6 Reserved + public byte Reserved3; + /// Byte 7 Reserved + public byte Reserved4; + } - public struct TitleKey - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 CPM - public byte CMI; - /// Bytes 5 to 10 Title key for CSS - public byte[] Key; - /// Byte 11 Reserved - public byte Reserved3; - /// Byte 12 Reserved - public byte Reserved4; - } + public struct DiscKey + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 2052 Disc key for CSS, Album Identifier for CPPM + public byte[] Key; + } - public struct AuthenticationSuccessFlag - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 Reserved - public byte Reserved3; - /// Byte 5 Reserved - public byte Reserved4; - /// Byte 6 Reserved - public byte Reserved5; - /// Byte 7 Reserved and ASF - public byte ASF; - } + public struct TitleKey + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 CPM + public byte CMI; + /// Bytes 5 to 10 Title key for CSS + public byte[] Key; + /// Byte 11 Reserved + public byte Reserved3; + /// Byte 12 Reserved + public byte Reserved4; + } - public struct RegionalPlaybackControlState - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 Type Code and # of Vendor Resets Available and # of User Controlled Changes Available - public byte TypeCode_VendorResetsAvailable_UserControlledChangesAvailable; - /// Byte 5 Region Mask - public byte RegionMask; - /// Byte 6 RPC Scheme - public byte RPCScheme; - /// Byte 7 Reserved - public byte Reserved3; - } + public struct AuthenticationSuccessFlag + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved and ASF + public byte ASF; + } - enum TypeCode - { - None = 0, Set = 1, LastChance = 2, - Perm = 3 - } + public struct RegionalPlaybackControlState + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Type Code and # of Vendor Resets Available and # of User Controlled Changes Available + public byte TypeCode_VendorResetsAvailable_UserControlledChangesAvailable; + /// Byte 5 Region Mask + public byte RegionMask; + /// Byte 6 RPC Scheme + public byte RPCScheme; + /// Byte 7 Reserved + public byte Reserved3; + } + + enum TypeCode + { + None = 0, Set = 1, LastChance = 2, + Perm = 3 } } \ No newline at end of file diff --git a/DVD/Cartridge.cs b/DVD/Cartridge.cs index 7c217dc..84c6db9 100644 --- a/DVD/Cartridge.cs +++ b/DVD/Cartridge.cs @@ -33,143 +33,142 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class Cartridge { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class Cartridge + public static MediumStatus? Decode(byte[] response) { - 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], - RAMSWI = response[7] - }; + 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], + RAMSWI = response[7] + }; + } + + public static string Prettify(MediumStatus? status) + { + if(status == null) + return null; + + MediumStatus decoded = status.Value; + var sb = new StringBuilder(); + + 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"); } - public static string Prettify(MediumStatus? status) + switch(decoded.DiscType) { - if(status == null) - return null; + case 0: + sb.AppendLine("Disc shall not be written without a cartridge"); - MediumStatus decoded = status.Value; - var sb = new StringBuilder(); + break; + case 0x10: + sb.AppendLine("Disc may be written without a cartridge"); - if(decoded.PWP) - sb.AppendLine("Disc surface is set to write protected status"); + break; + default: + sb.AppendFormat("Unknown disc type id {0}", decoded.DiscType).AppendLine(); - 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"); - } - - 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(); - - 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; - } + break; + } + if(!decoded.MSWI) return sb.ToString(); - } - public static string Prettify(byte[] response) => Prettify(Decode(response)); - - public struct MediumStatus + switch(decoded.RAMSWI) { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4, bit 7 Medium is in a cartridge - public bool Cartridge; - /// Byte 4, bit 6 Medium has been taken out/inserted in a cartridge - public bool OUT; - /// Byte 4, bits 5 to 4 Reserved - public byte Reserved3; - /// Byte 4, bit 3 Media is write protected by reason stablished in RAMSWI - public bool MSWI; - /// Byte 4, bit 2 Media is write protected by cartridge - public bool CWP; - /// Byte 4, bit 1 Media is persistently write protected - public bool PWP; - /// Byte 4, bit 0 Reserved - public bool Reserved4; - /// Byte 5 Writable status depending on cartridge - public byte DiscType; - /// Byte 6 Reserved - public byte Reserved5; - /// - /// Byte 7 Reason of specific write protection, only defined 0x01 as "bare disc wp", and 0xFF as unspecified. Rest - /// reserved. - /// - public byte 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; } + + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + + public struct MediumStatus + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 Medium is in a cartridge + public bool Cartridge; + /// Byte 4, bit 6 Medium has been taken out/inserted in a cartridge + public bool OUT; + /// Byte 4, bits 5 to 4 Reserved + public byte Reserved3; + /// Byte 4, bit 3 Media is write protected by reason stablished in RAMSWI + public bool MSWI; + /// Byte 4, bit 2 Media is write protected by cartridge + public bool CWP; + /// Byte 4, bit 1 Media is persistently write protected + public bool PWP; + /// Byte 4, bit 0 Reserved + public bool Reserved4; + /// Byte 5 Writable status depending on cartridge + public byte DiscType; + /// Byte 6 Reserved + public byte Reserved5; + /// + /// Byte 7 Reason of specific write protection, only defined 0x01 as "bare disc wp", and 0xFF as unspecified. Rest + /// reserved. + /// + public byte RAMSWI; } } \ No newline at end of file diff --git a/DVD/DDS.cs b/DVD/DDS.cs index e90b09d..fba7db3 100644 --- a/DVD/DDS.cs +++ b/DVD/DDS.cs @@ -34,218 +34,217 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DDS { - // 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) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class DDS + public static DiscDefinitionStructure? Decode(byte[] response) { - public static DiscDefinitionStructure? Decode(byte[] response) + if(response?.Length != 2052) + return null; + + var dds = new DiscDefinitionStructure { - if(response?.Length != 2052) - return null; + Identifier = (ushort)((response[4] << 8) + response[5]) + }; - var dds = new DiscDefinitionStructure + if(dds.Identifier != 0x0A0A) + return null; + + // Common to both DVD-RAM versions + dds.DataLength = (ushort)((response[0] << 8) + response[1]); + dds.Reserved1 = response[2]; + dds.Reserved2 = response[3]; + dds.Reserved3 = response[6]; + 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]); + + // ECMA-272 + if(dds.Groups == 24) + { + dds.PartialCertification |= (response[7] & 0x40) == 0x40; + dds.FormattingOnlyAGroup |= (response[7] & 0x20) == 0x20; + dds.Reserved4 = (byte)((response[7] & 0x1C) >> 2); + 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++) { - Identifier = (ushort)((response[4] << 8) + response[5]) - }; - - if(dds.Identifier != 0x0A0A) - return null; - - // Common to both DVD-RAM versions - dds.DataLength = (ushort)((response[0] << 8) + response[1]); - dds.Reserved1 = response[2]; - dds.Reserved2 = response[3]; - dds.Reserved3 = response[6]; - 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]); - - // ECMA-272 - if(dds.Groups == 24) - { - dds.PartialCertification |= (response[7] & 0x40) == 0x40; - dds.FormattingOnlyAGroup |= (response[7] & 0x20) == 0x20; - dds.Reserved4 = (byte)((response[7] & 0x1C) >> 2); - 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; - dds.GroupCertificationFlags[i].PartialCertification |= (response[20 + i] & 0x40) == 0x40; - dds.GroupCertificationFlags[i].Reserved1 = (byte)((response[20 + i] & 0x3C) >> 2); - dds.GroupCertificationFlags[i].UserCertification |= (response[20 + i] & 0x02) == 0x02; - dds.GroupCertificationFlags[i].Reserved2 |= (response[20 + i] & 0x01) == 0x01; - } + dds.GroupCertificationFlags[i].InProcess |= (response[20 + i] & 0x80) == 0x80; + dds.GroupCertificationFlags[i].PartialCertification |= (response[20 + i] & 0x40) == 0x40; + dds.GroupCertificationFlags[i].Reserved1 = (byte)((response[20 + i] & 0x3C) >> 2); + dds.GroupCertificationFlags[i].UserCertification |= (response[20 + i] & 0x02) == 0x02; + dds.GroupCertificationFlags[i].Reserved2 |= (response[20 + i] & 0x01) == 0x01; } - - // ECMA-330 - if(dds.Groups != 1) - return dds; - - { - dds.Reserved4 = (byte)((response[7] & 0x7C) >> 2); - dds.Reserved = new byte[68]; - Array.Copy(response, 16, dds.Reserved, 0, 68); - dds.Zones = (ushort)((response[14] << 8) + response[15]); - dds.SpareAreaFirstPSN = (uint)((response[85] << 16) + (response[86] << 8) + response[87]); - dds.SpareAreaLastPSN = (uint)((response[89] << 16) + (response[90] << 8) + response[91]); - dds.LSN0Location = (uint)((response[93] << 16) + (response[94] << 8) + response[95]); - dds.StartLSNForZone = new uint[dds.Zones]; - - for(int i = 0; i < dds.Zones; i++) - dds.StartLSNForZone[i] = (uint)((response[260 + (i * 4) + 1] << 16) + - (response[260 + (i * 4) + 2] << 8) + response[260 + (i * 4) + 3]); - } - - return dds; } - public static string Prettify(DiscDefinitionStructure? dds) + // ECMA-330 + if(dds.Groups != 1) + return dds; + { - if(dds == null) - return null; + dds.Reserved4 = (byte)((response[7] & 0x7C) >> 2); + dds.Reserved = new byte[68]; + Array.Copy(response, 16, dds.Reserved, 0, 68); + dds.Zones = (ushort)((response[14] << 8) + response[15]); + dds.SpareAreaFirstPSN = (uint)((response[85] << 16) + (response[86] << 8) + response[87]); + dds.SpareAreaLastPSN = (uint)((response[89] << 16) + (response[90] << 8) + response[91]); + dds.LSN0Location = (uint)((response[93] << 16) + (response[94] << 8) + response[95]); + dds.StartLSNForZone = new uint[dds.Zones]; - DiscDefinitionStructure decoded = dds.Value; - var sb = new StringBuilder(); + for(int i = 0; i < dds.Zones; i++) + dds.StartLSNForZone[i] = (uint)((response[260 + (i * 4) + 1] << 16) + + (response[260 + (i * 4) + 2] << 8) + response[260 + (i * 4) + 3]); + } - if(decoded.InProcess) - { - sb.AppendLine("Formatting in progress."); + return dds; + } - if(decoded.Groups == 24) - { - if(decoded.PartialCertification) - sb.AppendLine("Formatting is only using partial certification"); + public static string Prettify(DiscDefinitionStructure? dds) + { + if(dds == null) + return null; - if(decoded.FormattingOnlyAGroup) - sb.AppendLine("Only a group is being formatted"); - } - } + DiscDefinitionStructure decoded = dds.Value; + var sb = new StringBuilder(); - 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(); + if(decoded.InProcess) + { + sb.AppendLine("Formatting in progress."); if(decoded.Groups == 24) - for(int i = 0; i < decoded.GroupCertificationFlags.Length; i++) + { + 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"); + + sb.AppendFormat("DDS has been updated {0} times", decoded.UpdateCount).AppendLine(); + + if(decoded.Groups == 24) + for(int i = 0; i < decoded.GroupCertificationFlags.Length; i++) + { + if(decoded.GroupCertificationFlags[i].InProcess) { - if(decoded.GroupCertificationFlags[i].InProcess) - { - sb.AppendFormat("Group {0} is being formatted", i).AppendLine(); + sb.AppendFormat("Group {0} is being formatted", i).AppendLine(); - if(decoded.GroupCertificationFlags[i].PartialCertification) - sb.AppendFormat("Group {0} is being certified partially", i).AppendLine(); - } - - if(decoded.GroupCertificationFlags[i].UserCertification) - sb.AppendFormat("Group {0} has been certified by an user", i).AppendLine(); + if(decoded.GroupCertificationFlags[i].PartialCertification) + sb.AppendFormat("Group {0} is being certified partially", i).AppendLine(); } - 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++) - sb.AppendFormat("Zone {0} starts at LSN {1}", i, decoded.StartLSNForZone[i]).AppendLine(); + if(decoded.GroupCertificationFlags[i].UserCertification) + sb.AppendFormat("Group {0} has been certified by an user", i).AppendLine(); } + if(decoded.Groups != 1) return sb.ToString(); - } - public static string Prettify(byte[] response) => Prettify(Decode(response)); - - public struct DiscDefinitionStructure { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; + sb.AppendFormat("Disc has {0} zones", decoded.Zones).AppendLine(); - /// Bytes 4 to 5 DDS Identifier = 0x0A0A - public ushort Identifier; - /// Byte 6 Reserved - public byte Reserved3; - /// Byte 7, bit 7 If set, formatting is in process - public bool InProcess; - /// Byte 7, bit 6 If set, formatting is using partial certification Only in ECMA-272 - public bool PartialCertification; - /// Byte 7, bit 5 If set, only a group is being formatted Only in ECMA-272 - public bool FormattingOnlyAGroup; - /// Byte 7, bits 4 to 2 Reserved - public byte Reserved4; - /// Byte 7, bit 1 If set, disk has been certified by a user - public bool UserCertification; - /// Byte 7, bit 0 If set, disk has been certified by a manufacturer - public bool ManufacturerCertification; - /// Bytes 8 to 11 How many times the DDS has been updated - public uint UpdateCount; - /// Bytes 12 to 13 How many groups the disk has 24 for ECMA-272 1 for ECMA-330 - public ushort Groups; - /// Bytes 14 to 15 How many zones the disk has Only in ECMA-330 - public ushort Zones; - /// Bytes 14 to 19 in ECMA-272 Bytes 16 to 83 in ECMA-330 Reserved - public byte[] Reserved; - /// Bytes 20 to 43 Group certification flags - public GroupCertificationFlag[] GroupCertificationFlags; + sb.AppendFormat("Primary Spare Area stats at PSN {0:X}h and ends at PSN {1:X}h, inclusively", + decoded.SpareAreaFirstPSN, decoded.SpareAreaLastPSN).AppendLine(); - /// Bytes 85 to 87 Location of first sector in the Primary Spare Area - public uint SpareAreaFirstPSN; - /// Bytes 89 to 91 Location of first sector in the Primary Spare Area - public uint SpareAreaLastPSN; - /// Bytes 93 to 95 PSN for LSN 0 - public uint LSN0Location; - /// The starting LSN of each zone - public uint[] StartLSNForZone; + sb.AppendFormat("LSN 0 is at PSN {0:X}h", decoded.LSN0Location).AppendLine(); + + for(int i = 0; i < decoded.StartLSNForZone.Length; i++) + sb.AppendFormat("Zone {0} starts at LSN {1}", i, decoded.StartLSNForZone[i]).AppendLine(); } - public struct GroupCertificationFlag - { - /// Bit 7 If set, formatting of this group is in process - public bool InProcess; - /// Bit 6 If set, formatting is using partial certification - public bool PartialCertification; - /// Bits 5 to 2 Reserved - public byte Reserved1; - /// Bit 1 If set, this group has been certified by user - public bool UserCertification; - /// Bit 0 Reserved - public bool Reserved2; - } + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + + public struct DiscDefinitionStructure + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + + /// Bytes 4 to 5 DDS Identifier = 0x0A0A + public ushort Identifier; + /// Byte 6 Reserved + public byte Reserved3; + /// Byte 7, bit 7 If set, formatting is in process + public bool InProcess; + /// Byte 7, bit 6 If set, formatting is using partial certification Only in ECMA-272 + public bool PartialCertification; + /// Byte 7, bit 5 If set, only a group is being formatted Only in ECMA-272 + public bool FormattingOnlyAGroup; + /// Byte 7, bits 4 to 2 Reserved + public byte Reserved4; + /// Byte 7, bit 1 If set, disk has been certified by a user + public bool UserCertification; + /// Byte 7, bit 0 If set, disk has been certified by a manufacturer + public bool ManufacturerCertification; + /// Bytes 8 to 11 How many times the DDS has been updated + public uint UpdateCount; + /// Bytes 12 to 13 How many groups the disk has 24 for ECMA-272 1 for ECMA-330 + public ushort Groups; + /// Bytes 14 to 15 How many zones the disk has Only in ECMA-330 + public ushort Zones; + /// Bytes 14 to 19 in ECMA-272 Bytes 16 to 83 in ECMA-330 Reserved + public byte[] Reserved; + /// Bytes 20 to 43 Group certification flags + public GroupCertificationFlag[] GroupCertificationFlags; + + /// Bytes 85 to 87 Location of first sector in the Primary Spare Area + public uint SpareAreaFirstPSN; + /// Bytes 89 to 91 Location of first sector in the Primary Spare Area + public uint SpareAreaLastPSN; + /// Bytes 93 to 95 PSN for LSN 0 + public uint LSN0Location; + /// The starting LSN of each zone + public uint[] StartLSNForZone; + } + + public struct GroupCertificationFlag + { + /// Bit 7 If set, formatting of this group is in process + public bool InProcess; + /// Bit 6 If set, formatting is using partial certification + public bool PartialCertification; + /// Bits 5 to 2 Reserved + public byte Reserved1; + /// Bit 1 If set, this group has been certified by user + public bool UserCertification; + /// Bit 0 Reserved + public bool Reserved2; } } \ No newline at end of file diff --git a/DVD/DMI.cs b/DVD/DMI.cs index aa319e2..1e5a3d6 100644 --- a/DVD/DMI.cs +++ b/DVD/DMI.cs @@ -32,36 +32,35 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class DMI { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class DMI + public struct DiscManufacturingInformation { - public struct DiscManufacturingInformation - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 2052 Disc Manufacturing Information - public byte[] DMI; - } + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 2052 Disc Manufacturing Information + public byte[] DMI; } } \ No newline at end of file diff --git a/DVD/Enums.cs b/DVD/Enums.cs index bbdcd79..7133669 100644 --- a/DVD/Enums.cs +++ b/DVD/Enums.cs @@ -32,151 +32,150 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +#region Public enumerations +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DiskCategory : byte { - #region Public enumerations - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DiskCategory : byte - { - /// DVD-ROM. Version 1 is ECMA-267 and ECMA-268. - DVDROM = 0, - /// DVD-RAM. Version 1 is ECMA-272. Version 6 is ECMA-330. - DVDRAM = 1, - /// DVD-R. Version 1 is ECMA-279. Version 5 is ECMA-359. Version 6 is ECMA-382. - DVDR = 2, - /// DVD-RW. Version 2 is ECMA-338. Version 3 is ECMA-384. - DVDRW = 3, - /// HD DVD-ROM - HDDVDROM = 4, - /// HD DVD-RAM - HDDVDRAM = 5, - /// HD DVD-R - HDDVDR = 6, - /// HD DVD-RW - HDDVDRW = 7, - /// UMD. Version 0 is ECMA-365. - UMD = 8, - /// DVD+RW. Version 1 is ECMA-274. Version 2 is ECMA-337. Version 3 is ECMA-371. - DVDPRW = 9, - /// DVD+R. Version 1 is ECMA-349. - DVDPR = 10, - /// DVD+RW DL. Version 1 is ECMA-374. - DVDPRWDL = 13, - /// DVD+R DL. Version 1 is ECMA-364. - DVDPRDL = 14, - /// According to standards this value is reserved. It's used by Nintendo GODs and WODs. - Nintendo = 15 - } + /// DVD-ROM. Version 1 is ECMA-267 and ECMA-268. + DVDROM = 0, + /// DVD-RAM. Version 1 is ECMA-272. Version 6 is ECMA-330. + DVDRAM = 1, + /// DVD-R. Version 1 is ECMA-279. Version 5 is ECMA-359. Version 6 is ECMA-382. + DVDR = 2, + /// DVD-RW. Version 2 is ECMA-338. Version 3 is ECMA-384. + DVDRW = 3, + /// HD DVD-ROM + HDDVDROM = 4, + /// HD DVD-RAM + HDDVDRAM = 5, + /// HD DVD-R + HDDVDR = 6, + /// HD DVD-RW + HDDVDRW = 7, + /// UMD. Version 0 is ECMA-365. + UMD = 8, + /// DVD+RW. Version 1 is ECMA-274. Version 2 is ECMA-337. Version 3 is ECMA-371. + DVDPRW = 9, + /// DVD+R. Version 1 is ECMA-349. + DVDPR = 10, + /// DVD+RW DL. Version 1 is ECMA-374. + DVDPRWDL = 13, + /// DVD+R DL. Version 1 is ECMA-364. + DVDPRDL = 14, + /// According to standards this value is reserved. It's used by Nintendo GODs and WODs. + Nintendo = 15 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum MaximumRateField : byte - { - /// 2.52 Mbps - TwoMbps = 0x00, - /// 5.04 Mbps - FiveMbps = 0x01, - /// 10.08 Mbps - TenMbps = 0x02, - /// 20.16 Mbps - TwentyMbps = 0x03, - /// 30.24 Mbps - ThirtyMbps = 0x04, Unspecified = 0x0F - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum MaximumRateField : byte +{ + /// 2.52 Mbps + TwoMbps = 0x00, + /// 5.04 Mbps + FiveMbps = 0x01, + /// 10.08 Mbps + TenMbps = 0x02, + /// 20.16 Mbps + TwentyMbps = 0x03, + /// 30.24 Mbps + ThirtyMbps = 0x04, Unspecified = 0x0F +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum LayerTypeFieldMask : byte - { - Embossed = 0x01, Recordable = 0x02, Rewritable = 0x04, - Reserved = 0x08 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum LayerTypeFieldMask : byte +{ + Embossed = 0x01, Recordable = 0x02, Rewritable = 0x04, + Reserved = 0x08 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum LinearDensityField : byte - { - /// 0.267 μm/bit - TwoSix = 0x00, - /// 0.293 μm/bit - TwoNine = 0x01, - /// 0.409 to 0.435 μm/bit - FourZero = 0x02, - /// 0.280 to 0.291 μm/bit - TwoEight = 0x04, - /// 0.153 μm/bit - OneFive = 0x05, - /// 0.130 to 0.140 μm/bit - OneThree = 0x06, - /// 0.353 μm/bit - ThreeFive = 0x08 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum LinearDensityField : byte +{ + /// 0.267 μm/bit + TwoSix = 0x00, + /// 0.293 μm/bit + TwoNine = 0x01, + /// 0.409 to 0.435 μm/bit + FourZero = 0x02, + /// 0.280 to 0.291 μm/bit + TwoEight = 0x04, + /// 0.153 μm/bit + OneFive = 0x05, + /// 0.130 to 0.140 μm/bit + OneThree = 0x06, + /// 0.353 μm/bit + ThreeFive = 0x08 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum TrackDensityField : byte - { - /// 0.74 μm/track - Seven = 0x00, - /// 0.80 μm/track - Eight = 0x01, - /// 0.615 μm/track - Six = 0x02, - /// 0.40 μm/track - Four = 0x03, - /// 0.34 μm/track - Three = 0x04 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum TrackDensityField : byte +{ + /// 0.74 μm/track + Seven = 0x00, + /// 0.80 μm/track + Eight = 0x01, + /// 0.615 μm/track + Six = 0x02, + /// 0.40 μm/track + Four = 0x03, + /// 0.34 μm/track + Three = 0x04 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum CopyrightType : byte - { - /// There is no copy protection - NoProtection = 0x00, - /// Copy protection is CSS/CPPM - CSS = 0x01, - /// Copy protection is CPRM - CPRM = 0x02, - /// Copy protection is AACS - AACS = 0x10 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum CopyrightType : byte +{ + /// There is no copy protection + NoProtection = 0x00, + /// Copy protection is CSS/CPPM + CSS = 0x01, + /// Copy protection is CPRM + CPRM = 0x02, + /// Copy protection is AACS + AACS = 0x10 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WPDiscTypes : byte - { - /// Should not write without a cartridge - DoNotWrite = 0x00, - /// Can write without a cartridge - CanWrite = 0x01, Reserved1 = 0x02, Reserved2 = 0x03 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum WPDiscTypes : byte +{ + /// Should not write without a cartridge + DoNotWrite = 0x00, + /// Can write without a cartridge + CanWrite = 0x01, Reserved1 = 0x02, Reserved2 = 0x03 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DVDSize - { - /// 120 mm - OneTwenty = 0, - /// 80 mm - Eighty = 1 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DVDSize +{ + /// 120 mm + OneTwenty = 0, + /// 80 mm + Eighty = 1 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DVDRAMDiscType - { - /// Shall not be recorded without a case - Cased = 0, - /// May be recorded without a case or within one - Uncased = 1 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DVDRAMDiscType +{ + /// Shall not be recorded without a case + Cased = 0, + /// May be recorded without a case or within one + Uncased = 1 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DVDLayerStructure - { - Unspecified = 0, InvertedStack = 1, TwoP = 2, - Reserved = 3 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DVDLayerStructure +{ + 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, - Twelve = 0x50 - } - #endregion -} \ No newline at end of file +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DVDRecordingSpeed +{ + None = 0, Two = 0, Four = 0x10, + Six = 0x20, Eight = 0x30, Ten = 0x40, + Twelve = 0x50 +} +#endregion \ No newline at end of file diff --git a/DVD/Layers.cs b/DVD/Layers.cs index 5dc2a45..82d0691 100644 --- a/DVD/Layers.cs +++ b/DVD/Layers.cs @@ -32,108 +32,107 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Layers { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Layers + public struct LayerCapacity { - public struct LayerCapacity - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4, bit 7 If set, L0 capacity is immutable - public bool InitStatus; - /// Byte 4, bits 6 to 0 Reserved - public byte Reserved3; - /// Byte 5 Reserved - public byte Reserved4; - /// Byte 6 Reserved - public byte Reserved5; - /// Byte 7 Reserved - public byte Reserved6; - /// Byte 8 to 11 L0 Data Area Capacity - public uint Capacity; - } + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 If set, L0 capacity is immutable + public bool InitStatus; + /// Byte 4, bits 6 to 0 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 L0 Data Area Capacity + public uint Capacity; + } - public struct MiddleZoneStartAddress - { - /// Bytes 0 to 1 Data length = 10 - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4, bit 7 If set, L0 shifter middle area is immutable - public bool InitStatus; - /// Byte 4, bits 6 to 0 Reserved - public byte Reserved3; - /// Byte 5 Reserved - public byte Reserved4; - /// Byte 6 Reserved - public byte Reserved5; - /// Byte 7 Reserved - public byte Reserved6; - /// Byte 8 to 11 Start LBA of Shifted Middle Area on L0 - public uint ShiftedMiddleAreaStartAddress; - } + public struct MiddleZoneStartAddress + { + /// Bytes 0 to 1 Data length = 10 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bit 7 If set, L0 shifter middle area is immutable + public bool InitStatus; + /// Byte 4, bits 6 to 0 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 Start LBA of Shifted Middle Area on L0 + public uint ShiftedMiddleAreaStartAddress; + } - public struct JumpIntervalSize - { - /// Bytes 0 to 1 Data length = 10 - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 Reserved - public byte Reserved3; - /// Byte 5 Reserved - public byte Reserved4; - /// Byte 6 Reserved - public byte Reserved5; - /// Byte 7 Reserved - public byte Reserved6; - /// Byte 8 to 11 Jump Interval size for the Regular Interval Layer Jump - public uint Size; - } + public struct JumpIntervalSize + { + /// Bytes 0 to 1 Data length = 10 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 Jump Interval size for the Regular Interval Layer Jump + public uint Size; + } - public struct ManualLayerJumpAddress - { - /// Bytes 0 to 1 Data length = 10 - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 Reserved - public byte Reserved3; - /// Byte 5 Reserved - public byte Reserved4; - /// Byte 6 Reserved - public byte Reserved5; - /// Byte 7 Reserved - public byte Reserved6; - /// Byte 8 to 11 LBA for the manual layer jump - public uint LBA; - } + public struct ManualLayerJumpAddress + { + /// Bytes 0 to 1 Data length = 10 + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; + /// Byte 8 to 11 LBA for the manual layer jump + public uint LBA; } } \ No newline at end of file diff --git a/DVD/PFI.cs b/DVD/PFI.cs index a0cbaf2..0021164 100644 --- a/DVD/PFI.cs +++ b/DVD/PFI.cs @@ -36,1528 +36,1527 @@ using System.Text; using Aaru.CommonTypes; using Aaru.Helpers; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 267: 120 mm DVD - Read-Only Disk +// ECMA 268: 80 mm DVD - Read-Only Disk +// ECMA 272: 120 mm DVD Rewritable Disk (DVD-RAM) +// ECMA 274: Data Interchange on 120 mm Optical Disk using +RW Format - Capacity: 3,0 Gbytes and 6,0 Gbytes +// ECMA 279: 80 mm (1,23 Gbytes per side) and 120 mm (3,95 Gbytes per side) DVD-Recordable Disk (DVD-R) +// ECMA 330: 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM) +// ECMA 337: Data Interchange on 120 mm and 80 mm Optical Disk using +RW Format - Capacity: 4,7 and 1,46 Gbytes per Side +// ECMA 338: 80 mm (1,46 Gbytes per side) and 120 mm (4,70 Gbytes per side) DVD Re-recordable Disk (DVD-RW) +// ECMA 349: Data Interchange on 120 mm and 80 mm Optical Disk using +R Format - Capacity: 4,7 and 1,46 Gbytes per Side +// ECMA 359: 80 mm (1,46 Gbytes per side) and 120 mm (4,70 Gbytes per side) DVD Recordable Disk (DVD-R) +// ECMA 364: Data Interchange on 120 mm and 80 mm Optical Disk using +R DL Format - Capacity 8,55 and 2,66 Gbytes per Side +// ECMA 365: Data Interchange on 60 mm Read-Only ODC - Capacity: 1,8 Gbytes (UMD™) +// ECMA 371: Data Interchange on 120 mm and 80 mm Optical Disk using +RW HS Format - Capacity 4,7 and 1,46 Gbytes per side +// ECMA 374: Data Interchange on 120 mm and 80 mm Optical Disk using +RW DL Format - Capacity 8,55 and 2,66 Gbytes per side +// ECMA 382: 120 mm (8,54 Gbytes per side) and 80 mm (2,66 Gbytes per side) DVD Recordable Disk for Dual Layer (DVD-R for DL) +// ECMA 384: 120 mm (8,54 Gbytes per side) and 80 mm (2,66 Gbytes per side) DVD Re-recordable Disk for Dual Layer (DVD-RW for DL) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class PFI { - // 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 267: 120 mm DVD - Read-Only Disk - // ECMA 268: 80 mm DVD - Read-Only Disk - // ECMA 272: 120 mm DVD Rewritable Disk (DVD-RAM) - // ECMA 274: Data Interchange on 120 mm Optical Disk using +RW Format - Capacity: 3,0 Gbytes and 6,0 Gbytes - // ECMA 279: 80 mm (1,23 Gbytes per side) and 120 mm (3,95 Gbytes per side) DVD-Recordable Disk (DVD-R) - // ECMA 330: 120 mm (4,7 Gbytes per side) and 80 mm (1,46 Gbytes per side) DVD Rewritable Disk (DVD-RAM) - // ECMA 337: Data Interchange on 120 mm and 80 mm Optical Disk using +RW Format - Capacity: 4,7 and 1,46 Gbytes per Side - // ECMA 338: 80 mm (1,46 Gbytes per side) and 120 mm (4,70 Gbytes per side) DVD Re-recordable Disk (DVD-RW) - // ECMA 349: Data Interchange on 120 mm and 80 mm Optical Disk using +R Format - Capacity: 4,7 and 1,46 Gbytes per Side - // ECMA 359: 80 mm (1,46 Gbytes per side) and 120 mm (4,70 Gbytes per side) DVD Recordable Disk (DVD-R) - // ECMA 364: Data Interchange on 120 mm and 80 mm Optical Disk using +R DL Format - Capacity 8,55 and 2,66 Gbytes per Side - // ECMA 365: Data Interchange on 60 mm Read-Only ODC - Capacity: 1,8 Gbytes (UMD™) - // ECMA 371: Data Interchange on 120 mm and 80 mm Optical Disk using +RW HS Format - Capacity 4,7 and 1,46 Gbytes per side - // ECMA 374: Data Interchange on 120 mm and 80 mm Optical Disk using +RW DL Format - Capacity 8,55 and 2,66 Gbytes per side - // ECMA 382: 120 mm (8,54 Gbytes per side) and 80 mm (2,66 Gbytes per side) DVD Recordable Disk for Dual Layer (DVD-R for DL) - // ECMA 384: 120 mm (8,54 Gbytes per side) and 80 mm (2,66 Gbytes per side) DVD Re-recordable Disk for Dual Layer (DVD-RW for DL) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class PFI + public static PhysicalFormatInformation? Decode(byte[] response, MediaType mediaType) { - public static PhysicalFormatInformation? Decode(byte[] response, MediaType mediaType) + if(response == null) + return null; + + if(response.Length == 2048) { - if(response == null) - return null; + byte[] tmp2 = new byte[2052]; + Array.Copy(response, 0, tmp2, 4, 2048); + response = tmp2; + } - if(response.Length == 2048) + if(response.Length < 2052) + return null; + + var pfi = new PhysicalFormatInformation(); + byte[] tmp; + + pfi.DataLength = (ushort)((response[0] << 8) + response[1]); + pfi.Reserved1 = response[2]; + pfi.Reserved2 = response[3]; + + // Common + pfi.DiskCategory = (DiskCategory)((response[4] & 0xF0) >> 4); + pfi.PartVersion = (byte)(response[4] & 0x0F); + pfi.DiscSize = (DVDSize)((response[5] & 0xF0) >> 4); + pfi.MaximumRate = (MaximumRateField)(response[5] & 0x0F); + pfi.Reserved3 |= (response[6] & 0x80) == 0x80; + pfi.Layers = (byte)((response[6] & 0x60) >> 5); + pfi.TrackPath |= (response[6] & 0x08) == 0x08; + pfi.LayerType = (LayerTypeFieldMask)(response[6] & 0x07); + pfi.LinearDensity = (LinearDensityField)((response[7] & 0xF0) >> 4); + pfi.TrackDensity = (TrackDensityField)(response[7] & 0x0F); + + pfi.DataAreaStartPSN = + (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]); + + pfi.DataAreaEndPSN = + (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]); + + pfi.Layer0EndPSN = (uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]); + + pfi.BCA |= (response[20] & 0x80) == 0x80; + + pfi.RecordedBookType = pfi.DiskCategory; + + if(mediaType != MediaType.DVDROM) + { + switch(mediaType) { - byte[] tmp2 = new byte[2052]; - Array.Copy(response, 0, tmp2, 4, 2048); - response = tmp2; + case MediaType.DVDPR: + pfi.DiskCategory = DiskCategory.DVDPR; + + break; + case MediaType.DVDPRDL: + pfi.DiskCategory = DiskCategory.DVDPRDL; + + break; + case MediaType.DVDPRW: + pfi.DiskCategory = DiskCategory.DVDPRW; + + break; + case MediaType.DVDPRWDL: + pfi.DiskCategory = DiskCategory.DVDPRWDL; + + break; + case MediaType.DVDRDL: + pfi.DiskCategory = DiskCategory.DVDR; + + if(pfi.PartVersion < 6) + pfi.PartVersion = 6; + + break; + case MediaType.DVDR: + pfi.DiskCategory = DiskCategory.DVDR; + + if(pfi.PartVersion > 5) + pfi.PartVersion = 5; + + break; + case MediaType.DVDRAM: + pfi.DiskCategory = DiskCategory.DVDRAM; + + break; + case MediaType.DVDRWDL: + pfi.DiskCategory = DiskCategory.DVDRW; + + if(pfi.PartVersion < 15) + pfi.PartVersion = 15; + + break; + case MediaType.DVDRW: + pfi.DiskCategory = DiskCategory.DVDRW; + + if(pfi.PartVersion > 14) + pfi.PartVersion = 14; + + break; + + case MediaType.HDDVDR: + pfi.DiskCategory = DiskCategory.HDDVDR; + + break; + case MediaType.HDDVDRAM: + pfi.DiskCategory = DiskCategory.HDDVDRAM; + + break; + case MediaType.HDDVDROM: + pfi.DiskCategory = DiskCategory.HDDVDROM; + + break; + case MediaType.HDDVDRW: + pfi.DiskCategory = DiskCategory.HDDVDRW; + + break; + case MediaType.GOD: + pfi.DiscSize = DVDSize.Eighty; + pfi.DiskCategory = DiskCategory.Nintendo; + + break; + case MediaType.WOD: + pfi.DiscSize = DVDSize.OneTwenty; + pfi.DiskCategory = DiskCategory.Nintendo; + + break; + case MediaType.UMD: + pfi.DiskCategory = DiskCategory.UMD; + + break; } + } - if(response.Length < 2052) - return null; + switch(pfi.DiskCategory) + { + // UMD + case DiskCategory.UMD: + pfi.MediaAttribute = (ushort)((response[21] << 8) + response[22]); - var pfi = new PhysicalFormatInformation(); - byte[] tmp; + break; - pfi.DataLength = (ushort)((response[0] << 8) + response[1]); - pfi.Reserved1 = response[2]; - pfi.Reserved2 = response[3]; + // DVD-RAM + case DiskCategory.DVDRAM: + pfi.DiscType = (DVDRAMDiscType)response[36]; - // Common - pfi.DiskCategory = (DiskCategory)((response[4] & 0xF0) >> 4); - pfi.PartVersion = (byte)(response[4] & 0x0F); - pfi.DiscSize = (DVDSize)((response[5] & 0xF0) >> 4); - pfi.MaximumRate = (MaximumRateField)(response[5] & 0x0F); - pfi.Reserved3 |= (response[6] & 0x80) == 0x80; - pfi.Layers = (byte)((response[6] & 0x60) >> 5); - pfi.TrackPath |= (response[6] & 0x08) == 0x08; - pfi.LayerType = (LayerTypeFieldMask)(response[6] & 0x07); - pfi.LinearDensity = (LinearDensityField)((response[7] & 0xF0) >> 4); - pfi.TrackDensity = (TrackDensityField)(response[7] & 0x0F); - - pfi.DataAreaStartPSN = - (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]); - - pfi.DataAreaEndPSN = - (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]); - - pfi.Layer0EndPSN = (uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]); - - pfi.BCA |= (response[20] & 0x80) == 0x80; - - pfi.RecordedBookType = pfi.DiskCategory; - - if(mediaType != MediaType.DVDROM) - { - switch(mediaType) + if(pfi.PartVersion == 1) { - case MediaType.DVDPR: - pfi.DiskCategory = DiskCategory.DVDPR; + pfi.Velocity = response[52]; + pfi.ReadPower = response[53]; + pfi.PeakPower = response[54]; + pfi.BiasPower = response[55]; + pfi.FirstPulseStart = response[56]; + pfi.FirstPulseEnd = response[57]; + pfi.MultiPulseDuration = response[58]; + pfi.LastPulseStart = response[59]; + pfi.LastPulseEnd = response[60]; + pfi.BiasPowerDuration = response[61]; + pfi.PeakPowerGroove = response[62]; + pfi.BiasPowerGroove = response[63]; + pfi.FirstPulseStartGroove = response[64]; + pfi.FirstPulseEndGroove = response[65]; + pfi.MultiplePulseDurationGroove = response[66]; + pfi.LastPulseStartGroove = response[67]; + pfi.LastPulseEndGroove = response[68]; + pfi.BiasPowerDurationGroove = response[69]; + } + else if(pfi.PartVersion >= 6) + { + pfi.Velocity = response[504]; + pfi.ReadPower = response[505]; + pfi.AdaptativeWritePulseControlFlag |= (response[506] & 0x80) == 0x80; + pfi.PeakPower = response[507]; + pfi.BiasPower1 = response[508]; + pfi.BiasPower2 = response[509]; + pfi.BiasPower3 = response[510]; + pfi.PeakPowerGroove = response[511]; + pfi.BiasPower1Groove = response[512]; + pfi.BiasPower2Groove = response[513]; + pfi.BiasPower3Groove = response[514]; + pfi.FirstPulseEnd = response[515]; + pfi.FirstPulseDuration = response[516]; + pfi.MultiPulseDuration = response[518]; + pfi.LastPulseStart = response[519]; + pfi.BiasPower2Duration = response[520]; + pfi.FirstPulseStart3TSpace3T = response[521]; + pfi.FirstPulseStart4TSpace3T = response[522]; + pfi.FirstPulseStart5TSpace3T = response[523]; + pfi.FirstPulseStartSpace3T = response[524]; + pfi.FirstPulseStart3TSpace4T = response[525]; + pfi.FirstPulseStart4TSpace4T = response[526]; + pfi.FirstPulseStart5TSpace4T = response[527]; + pfi.FirstPulseStartSpace4T = response[528]; + pfi.FirstPulseStart3TSpace5T = response[529]; + pfi.FirstPulseStart4TSpace5T = response[530]; + pfi.FirstPulseStart5TSpace5T = response[531]; + pfi.FirstPulseStartSpace5T = response[532]; + pfi.FirstPulseStart3TSpace = response[533]; + pfi.FirstPulseStart4TSpace = response[534]; + pfi.FirstPulseStart5TSpace = response[535]; + pfi.FirstPulseStartSpace = response[536]; + pfi.FirstPulse3TStartTSpace3T = response[537]; + pfi.FirstPulse4TStartTSpace3T = response[538]; + pfi.FirstPulse5TStartTSpace3T = response[539]; + pfi.FirstPulseStartTSpace3T = response[540]; + pfi.FirstPulse3TStartTSpace4T = response[541]; + pfi.FirstPulse4TStartTSpace4T = response[542]; + pfi.FirstPulse5TStartTSpace4T = response[543]; + pfi.FirstPulseStartTSpace4T = response[544]; + pfi.FirstPulse3TStartTSpace5T = response[545]; + pfi.FirstPulse4TStartTSpace5T = response[546]; + pfi.FirstPulse5TStartTSpace5T = response[547]; + pfi.FirstPulseStartTSpace5T = response[548]; + pfi.FirstPulse3TStartTSpace = response[549]; + pfi.FirstPulse4TStartTSpace = response[550]; + pfi.FirstPulse5TStartTSpace = response[551]; + pfi.FirstPulseStartTSpace = response[552]; + tmp = new byte[48]; + Array.Copy(response, 553, tmp, 0, 48); + pfi.DiskManufacturer = StringHandlers.SpacePaddedToString(tmp); + tmp = new byte[16]; + Array.Copy(response, 601, tmp, 0, 16); + pfi.DiskManufacturerSupplementary = StringHandlers.SpacePaddedToString(tmp); + pfi.WritePowerControlParams = new byte[2]; + pfi.WritePowerControlParams[0] = response[617]; + pfi.WritePowerControlParams[1] = response[618]; + pfi.PowerRatioLandThreshold = response[619]; + pfi.TargetAsymmetry = response[620]; + pfi.TemporaryPeakPower = response[621]; + pfi.TemporaryBiasPower1 = response[622]; + pfi.TemporaryBiasPower2 = response[623]; + pfi.TemporaryBiasPower3 = response[624]; + pfi.PowerRatioGrooveThreshold = response[625]; + pfi.PowerRatioLandThreshold6T = response[626]; + pfi.PowerRatioGrooveThreshold6T = response[627]; + } + + break; + + // DVD-R and DVD-RW + case DiskCategory.DVDR when pfi.PartVersion < 6: + case DiskCategory.DVDRW when pfi.PartVersion < 15: + pfi.CurrentBorderOutSector = + (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + + pfi.NextBorderInSector = + (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + + break; + + // DVD+RW + case DiskCategory.DVDPRW: + pfi.RecordingVelocity = response[36]; + pfi.ReadPowerMaxVelocity = response[37]; + pfi.PIndMaxVelocity = response[38]; + pfi.PMaxVelocity = response[39]; + pfi.E1MaxVelocity = response[40]; + pfi.E2MaxVelocity = response[41]; + pfi.YTargetMaxVelocity = response[42]; + pfi.ReadPowerRefVelocity = response[43]; + pfi.PIndRefVelocity = response[44]; + pfi.PRefVelocity = response[45]; + pfi.E1RefVelocity = response[46]; + pfi.E2RefVelocity = response[47]; + pfi.YTargetRefVelocity = response[48]; + pfi.ReadPowerMinVelocity = response[49]; + pfi.PIndMinVelocity = response[50]; + pfi.PMinVelocity = response[51]; + pfi.E1MinVelocity = response[52]; + pfi.E2MinVelocity = response[53]; + pfi.YTargetMinVelocity = response[54]; + + break; + } + + // DVD+R, DVD+RW, DVD+R DL and DVD+RW DL + if(pfi.DiskCategory == DiskCategory.DVDPR || + pfi.DiskCategory == DiskCategory.DVDPRW || + pfi.DiskCategory == DiskCategory.DVDPRDL || + pfi.DiskCategory == DiskCategory.DVDPRWDL) + { + pfi.VCPS |= (response[20] & 0x40) == 0x40; + pfi.ApplicationCode = response[21]; + pfi.ExtendedInformation = response[22]; + tmp = new byte[8]; + Array.Copy(response, 23, tmp, 0, 8); + pfi.DiskManufacturerID = StringHandlers.CToString(tmp); + tmp = new byte[3]; + Array.Copy(response, 31, tmp, 0, 3); + pfi.MediaTypeID = StringHandlers.CToString(tmp); + + pfi.ProductRevision = pfi.DiskCategory == DiskCategory.DVDPRDL ? (byte)(response[34] & 0x3F) + : response[34]; + + pfi.PFIUsedInADIP = response[35]; + } + + switch(pfi.DiskCategory) + { + // DVD+RW + case DiskCategory.DVDPRW when pfi.PartVersion == 2: + pfi.TopFirstPulseDuration = response[55]; + pfi.MultiPulseDuration = response[56]; + pfi.FirstPulseLeadTime = response[57]; + pfi.EraseLeadTimeRefVelocity = response[58]; + pfi.EraseLeadTimeUppVelocity = response[59]; + + break; + + // DVD+R and DVD+R DL + case DiskCategory.DVDPR: + case DiskCategory.DVDPRDL: + pfi.PrimaryVelocity = response[36]; + pfi.UpperVelocity = response[37]; + pfi.Wavelength = response[38]; + pfi.NormalizedPowerDependency = response[39]; + pfi.MaximumPowerAtPrimaryVelocity = response[40]; + pfi.PindAtPrimaryVelocity = response[41]; + pfi.BtargetAtPrimaryVelocity = response[42]; + pfi.MaximumPowerAtUpperVelocity = response[43]; + pfi.PindAtUpperVelocity = response[44]; + pfi.BtargetAtUpperVelocity = response[45]; + pfi.FirstPulseDuration4TPrimaryVelocity = response[46]; + pfi.FirstPulseDuration3TPrimaryVelocity = response[47]; + pfi.MultiPulseDurationPrimaryVelocity = response[48]; + pfi.LastPulseDurationPrimaryVelocity = response[49]; + pfi.FirstPulseLeadTime4TPrimaryVelocity = response[50]; + pfi.FirstPulseLeadTime3TPrimaryVelocity = response[51]; + pfi.FirstPulseLeadingEdgePrimaryVelocity = response[52]; + pfi.FirstPulseDuration4TUpperVelocity = response[53]; + pfi.FirstPulseDuration3TUpperVelocity = response[54]; + pfi.MultiPulseDurationUpperVelocity = response[55]; + pfi.LastPulseDurationUpperVelocity = response[56]; + pfi.FirstPulseLeadTime4TUpperVelocity = response[57]; + pfi.FirstPulseLeadTime3TUpperVelocity = response[58]; + pfi.FirstPulseLeadingEdgeUpperVelocity = response[59]; + + break; + } + + switch(pfi.DiskCategory) + { + // DVD+R DL + case DiskCategory.DVDPRDL: + pfi.LayerStructure = (DVDLayerStructure)((response[34] & 0xC0) >> 6); + + break; + + // DVD+RW DL + case DiskCategory.DVDPRWDL: + pfi.BasicPrimaryVelocity = response[36]; + pfi.MaxReadPowerPrimaryVelocity = response[37]; + pfi.PindPrimaryVelocity = response[38]; + pfi.PPrimaryVelocity = response[39]; + pfi.E1PrimaryVelocity = response[40]; + pfi.E2PrimaryVelocity = response[41]; + pfi.YtargetPrimaryVelocity = response[42]; + pfi.BOptimumPrimaryVelocity = response[43]; + pfi.TFirstPulseDuration = response[46]; + pfi.TMultiPulseDuration = response[47]; + pfi.FirstPulseLeadTimeAnyRun = response[48]; + pfi.FirstPulseLeadTimeRun3T = response[49]; + pfi.LastPulseLeadTimeAnyRun = response[50]; + pfi.LastPulseLeadTime3T = response[51]; + pfi.LastPulseLeadTime4T = response[52]; + pfi.ErasePulseLeadTimeAny = response[53]; + pfi.ErasePulseLeadTime3T = response[54]; + pfi.ErasePulseLeadTime4T = response[55]; + + break; + + // DVD-R DL and DVD-RW DL + case DiskCategory.DVDR when pfi.PartVersion >= 6: + case DiskCategory.DVDRW when pfi.PartVersion >= 15: + pfi.MaxRecordingSpeed = (DVDRecordingSpeed)response[21]; + pfi.MinRecordingSpeed = (DVDRecordingSpeed)response[22]; + pfi.RecordingSpeed1 = (DVDRecordingSpeed)response[23]; + pfi.RecordingSpeed2 = (DVDRecordingSpeed)response[24]; + pfi.RecordingSpeed3 = (DVDRecordingSpeed)response[25]; + pfi.RecordingSpeed4 = (DVDRecordingSpeed)response[26]; + pfi.RecordingSpeed5 = (DVDRecordingSpeed)response[27]; + pfi.RecordingSpeed6 = (DVDRecordingSpeed)response[28]; + pfi.RecordingSpeed7 = (DVDRecordingSpeed)response[29]; + pfi.Class = response[30]; + pfi.ExtendedVersion = response[31]; + + pfi.CurrentBorderOutSector = + (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + + pfi.NextBorderInSector = + (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + + pfi.PreRecordedControlDataInv |= (response[44] & 0x01) == 0x01; + pfi.PreRecordedLeadIn |= (response[44] & 0x02) == 0x02; + pfi.PreRecordedLeadOut |= (response[44] & 0x08) == 0x08; + pfi.ARCharLayer1 = (byte)(response[45] & 0x0F); + pfi.TrackPolarityLayer1 = (byte)((response[45] & 0xF0) >> 4); + + break; + } + + return pfi; + } + + public static string Prettify(PhysicalFormatInformation? pfi) + { + if(pfi == null) + return null; + + PhysicalFormatInformation decoded = pfi.Value; + var sb = new StringBuilder(); + + string sizeString; + + switch(decoded.DiscSize) + { + case DVDSize.Eighty: + sizeString = "80mm"; + + break; + case DVDSize.OneTwenty: + sizeString = "120mm"; + + break; + default: + sizeString = $"unknown size identifier {decoded.DiscSize}"; + + break; + } + + string categorySentence = "Disc is a {0} {1} version {2}"; + + switch(decoded.DiskCategory) + { + case DiskCategory.DVDROM: + sb.AppendFormat(categorySentence, sizeString, "DVD-ROM", decoded.PartVersion).AppendLine(); + + switch(decoded.DiscSize) + { + case DVDSize.OneTwenty when decoded.PartVersion == 1: + sb.AppendLine("Disc claims conformation to ECMA-267"); break; - case MediaType.DVDPRDL: - pfi.DiskCategory = DiskCategory.DVDPRDL; - - break; - case MediaType.DVDPRW: - pfi.DiskCategory = DiskCategory.DVDPRW; - - break; - case MediaType.DVDPRWDL: - pfi.DiskCategory = DiskCategory.DVDPRWDL; - - break; - case MediaType.DVDRDL: - pfi.DiskCategory = DiskCategory.DVDR; - - if(pfi.PartVersion < 6) - pfi.PartVersion = 6; - - break; - case MediaType.DVDR: - pfi.DiskCategory = DiskCategory.DVDR; - - if(pfi.PartVersion > 5) - pfi.PartVersion = 5; - - break; - case MediaType.DVDRAM: - pfi.DiskCategory = DiskCategory.DVDRAM; - - break; - case MediaType.DVDRWDL: - pfi.DiskCategory = DiskCategory.DVDRW; - - if(pfi.PartVersion < 15) - pfi.PartVersion = 15; - - break; - case MediaType.DVDRW: - pfi.DiskCategory = DiskCategory.DVDRW; - - if(pfi.PartVersion > 14) - pfi.PartVersion = 14; - - break; - - case MediaType.HDDVDR: - pfi.DiskCategory = DiskCategory.HDDVDR; - - break; - case MediaType.HDDVDRAM: - pfi.DiskCategory = DiskCategory.HDDVDRAM; - - break; - case MediaType.HDDVDROM: - pfi.DiskCategory = DiskCategory.HDDVDROM; - - break; - case MediaType.HDDVDRW: - pfi.DiskCategory = DiskCategory.HDDVDRW; - - break; - case MediaType.GOD: - pfi.DiscSize = DVDSize.Eighty; - pfi.DiskCategory = DiskCategory.Nintendo; - - break; - case MediaType.WOD: - pfi.DiscSize = DVDSize.OneTwenty; - pfi.DiskCategory = DiskCategory.Nintendo; - - break; - case MediaType.UMD: - pfi.DiskCategory = DiskCategory.UMD; + case DVDSize.Eighty when decoded.PartVersion == 1: + sb.AppendLine("Disc claims conformation to ECMA-268"); break; } - } - switch(pfi.DiskCategory) - { - // UMD - case DiskCategory.UMD: - pfi.MediaAttribute = (ushort)((response[21] << 8) + response[22]); + break; + case DiskCategory.DVDRAM: + sb.AppendFormat(categorySentence, sizeString, "DVD-RAM", decoded.PartVersion).AppendLine(); - break; + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine("Disc claims conformation to ECMA-272"); - // DVD-RAM - case DiskCategory.DVDRAM: - pfi.DiscType = (DVDRAMDiscType)response[36]; + break; + case 6: + sb.AppendLine("Disc claims conformation to ECMA-330"); - if(pfi.PartVersion == 1) - { - pfi.Velocity = response[52]; - pfi.ReadPower = response[53]; - pfi.PeakPower = response[54]; - pfi.BiasPower = response[55]; - pfi.FirstPulseStart = response[56]; - pfi.FirstPulseEnd = response[57]; - pfi.MultiPulseDuration = response[58]; - pfi.LastPulseStart = response[59]; - pfi.LastPulseEnd = response[60]; - pfi.BiasPowerDuration = response[61]; - pfi.PeakPowerGroove = response[62]; - pfi.BiasPowerGroove = response[63]; - pfi.FirstPulseStartGroove = response[64]; - pfi.FirstPulseEndGroove = response[65]; - pfi.MultiplePulseDurationGroove = response[66]; - pfi.LastPulseStartGroove = response[67]; - pfi.LastPulseEndGroove = response[68]; - pfi.BiasPowerDurationGroove = response[69]; - } - else if(pfi.PartVersion >= 6) - { - pfi.Velocity = response[504]; - pfi.ReadPower = response[505]; - pfi.AdaptativeWritePulseControlFlag |= (response[506] & 0x80) == 0x80; - pfi.PeakPower = response[507]; - pfi.BiasPower1 = response[508]; - pfi.BiasPower2 = response[509]; - pfi.BiasPower3 = response[510]; - pfi.PeakPowerGroove = response[511]; - pfi.BiasPower1Groove = response[512]; - pfi.BiasPower2Groove = response[513]; - pfi.BiasPower3Groove = response[514]; - pfi.FirstPulseEnd = response[515]; - pfi.FirstPulseDuration = response[516]; - pfi.MultiPulseDuration = response[518]; - pfi.LastPulseStart = response[519]; - pfi.BiasPower2Duration = response[520]; - pfi.FirstPulseStart3TSpace3T = response[521]; - pfi.FirstPulseStart4TSpace3T = response[522]; - pfi.FirstPulseStart5TSpace3T = response[523]; - pfi.FirstPulseStartSpace3T = response[524]; - pfi.FirstPulseStart3TSpace4T = response[525]; - pfi.FirstPulseStart4TSpace4T = response[526]; - pfi.FirstPulseStart5TSpace4T = response[527]; - pfi.FirstPulseStartSpace4T = response[528]; - pfi.FirstPulseStart3TSpace5T = response[529]; - pfi.FirstPulseStart4TSpace5T = response[530]; - pfi.FirstPulseStart5TSpace5T = response[531]; - pfi.FirstPulseStartSpace5T = response[532]; - pfi.FirstPulseStart3TSpace = response[533]; - pfi.FirstPulseStart4TSpace = response[534]; - pfi.FirstPulseStart5TSpace = response[535]; - pfi.FirstPulseStartSpace = response[536]; - pfi.FirstPulse3TStartTSpace3T = response[537]; - pfi.FirstPulse4TStartTSpace3T = response[538]; - pfi.FirstPulse5TStartTSpace3T = response[539]; - pfi.FirstPulseStartTSpace3T = response[540]; - pfi.FirstPulse3TStartTSpace4T = response[541]; - pfi.FirstPulse4TStartTSpace4T = response[542]; - pfi.FirstPulse5TStartTSpace4T = response[543]; - pfi.FirstPulseStartTSpace4T = response[544]; - pfi.FirstPulse3TStartTSpace5T = response[545]; - pfi.FirstPulse4TStartTSpace5T = response[546]; - pfi.FirstPulse5TStartTSpace5T = response[547]; - pfi.FirstPulseStartTSpace5T = response[548]; - pfi.FirstPulse3TStartTSpace = response[549]; - pfi.FirstPulse4TStartTSpace = response[550]; - pfi.FirstPulse5TStartTSpace = response[551]; - pfi.FirstPulseStartTSpace = response[552]; - tmp = new byte[48]; - Array.Copy(response, 553, tmp, 0, 48); - pfi.DiskManufacturer = StringHandlers.SpacePaddedToString(tmp); - tmp = new byte[16]; - Array.Copy(response, 601, tmp, 0, 16); - pfi.DiskManufacturerSupplementary = StringHandlers.SpacePaddedToString(tmp); - pfi.WritePowerControlParams = new byte[2]; - pfi.WritePowerControlParams[0] = response[617]; - pfi.WritePowerControlParams[1] = response[618]; - pfi.PowerRatioLandThreshold = response[619]; - pfi.TargetAsymmetry = response[620]; - pfi.TemporaryPeakPower = response[621]; - pfi.TemporaryBiasPower1 = response[622]; - pfi.TemporaryBiasPower2 = response[623]; - pfi.TemporaryBiasPower3 = response[624]; - pfi.PowerRatioGrooveThreshold = response[625]; - pfi.PowerRatioLandThreshold6T = response[626]; - pfi.PowerRatioGrooveThreshold6T = response[627]; - } + break; + } - break; + break; + case DiskCategory.DVDR: + if(decoded.PartVersion >= 6) + sb.AppendFormat(categorySentence, sizeString, "DVD-R DL", decoded.PartVersion).AppendLine(); + else + sb.AppendFormat(categorySentence, sizeString, "DVD-R", decoded.PartVersion).AppendLine(); - // DVD-R and DVD-RW - case DiskCategory.DVDR when pfi.PartVersion < 6: - case DiskCategory.DVDRW when pfi.PartVersion < 15: - pfi.CurrentBorderOutSector = - (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine("Disc claims conformation to ECMA-279"); - pfi.NextBorderInSector = - (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + break; + case 5: + sb.AppendLine("Disc claims conformation to ECMA-359"); - break; + break; + case 6: + sb.AppendLine("Disc claims conformation to ECMA-382"); - // DVD+RW - case DiskCategory.DVDPRW: - pfi.RecordingVelocity = response[36]; - pfi.ReadPowerMaxVelocity = response[37]; - pfi.PIndMaxVelocity = response[38]; - pfi.PMaxVelocity = response[39]; - pfi.E1MaxVelocity = response[40]; - pfi.E2MaxVelocity = response[41]; - pfi.YTargetMaxVelocity = response[42]; - pfi.ReadPowerRefVelocity = response[43]; - pfi.PIndRefVelocity = response[44]; - pfi.PRefVelocity = response[45]; - pfi.E1RefVelocity = response[46]; - pfi.E2RefVelocity = response[47]; - pfi.YTargetRefVelocity = response[48]; - pfi.ReadPowerMinVelocity = response[49]; - pfi.PIndMinVelocity = response[50]; - pfi.PMinVelocity = response[51]; - pfi.E1MinVelocity = response[52]; - pfi.E2MinVelocity = response[53]; - pfi.YTargetMinVelocity = response[54]; + break; + } - break; - } + break; + case DiskCategory.DVDRW: + if(decoded.PartVersion >= 15) + sb.AppendFormat(categorySentence, sizeString, "DVD-RW DL", decoded.PartVersion).AppendLine(); + else + sb.AppendFormat(categorySentence, sizeString, "DVD-RW", decoded.PartVersion).AppendLine(); - // DVD+R, DVD+RW, DVD+R DL and DVD+RW DL - if(pfi.DiskCategory == DiskCategory.DVDPR || - pfi.DiskCategory == DiskCategory.DVDPRW || - pfi.DiskCategory == DiskCategory.DVDPRDL || - pfi.DiskCategory == DiskCategory.DVDPRWDL) - { - pfi.VCPS |= (response[20] & 0x40) == 0x40; - pfi.ApplicationCode = response[21]; - pfi.ExtendedInformation = response[22]; - tmp = new byte[8]; - Array.Copy(response, 23, tmp, 0, 8); - pfi.DiskManufacturerID = StringHandlers.CToString(tmp); - tmp = new byte[3]; - Array.Copy(response, 31, tmp, 0, 3); - pfi.MediaTypeID = StringHandlers.CToString(tmp); + switch(decoded.PartVersion) + { + case 2: + sb.AppendLine("Disc claims conformation to ECMA-338"); - pfi.ProductRevision = pfi.DiskCategory == DiskCategory.DVDPRDL ? (byte)(response[34] & 0x3F) - : response[34]; + break; + case 3: + sb.AppendLine("Disc claims conformation to ECMA-384"); - pfi.PFIUsedInADIP = response[35]; - } + break; + } - switch(pfi.DiskCategory) - { - // DVD+RW - case DiskCategory.DVDPRW when pfi.PartVersion == 2: - pfi.TopFirstPulseDuration = response[55]; - pfi.MultiPulseDuration = response[56]; - pfi.FirstPulseLeadTime = response[57]; - pfi.EraseLeadTimeRefVelocity = response[58]; - pfi.EraseLeadTimeUppVelocity = response[59]; + break; + case DiskCategory.UMD: + if(decoded.DiscSize == DVDSize.OneTwenty) + sb.AppendFormat(categorySentence, "60mm", "UMD", decoded.PartVersion).AppendLine(); + else + sb.AppendFormat(categorySentence, "invalid size", "UMD", decoded.PartVersion).AppendLine(); - break; + switch(decoded.PartVersion) + { + case 0: + sb.AppendLine("Disc claims conformation to ECMA-365"); - // DVD+R and DVD+R DL - case DiskCategory.DVDPR: - case DiskCategory.DVDPRDL: - pfi.PrimaryVelocity = response[36]; - pfi.UpperVelocity = response[37]; - pfi.Wavelength = response[38]; - pfi.NormalizedPowerDependency = response[39]; - pfi.MaximumPowerAtPrimaryVelocity = response[40]; - pfi.PindAtPrimaryVelocity = response[41]; - pfi.BtargetAtPrimaryVelocity = response[42]; - pfi.MaximumPowerAtUpperVelocity = response[43]; - pfi.PindAtUpperVelocity = response[44]; - pfi.BtargetAtUpperVelocity = response[45]; - pfi.FirstPulseDuration4TPrimaryVelocity = response[46]; - pfi.FirstPulseDuration3TPrimaryVelocity = response[47]; - pfi.MultiPulseDurationPrimaryVelocity = response[48]; - pfi.LastPulseDurationPrimaryVelocity = response[49]; - pfi.FirstPulseLeadTime4TPrimaryVelocity = response[50]; - pfi.FirstPulseLeadTime3TPrimaryVelocity = response[51]; - pfi.FirstPulseLeadingEdgePrimaryVelocity = response[52]; - pfi.FirstPulseDuration4TUpperVelocity = response[53]; - pfi.FirstPulseDuration3TUpperVelocity = response[54]; - pfi.MultiPulseDurationUpperVelocity = response[55]; - pfi.LastPulseDurationUpperVelocity = response[56]; - pfi.FirstPulseLeadTime4TUpperVelocity = response[57]; - pfi.FirstPulseLeadTime3TUpperVelocity = response[58]; - pfi.FirstPulseLeadingEdgeUpperVelocity = response[59]; + break; + } - break; - } + break; + case DiskCategory.DVDPRW: + sb.AppendFormat(categorySentence, sizeString, "DVD+RW", decoded.PartVersion).AppendLine(); - switch(pfi.DiskCategory) - { - // DVD+R DL - case DiskCategory.DVDPRDL: - pfi.LayerStructure = (DVDLayerStructure)((response[34] & 0xC0) >> 6); + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine("Disc claims conformation to ECMA-274"); - break; + break; + case 2: + sb.AppendLine("Disc claims conformation to ECMA-337"); - // DVD+RW DL - case DiskCategory.DVDPRWDL: - pfi.BasicPrimaryVelocity = response[36]; - pfi.MaxReadPowerPrimaryVelocity = response[37]; - pfi.PindPrimaryVelocity = response[38]; - pfi.PPrimaryVelocity = response[39]; - pfi.E1PrimaryVelocity = response[40]; - pfi.E2PrimaryVelocity = response[41]; - pfi.YtargetPrimaryVelocity = response[42]; - pfi.BOptimumPrimaryVelocity = response[43]; - pfi.TFirstPulseDuration = response[46]; - pfi.TMultiPulseDuration = response[47]; - pfi.FirstPulseLeadTimeAnyRun = response[48]; - pfi.FirstPulseLeadTimeRun3T = response[49]; - pfi.LastPulseLeadTimeAnyRun = response[50]; - pfi.LastPulseLeadTime3T = response[51]; - pfi.LastPulseLeadTime4T = response[52]; - pfi.ErasePulseLeadTimeAny = response[53]; - pfi.ErasePulseLeadTime3T = response[54]; - pfi.ErasePulseLeadTime4T = response[55]; + break; + case 3: + sb.AppendLine("Disc claims conformation to ECMA-371"); - break; + break; + } - // DVD-R DL and DVD-RW DL - case DiskCategory.DVDR when pfi.PartVersion >= 6: - case DiskCategory.DVDRW when pfi.PartVersion >= 15: - pfi.MaxRecordingSpeed = (DVDRecordingSpeed)response[21]; - pfi.MinRecordingSpeed = (DVDRecordingSpeed)response[22]; - pfi.RecordingSpeed1 = (DVDRecordingSpeed)response[23]; - pfi.RecordingSpeed2 = (DVDRecordingSpeed)response[24]; - pfi.RecordingSpeed3 = (DVDRecordingSpeed)response[25]; - pfi.RecordingSpeed4 = (DVDRecordingSpeed)response[26]; - pfi.RecordingSpeed5 = (DVDRecordingSpeed)response[27]; - pfi.RecordingSpeed6 = (DVDRecordingSpeed)response[28]; - pfi.RecordingSpeed7 = (DVDRecordingSpeed)response[29]; - pfi.Class = response[30]; - pfi.ExtendedVersion = response[31]; + break; + case DiskCategory.DVDPR: + sb.AppendFormat(categorySentence, sizeString, "DVD+R", decoded.PartVersion).AppendLine(); - pfi.CurrentBorderOutSector = - (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine("Disc claims conformation to ECMA-349"); - pfi.NextBorderInSector = - (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + break; + } - pfi.PreRecordedControlDataInv |= (response[44] & 0x01) == 0x01; - pfi.PreRecordedLeadIn |= (response[44] & 0x02) == 0x02; - pfi.PreRecordedLeadOut |= (response[44] & 0x08) == 0x08; - pfi.ARCharLayer1 = (byte)(response[45] & 0x0F); - pfi.TrackPolarityLayer1 = (byte)((response[45] & 0xF0) >> 4); + break; + case DiskCategory.DVDPRWDL: + sb.AppendFormat(categorySentence, sizeString, "DVD+RW DL", decoded.PartVersion).AppendLine(); - break; - } + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine("Disc claims conformation to ECMA-374"); - return pfi; + break; + } + + break; + case DiskCategory.DVDPRDL: + sb.AppendFormat(categorySentence, sizeString, "DVD+R DL", decoded.PartVersion).AppendLine(); + + switch(decoded.PartVersion) + { + case 1: + sb.AppendLine("Disc claims conformation to ECMA-364"); + + break; + } + + break; + case DiskCategory.Nintendo: + if(decoded.PartVersion == 15) + if(decoded.DiscSize == DVDSize.Eighty) + sb.AppendLine("Disc is a Nintendo Gamecube Optical Disc (GOD)"); + else if(decoded.DiscSize == DVDSize.OneTwenty) + sb.AppendLine("Disc is a Nintendo Wii Optical Disc (WOD)"); + else + goto default; + else + goto default; + + break; + case DiskCategory.HDDVDROM: + sb.AppendFormat(categorySentence, sizeString, "HD DVD-ROM", decoded.PartVersion).AppendLine(); + + break; + case DiskCategory.HDDVDRAM: + sb.AppendFormat(categorySentence, sizeString, "HD DVD-RAM", decoded.PartVersion).AppendLine(); + + break; + case DiskCategory.HDDVDR: + sb.AppendFormat(categorySentence, sizeString, "HD DVD-R", decoded.PartVersion).AppendLine(); + + break; + case DiskCategory.HDDVDRW: + sb.AppendFormat(categorySentence, sizeString, "HD DVD-RW", decoded.PartVersion).AppendLine(); + + break; + default: + sb.AppendFormat(categorySentence, sizeString, "unknown disc type", decoded.PartVersion). + AppendLine(); + + break; } - public static string Prettify(PhysicalFormatInformation? pfi) + if(decoded.RecordedBookType != decoded.DiskCategory) { - if(pfi == null) - return null; + string bookTypeSentence = "Disc book type is {0}"; - PhysicalFormatInformation decoded = pfi.Value; - var sb = new StringBuilder(); - - string sizeString; - - switch(decoded.DiscSize) - { - case DVDSize.Eighty: - sizeString = "80mm"; - - break; - case DVDSize.OneTwenty: - sizeString = "120mm"; - - break; - default: - sizeString = $"unknown size identifier {decoded.DiscSize}"; - - break; - } - - string categorySentence = "Disc is a {0} {1} version {2}"; - - switch(decoded.DiskCategory) + switch(decoded.RecordedBookType) { case DiskCategory.DVDROM: - sb.AppendFormat(categorySentence, sizeString, "DVD-ROM", decoded.PartVersion).AppendLine(); - - switch(decoded.DiscSize) - { - case DVDSize.OneTwenty when decoded.PartVersion == 1: - sb.AppendLine("Disc claims conformation to ECMA-267"); - - break; - case DVDSize.Eighty when decoded.PartVersion == 1: - sb.AppendLine("Disc claims conformation to ECMA-268"); - - break; - } + sb.AppendFormat(bookTypeSentence, "DVD-ROM").AppendLine(); break; case DiskCategory.DVDRAM: - sb.AppendFormat(categorySentence, sizeString, "DVD-RAM", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 1: - sb.AppendLine("Disc claims conformation to ECMA-272"); - - break; - case 6: - sb.AppendLine("Disc claims conformation to ECMA-330"); - - break; - } + sb.AppendFormat(bookTypeSentence, "DVD-RAM").AppendLine(); break; case DiskCategory.DVDR: if(decoded.PartVersion >= 6) - sb.AppendFormat(categorySentence, sizeString, "DVD-R DL", decoded.PartVersion).AppendLine(); + sb.AppendFormat(bookTypeSentence, "DVD-R DL").AppendLine(); else - sb.AppendFormat(categorySentence, sizeString, "DVD-R", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 1: - sb.AppendLine("Disc claims conformation to ECMA-279"); - - break; - case 5: - sb.AppendLine("Disc claims conformation to ECMA-359"); - - break; - case 6: - sb.AppendLine("Disc claims conformation to ECMA-382"); - - break; - } + sb.AppendFormat(bookTypeSentence, "DVD-R").AppendLine(); break; case DiskCategory.DVDRW: if(decoded.PartVersion >= 15) - sb.AppendFormat(categorySentence, sizeString, "DVD-RW DL", decoded.PartVersion).AppendLine(); + sb.AppendFormat(bookTypeSentence, "DVD-RW DL").AppendLine(); else - sb.AppendFormat(categorySentence, sizeString, "DVD-RW", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 2: - sb.AppendLine("Disc claims conformation to ECMA-338"); - - break; - case 3: - sb.AppendLine("Disc claims conformation to ECMA-384"); - - break; - } + sb.AppendFormat(bookTypeSentence, "DVD-RW").AppendLine(); break; case DiskCategory.UMD: - if(decoded.DiscSize == DVDSize.OneTwenty) - sb.AppendFormat(categorySentence, "60mm", "UMD", decoded.PartVersion).AppendLine(); - else - sb.AppendFormat(categorySentence, "invalid size", "UMD", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 0: - sb.AppendLine("Disc claims conformation to ECMA-365"); - - break; - } + sb.AppendFormat(bookTypeSentence, "UMD").AppendLine(); break; case DiskCategory.DVDPRW: - sb.AppendFormat(categorySentence, sizeString, "DVD+RW", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 1: - sb.AppendLine("Disc claims conformation to ECMA-274"); - - break; - case 2: - sb.AppendLine("Disc claims conformation to ECMA-337"); - - break; - case 3: - sb.AppendLine("Disc claims conformation to ECMA-371"); - - break; - } + sb.AppendFormat(bookTypeSentence, "DVD+RW").AppendLine(); break; case DiskCategory.DVDPR: - sb.AppendFormat(categorySentence, sizeString, "DVD+R", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 1: - sb.AppendLine("Disc claims conformation to ECMA-349"); - - break; - } + sb.AppendFormat(bookTypeSentence, "DVD+R").AppendLine(); break; case DiskCategory.DVDPRWDL: - sb.AppendFormat(categorySentence, sizeString, "DVD+RW DL", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 1: - sb.AppendLine("Disc claims conformation to ECMA-374"); - - break; - } + sb.AppendFormat(bookTypeSentence, "DVD+RW DL").AppendLine(); break; case DiskCategory.DVDPRDL: - sb.AppendFormat(categorySentence, sizeString, "DVD+R DL", decoded.PartVersion).AppendLine(); - - switch(decoded.PartVersion) - { - case 1: - sb.AppendLine("Disc claims conformation to ECMA-364"); - - break; - } - - break; - case DiskCategory.Nintendo: - if(decoded.PartVersion == 15) - if(decoded.DiscSize == DVDSize.Eighty) - sb.AppendLine("Disc is a Nintendo Gamecube Optical Disc (GOD)"); - else if(decoded.DiscSize == DVDSize.OneTwenty) - sb.AppendLine("Disc is a Nintendo Wii Optical Disc (WOD)"); - else - goto default; - else - goto default; + sb.AppendFormat(bookTypeSentence, "DVD+R DL").AppendLine(); break; case DiskCategory.HDDVDROM: - sb.AppendFormat(categorySentence, sizeString, "HD DVD-ROM", decoded.PartVersion).AppendLine(); + sb.AppendFormat(bookTypeSentence, "HD DVD-ROM").AppendLine(); break; case DiskCategory.HDDVDRAM: - sb.AppendFormat(categorySentence, sizeString, "HD DVD-RAM", decoded.PartVersion).AppendLine(); + sb.AppendFormat(bookTypeSentence, "HD DVD-RAM").AppendLine(); break; case DiskCategory.HDDVDR: - sb.AppendFormat(categorySentence, sizeString, "HD DVD-R", decoded.PartVersion).AppendLine(); + sb.AppendFormat(bookTypeSentence, "HD DVD-R").AppendLine(); break; case DiskCategory.HDDVDRW: - sb.AppendFormat(categorySentence, sizeString, "HD DVD-RW", decoded.PartVersion).AppendLine(); + sb.AppendFormat(bookTypeSentence, "HD DVD-RW").AppendLine(); break; default: - sb.AppendFormat(categorySentence, sizeString, "unknown disc type", decoded.PartVersion). - AppendLine(); + sb.AppendFormat(bookTypeSentence, "unknown").AppendLine(); break; } + } - if(decoded.RecordedBookType != decoded.DiskCategory) + switch(decoded.MaximumRate) + { + case MaximumRateField.TwoMbps: + sb.AppendLine("Disc maximum transfer rate is 2,52 Mbit/sec."); + + break; + case MaximumRateField.FiveMbps: + sb.AppendLine("Disc maximum transfer rate is 5,04 Mbit/sec."); + + break; + case MaximumRateField.TenMbps: + sb.AppendLine("Disc maximum transfer rate is 10,08 Mbit/sec."); + + break; + case MaximumRateField.TwentyMbps: + sb.AppendLine("Disc maximum transfer rate is 20,16 Mbit/sec."); + + break; + case MaximumRateField.ThirtyMbps: + sb.AppendLine("Disc maximum transfer rate is 30,24 Mbit/sec."); + + break; + case MaximumRateField.Unspecified: + sb.AppendLine("Disc maximum transfer rate is unspecified."); + + break; + default: + sb.AppendFormat("Disc maximum transfer rate is specified by unknown key {0}", decoded.MaximumRate). + AppendLine(); + + break; + } + + sb.AppendFormat("Disc has {0} layers", decoded.Layers + 1).AppendLine(); + + if(decoded.TrackPath && + decoded.Layers == 1) + sb.AppendLine("Layers are in parallel track path"); + else if(!decoded.TrackPath && + decoded.Layers == 1) + sb.AppendLine("Layers are in opposite track path"); + + switch(decoded.LinearDensity) + { + case LinearDensityField.TwoSix: + sb.AppendLine("Pitch size is 0,267 μm/bit"); + + break; + case LinearDensityField.TwoNine: + sb.AppendLine("Pitch size is 0,147 μm/bit"); + + break; + case LinearDensityField.FourZero: + sb.AppendLine("Pitch size is between 0,409 μm/bit and 0,435 μm/bit"); + + break; + case LinearDensityField.TwoEight: + sb.AppendLine("Pitch size is between 0,140 μm/bit and 0,148 μm/bit"); + + break; + case LinearDensityField.OneFive: + sb.AppendLine("Pitch size is 0,153 μm/bit"); + + break; + case LinearDensityField.OneThree: + sb.AppendLine("Pitch size is between 0,130 μm/bit and 0,140 μm/bit"); + + break; + case LinearDensityField.ThreeFive: + sb.AppendLine("Pitch size is 0,353 μm/bit"); + + break; + default: + sb.AppendFormat("Unknown pitch size key {0}", decoded.LinearDensity).AppendLine(); + + break; + } + + switch(decoded.TrackDensity) + { + case TrackDensityField.Seven: + sb.AppendLine("Track size is 0,74 μm"); + + break; + case TrackDensityField.Eight: + sb.AppendLine("Track size is 0,80 μm"); + + break; + case TrackDensityField.Six: + sb.AppendLine("Track size is 0,615 μm"); + + break; + case TrackDensityField.Four: + sb.AppendLine("Track size is 0,40 μm"); + + break; + case TrackDensityField.Three: + sb.AppendLine("Track size is 0,34 μm"); + + break; + default: + sb.AppendFormat("Unknown track size key {0}", decoded.LinearDensity).AppendLine(); + + break; + } + + if(decoded.DataAreaStartPSN > 0) + if(decoded.DataAreaEndPSN > 0) { - string bookTypeSentence = "Disc book type is {0}"; + sb.AppendFormat("Data area starts at PSN {0:X}h", decoded.DataAreaStartPSN).AppendLine(); + sb.AppendFormat("Data area ends at PSN {0:X}h", decoded.DataAreaEndPSN).AppendLine(); - switch(decoded.RecordedBookType) + if(decoded.Layers == 1 && + !decoded.TrackPath) + sb.AppendFormat("Layer 0 ends at PSN {0:X}h", decoded.Layer0EndPSN).AppendLine(); + } + else + sb.AppendLine("Disc is empty"); + else + sb.AppendLine("Disc is empty"); + + if(decoded.BCA) + sb.AppendLine("Disc has a burst cutting area"); + + switch(decoded.DiskCategory) + { + case DiskCategory.UMD: + sb.AppendFormat("Media attribute is {0}", decoded.MediaAttribute).AppendLine(); + + break; + case DiskCategory.DVDRAM: + switch(decoded.DiscType) { - case DiskCategory.DVDROM: - sb.AppendFormat(bookTypeSentence, "DVD-ROM").AppendLine(); + case DVDRAMDiscType.Cased: + sb.AppendLine("Disc shall be recorded with a case"); break; - case DiskCategory.DVDRAM: - sb.AppendFormat(bookTypeSentence, "DVD-RAM").AppendLine(); - - break; - case DiskCategory.DVDR: - if(decoded.PartVersion >= 6) - sb.AppendFormat(bookTypeSentence, "DVD-R DL").AppendLine(); - else - sb.AppendFormat(bookTypeSentence, "DVD-R").AppendLine(); - - break; - case DiskCategory.DVDRW: - if(decoded.PartVersion >= 15) - sb.AppendFormat(bookTypeSentence, "DVD-RW DL").AppendLine(); - else - sb.AppendFormat(bookTypeSentence, "DVD-RW").AppendLine(); - - break; - case DiskCategory.UMD: - sb.AppendFormat(bookTypeSentence, "UMD").AppendLine(); - - break; - case DiskCategory.DVDPRW: - sb.AppendFormat(bookTypeSentence, "DVD+RW").AppendLine(); - - break; - case DiskCategory.DVDPR: - sb.AppendFormat(bookTypeSentence, "DVD+R").AppendLine(); - - break; - case DiskCategory.DVDPRWDL: - sb.AppendFormat(bookTypeSentence, "DVD+RW DL").AppendLine(); - - break; - case DiskCategory.DVDPRDL: - sb.AppendFormat(bookTypeSentence, "DVD+R DL").AppendLine(); - - break; - case DiskCategory.HDDVDROM: - sb.AppendFormat(bookTypeSentence, "HD DVD-ROM").AppendLine(); - - break; - case DiskCategory.HDDVDRAM: - sb.AppendFormat(bookTypeSentence, "HD DVD-RAM").AppendLine(); - - break; - case DiskCategory.HDDVDR: - sb.AppendFormat(bookTypeSentence, "HD DVD-R").AppendLine(); - - break; - case DiskCategory.HDDVDRW: - sb.AppendFormat(bookTypeSentence, "HD DVD-RW").AppendLine(); + case DVDRAMDiscType.Uncased: + sb.AppendLine("Disc can be recorded with or without a case"); break; default: - sb.AppendFormat(bookTypeSentence, "unknown").AppendLine(); + sb.AppendFormat("Unknown DVD-RAM case type key {0}", decoded.DiscType).AppendLine(); break; } - } - switch(decoded.MaximumRate) - { - case MaximumRateField.TwoMbps: - sb.AppendLine("Disc maximum transfer rate is 2,52 Mbit/sec."); - - break; - case MaximumRateField.FiveMbps: - sb.AppendLine("Disc maximum transfer rate is 5,04 Mbit/sec."); - - break; - case MaximumRateField.TenMbps: - sb.AppendLine("Disc maximum transfer rate is 10,08 Mbit/sec."); - - break; - case MaximumRateField.TwentyMbps: - sb.AppendLine("Disc maximum transfer rate is 20,16 Mbit/sec."); - - break; - case MaximumRateField.ThirtyMbps: - sb.AppendLine("Disc maximum transfer rate is 30,24 Mbit/sec."); - - break; - case MaximumRateField.Unspecified: - sb.AppendLine("Disc maximum transfer rate is unspecified."); - - break; - default: - sb.AppendFormat("Disc maximum transfer rate is specified by unknown key {0}", decoded.MaximumRate). - AppendLine(); - - break; - } - - sb.AppendFormat("Disc has {0} layers", decoded.Layers + 1).AppendLine(); - - if(decoded.TrackPath && - decoded.Layers == 1) - sb.AppendLine("Layers are in parallel track path"); - else if(!decoded.TrackPath && - decoded.Layers == 1) - sb.AppendLine("Layers are in opposite track path"); - - switch(decoded.LinearDensity) - { - case LinearDensityField.TwoSix: - sb.AppendLine("Pitch size is 0,267 μm/bit"); - - break; - case LinearDensityField.TwoNine: - sb.AppendLine("Pitch size is 0,147 μm/bit"); - - break; - case LinearDensityField.FourZero: - sb.AppendLine("Pitch size is between 0,409 μm/bit and 0,435 μm/bit"); - - break; - case LinearDensityField.TwoEight: - sb.AppendLine("Pitch size is between 0,140 μm/bit and 0,148 μm/bit"); - - break; - case LinearDensityField.OneFive: - sb.AppendLine("Pitch size is 0,153 μm/bit"); - - break; - case LinearDensityField.OneThree: - sb.AppendLine("Pitch size is between 0,130 μm/bit and 0,140 μm/bit"); - - break; - case LinearDensityField.ThreeFive: - sb.AppendLine("Pitch size is 0,353 μm/bit"); - - break; - default: - sb.AppendFormat("Unknown pitch size key {0}", decoded.LinearDensity).AppendLine(); - - break; - } - - switch(decoded.TrackDensity) - { - case TrackDensityField.Seven: - sb.AppendLine("Track size is 0,74 μm"); - - break; - case TrackDensityField.Eight: - sb.AppendLine("Track size is 0,80 μm"); - - break; - case TrackDensityField.Six: - sb.AppendLine("Track size is 0,615 μm"); - - break; - case TrackDensityField.Four: - sb.AppendLine("Track size is 0,40 μm"); - - break; - case TrackDensityField.Three: - sb.AppendLine("Track size is 0,34 μm"); - - break; - default: - sb.AppendFormat("Unknown track size key {0}", decoded.LinearDensity).AppendLine(); - - break; - } - - if(decoded.DataAreaStartPSN > 0) - if(decoded.DataAreaEndPSN > 0) + if(decoded.PartVersion == 6) { - sb.AppendFormat("Data area starts at PSN {0:X}h", decoded.DataAreaStartPSN).AppendLine(); - sb.AppendFormat("Data area ends at PSN {0:X}h", decoded.DataAreaEndPSN).AppendLine(); + sb.AppendFormat("Disc manufacturer is {0}", ManufacturerFromDVDRAM(decoded.DiskManufacturer)). + AppendLine(); - if(decoded.Layers == 1 && - !decoded.TrackPath) - sb.AppendFormat("Layer 0 ends at PSN {0:X}h", decoded.Layer0EndPSN).AppendLine(); + sb.AppendFormat("Disc manufacturer supplementary information is {0}", + decoded.DiskManufacturerSupplementary).AppendLine(); } - else - sb.AppendLine("Disc is empty"); - else - sb.AppendLine("Disc is empty"); - if(decoded.BCA) - sb.AppendLine("Disc has a burst cutting area"); + break; + case DiskCategory.DVDR when decoded.PartVersion < 6: + case DiskCategory.DVDRW when decoded.PartVersion < 15: + sb.AppendFormat("Current Border-Out first sector is PSN {0:X}h", decoded.CurrentBorderOutSector). + AppendLine(); - switch(decoded.DiskCategory) - { - case DiskCategory.UMD: - sb.AppendFormat("Media attribute is {0}", decoded.MediaAttribute).AppendLine(); + sb.AppendFormat("Next Border-In first sector is PSN {0:X}h", decoded.NextBorderInSector). + AppendLine(); - break; - case DiskCategory.DVDRAM: - switch(decoded.DiscType) - { - case DVDRAMDiscType.Cased: - sb.AppendLine("Disc shall be recorded with a case"); + break; + case DiskCategory.DVDPR: + case DiskCategory.DVDPRW: + case DiskCategory.DVDPRDL: + case DiskCategory.DVDPRWDL: + if(decoded.VCPS) + sb.AppendLine("Disc contains extended information for VCPS"); - break; - case DVDRAMDiscType.Uncased: - sb.AppendLine("Disc can be recorded with or without a case"); + sb.AppendFormat("Disc application code is {0}", decoded.ApplicationCode).AppendLine(); - break; - default: - sb.AppendFormat("Unknown DVD-RAM case type key {0}", decoded.DiscType).AppendLine(); + sb.AppendFormat("Disc manufacturer is {0}", ManufacturerFromDVDPlusID(decoded.DiskManufacturerID)). + AppendLine(); - break; - } + sb.AppendFormat("Disc media type is {0}", decoded.MediaTypeID).AppendLine(); + sb.AppendFormat("Disc product revision is {0}", decoded.ProductRevision).AppendLine(); - if(decoded.PartVersion == 6) - { - sb.AppendFormat("Disc manufacturer is {0}", ManufacturerFromDVDRAM(decoded.DiskManufacturer)). - AppendLine(); - - sb.AppendFormat("Disc manufacturer supplementary information is {0}", - decoded.DiskManufacturerSupplementary).AppendLine(); - } - - break; - case DiskCategory.DVDR when decoded.PartVersion < 6: - case DiskCategory.DVDRW when decoded.PartVersion < 15: - sb.AppendFormat("Current Border-Out first sector is PSN {0:X}h", decoded.CurrentBorderOutSector). - AppendLine(); - - sb.AppendFormat("Next Border-In first sector is PSN {0:X}h", decoded.NextBorderInSector). - AppendLine(); - - break; - case DiskCategory.DVDPR: - case DiskCategory.DVDPRW: - case DiskCategory.DVDPRDL: - case DiskCategory.DVDPRWDL: - if(decoded.VCPS) - sb.AppendLine("Disc contains extended information for VCPS"); - - sb.AppendFormat("Disc application code is {0}", decoded.ApplicationCode).AppendLine(); - - sb.AppendFormat("Disc manufacturer is {0}", ManufacturerFromDVDPlusID(decoded.DiskManufacturerID)). - AppendLine(); - - sb.AppendFormat("Disc media type is {0}", decoded.MediaTypeID).AppendLine(); - sb.AppendFormat("Disc product revision is {0}", decoded.ProductRevision).AppendLine(); - - break; - } - - if((decoded.DiskCategory != DiskCategory.DVDR || decoded.PartVersion < 6) && - (decoded.DiskCategory != DiskCategory.DVDRW || decoded.PartVersion < 15)) - return sb.ToString(); - - sb.AppendFormat("Current RMD in extra Border zone starts at PSN {0:X}h", decoded.CurrentRMDExtraBorderPSN). - AppendLine(); - - sb.AppendFormat("PFI in extra Border zone starts at PSN {0:X}h", decoded.PFIExtraBorderPSN).AppendLine(); - - if(!decoded.PreRecordedControlDataInv) - sb.AppendLine("Control Data Zone is pre-recorded"); - - if(decoded.PreRecordedLeadIn) - sb.AppendLine("Lead-In is pre-recorded"); - - if(decoded.PreRecordedLeadOut) - sb.AppendLine("Lead-Out is pre-recorded"); + break; + } + if((decoded.DiskCategory != DiskCategory.DVDR || decoded.PartVersion < 6) && + (decoded.DiskCategory != DiskCategory.DVDRW || decoded.PartVersion < 15)) return sb.ToString(); - } - public static string Prettify(byte[] response, MediaType mediaType) => Prettify(Decode(response, mediaType)); + sb.AppendFormat("Current RMD in extra Border zone starts at PSN {0:X}h", decoded.CurrentRMDExtraBorderPSN). + AppendLine(); - public static string ManufacturerFromDVDRAM(string manufacturerId) + sb.AppendFormat("PFI in extra Border zone starts at PSN {0:X}h", decoded.PFIExtraBorderPSN).AppendLine(); + + if(!decoded.PreRecordedControlDataInv) + sb.AppendLine("Control Data Zone is pre-recorded"); + + if(decoded.PreRecordedLeadIn) + sb.AppendLine("Lead-In is pre-recorded"); + + if(decoded.PreRecordedLeadOut) + sb.AppendLine("Lead-Out is pre-recorded"); + + return sb.ToString(); + } + + public static string Prettify(byte[] response, MediaType mediaType) => Prettify(Decode(response, mediaType)); + + public static string ManufacturerFromDVDRAM(string manufacturerId) + { + switch(manufacturerId) { - switch(manufacturerId) - { - default: return ManufacturerFromDVDPlusID(manufacturerId); - } - } - - public static string ManufacturerFromDVDPlusID(string manufacturerId) - { - string manufacturer = ""; - - switch(manufacturerId) - { - case "CMC MAG": - manufacturer = "CMC Magnetics Corporation"; - - break; - case "INFOME": - manufacturer = "InfoMedia Inc."; - - break; - case "RITEK": - manufacturer = "Ritek Co."; - - break; - case "RICOHJPN": - manufacturer = "Ricoh Company, Ltd."; - - break; - case "ISSM": - manufacturer = "Info Source Digital Media (Zhongshan) Co., Ltd."; - - break; - case "LD": - manufacturer = "Lead Data Inc."; - - break; - case "MAXELL": - manufacturer = "Hitachi Maxell, Ltd."; - - break; - case "MCC": - manufacturer = "Mitsubishi Kagaku Media Co., LTD."; - - break; - case "PRODISC": - manufacturer = "Prodisc Technology Inc."; - - break; - case "Philips": - case "PHILIPS": - - manufacturer = "Philips Components"; - - break; - case "YUDEN000": - manufacturer = "Taiyo Yuden Company Ltd."; - - break; - case "AML": - manufacturer = "Avic Umedisc HK Ltd."; - - break; - case "DAXON": - manufacturer = "Daxon Technology Inc."; - - break; - case "FTI": - manufacturer = "Falcon Technologies International L.L.C."; - - break; - case "GSC503": - manufacturer = "Gigastore Corporation"; - - break; - case "MBIPG101": - manufacturer = "Moser Baer India Ltd."; - - break; - case "OPTODISC": - manufacturer = "OptoDisc Ltd."; - - break; - case "SONY": - manufacturer = "Sony Corporation"; - - break; - case "TDK": - manufacturer = "TDK Corporation"; - - break; - case "SENTINEL": - manufacturer = "Sentinel B.V."; - - break; - case "BeAll000": - manufacturer = "BeALL Developers, Inc."; - - break; - case "MPOMEDIA": - manufacturer = "MPO Disque Compact"; - - break; - case "IMC JPN": - manufacturer = "Intermedia Co., Ltd."; - - break; - case "INFODISC": - manufacturer = "InfoDisc Technology Co., Ltd."; - - break; - case "WFKA11": - manufacturer = "Wealth Fair Investment Inc."; - - break; - case "MAM": - manufacturer = "Manufacturing Advanced Media Europe"; - - break; - case "VDSPMSAB": - manufacturer = "Interaxia Digital Storage Materials AG"; - - break; - case "KIC00000": - manufacturer = "Advanced Media Corporation"; - - break; - case "MJC": - manufacturer = "Megan Media Holdings Berhad"; - - break; - case "MUST": - manufacturer = "Must Technology Co., Ltd."; - - break; - case "IS02": - manufacturer = "Infosmart Technology Ltd."; - - break; - case "DDDessau": - manufacturer = "Digital Disc Dessau GmbH"; - - break; - case "SKYMEDIA": - manufacturer = "Sky Media Manufacturing S.A."; - - break; - case "MICRON": - manufacturer = "Eastgate Technology Ltd."; - - break; - case "VIVA": - manufacturer = "Viva Optical Disc Manufacturing Ltd."; - - break; - case "EMDPZ3": - manufacturer = "E-TOP Mediatek Inc."; - - break; - case "LGEP16": - manufacturer = "LG Electronics Inc."; - - break; - case "POS": - manufacturer = "POSTECH Corporation"; - - break; - case "Dvsn+160": - manufacturer = "Digital Storage Technology Co., Ltd."; - - break; - case "ODMS": - manufacturer = "VDL Optical Disc Manufacturing Systems"; - - break; - } - - return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; - } - - public struct PhysicalFormatInformation - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - - #region PFI common to all - /// Byte 4, bits 7 to 4 Disk category field - public DiskCategory DiskCategory; - /// Byte 4, bits 3 to 0 Media version - public byte PartVersion; - /// Byte 5, bits 7 to 4 120mm if 0, 80mm if 1. If UMD (60mm) 0 also. Reserved rest of values - public DVDSize DiscSize; - /// Byte 5, bits 3 to 0 Maximum data rate - public MaximumRateField MaximumRate; - /// Byte 6, bit 7 Reserved - public bool Reserved3; - /// Byte 6, bits 6 to 5 Number of layers - public byte Layers; - /// Byte 6, bit 4 Track path - public bool TrackPath; - /// Byte 6, bits 3 to 0 Layer type - public LayerTypeFieldMask LayerType; - /// Byte 7, bits 7 to 4 Linear density field - public LinearDensityField LinearDensity; - /// Byte 7, bits 3 to 0 Track density field - public TrackDensityField TrackDensity; - /// Bytes 8 to 11 PSN where Data Area starts - public uint DataAreaStartPSN; - /// Bytes 12 to 15 PSN where Data Area ends - public uint DataAreaEndPSN; - /// Bytes 16 to 19 PSN where Data Area ends in Layer 0 - public uint Layer0EndPSN; - /// - /// Byte 20, bit 7 True if BCA exists. GC/Wii discs do not have this bit set, but there is a BCA, making it - /// unreadable in normal DVD drives - /// - public bool BCA; - /// Byte 20, bits 6 to 0 Reserved - public byte Reserved4; - #endregion PFI common to all - - #region UMD PFI - /// Bytes 21 to 22 UMD only, media attribute, application-defined, part of media specific in rest of discs - public ushort MediaAttribute; - #endregion UMD PFI - - #region DVD-RAM PFI - /// Byte 36 Disc type, respecting case recordability - public DVDRAMDiscType DiscType; - #endregion DVD-RAM PFI - - #region DVD-RAM PFI, Version 0001b - /// Byte 52 Byte 504 in Version 0110b Linear velocity, in tenths of m/s - public byte Velocity; - /// Byte 53 Byte 505 in Version 0110b Read power on disk surface, tenths of mW - public byte ReadPower; - /// Byte 54 Byte 507 in Version 0110b Peak power on disk surface for recording land tracks - public byte PeakPower; - /// Byte 55 Bias power on disk surface for recording land tracks - public byte BiasPower; - /// Byte 56 First pulse starting time for recording on land tracks, ns - public byte FirstPulseStart; - /// Byte 57 Byte 515 in Version 0110b First pulse ending time for recording on land tracks - public byte FirstPulseEnd; - /// Byte 58 Byte 518 in Version 0110b Multiple-pulse duration time for recording on land tracks - public byte MultiplePulseDuration; - /// Byte 59 Byte 519 in Version 0110b Last pulse starting time for recording on land tracks - public byte LastPulseStart; - /// Byte 60 Las pulse ending time for recording on land tracks - public byte LastPulseEnd; - /// Byte 61 Bias power duration for recording on land tracks - public byte BiasPowerDuration; - /// Byte 62 Byte 511 on Version 0110b Peak power for recording on groove tracks - public byte PeakPowerGroove; - /// Byte 63 Bias power for recording on groove tracks - public byte BiasPowerGroove; - /// Byte 64 First pulse starting time on groove tracks - public byte FirstPulseStartGroove; - /// Byte 65 First pulse ending time on groove tracks - public byte FirstPulseEndGroove; - /// Byte 66 Multiple-pulse duration time on groove tracks - public byte MultiplePulseDurationGroove; - /// Byte 67 Last pulse starting time on groove tracks - public byte LastPulseStartGroove; - /// Byte 68 Last pulse ending time on groove tracks - public byte LastPulseEndGroove; - /// Byte 69 Bias power duration for recording on groove tracks - public byte BiasPowerDurationGroove; - #endregion DVD-RAM PFI, Version 0001b - - #region DVD-R PFI, DVD-RW PFI - /// Bytes 36 to 39 Sector number of the first sector of the current Border Out - public uint CurrentBorderOutSector; - /// Bytes 40 to 43 Sector number of the first sector of the next Border In - public uint NextBorderInSector; - #endregion DVD-R PFI, DVD-RW PFI - - #region DVD+RW PFI - /// Byte 36 Linear velocities 0 = CLV from 4,90 m/s to 6,25 m/s 1 = CAV from 3,02 m/s to 7,35 m/s - public byte RecordingVelocity; - /// Byte 37 Maximum read power in milliwatts at maximum velocity mW = 20 * (value - 1) - public byte ReadPowerMaxVelocity; - /// Byte 38 Indicative value of Ptarget in mW at maximum velocity - public byte PIndMaxVelocity; - /// Byte 39 Peak power multiplication factor at maximum velocity - public byte PMaxVelocity; - /// Byte 40 Bias1/write power ration at maximum velocity - public byte E1MaxVelocity; - /// Byte 41 Bias2/write power ration at maximum velocity - public byte E2MaxVelocity; - /// Byte 42 Target value for γ, γtarget at the maximum velocity - public byte YTargetMaxVelocity; - /// Byte 43 Maximum read power in milliwatts at reference velocity (4,90 m/s) mW = 20 * (value - 1) - public byte ReadPowerRefVelocity; - /// Byte 44 Indicative value of Ptarget in mW at reference velocity (4,90 m/s) - public byte PIndRefVelocity; - /// Byte 45 Peak power multiplication factor at reference velocity (4,90 m/s) - public byte PRefVelocity; - /// Byte 46 Bias1/write power ration at reference velocity (4,90 m/s) - public byte E1RefVelocity; - /// Byte 47 Bias2/write power ration at reference velocity (4,90 m/s) - public byte E2RefVelocity; - /// Byte 48 Target value for γ, γtarget at the reference velocity (4,90 m/s) - public byte YTargetRefVelocity; - /// Byte 49 Maximum read power in milliwatts at minimum velocity mW = 20 * (value - 1) - public byte ReadPowerMinVelocity; - /// Byte 50 Indicative value of Ptarget in mW at minimum velocity - public byte PIndMinVelocity; - /// Byte 51 Peak power multiplication factor at minimum velocity - public byte PMinVelocity; - /// Byte 52 Bias1/write power ration at minimum velocity - public byte E1MinVelocity; - /// Byte 53 Bias2/write power ration at minimum velocity - public byte E2MinVelocity; - /// Byte 54 Target value for γ, γtarget at the minimum velocity - public byte YTargetMinVelocity; - #endregion DVD+RW PFI - - #region DVD-RAM PFI, version 0110b - /// Byte 506, bit 7 Mode of adaptative write pulse control - public bool AdaptativeWritePulseControlFlag; - /// Byte 508 Bias power 1 on disk surface for recording land tracks - public byte BiasPower1; - /// Byte 509 Bias power 2 on disk surface for recording land tracks - public byte BiasPower2; - /// Byte 510 Bias power 3 on disk surface for recording land tracks - public byte BiasPower3; - /// Byte 512 Bias power 1 on disk surface for recording groove tracks - public byte BiasPower1Groove; - /// Byte 513 Bias power 2 on disk surface for recording groove tracks - public byte BiasPower2Groove; - /// Byte 514 Bias power 3 on disk surface for recording groove tracks - public byte BiasPower3Groove; - /// Byte 516 First pulse duration - public byte FirstPulseDuration; - /// Byte 520 Bias power 2 duration on land tracks at Velocity 1 - public byte BiasPower2Duration; - /// Byte 521 First pulse start time, at Mark 3T and Leading Space 3T - public byte FirstPulseStart3TSpace3T; - /// Byte 522 First pulse start time, at Mark 4T and Leading Space 3T - public byte FirstPulseStart4TSpace3T; - /// Byte 523 First pulse start time, at Mark 5T and Leading Space 3T - public byte FirstPulseStart5TSpace3T; - /// Byte 524 First pulse start time, at Mark >5T and Leading Space 3T - public byte FirstPulseStartSpace3T; - /// Byte 525 First pulse start time, at Mark 3T and Leading Space 4T - public byte FirstPulseStart3TSpace4T; - /// Byte 526 First pulse start time, at Mark 4T and Leading Space 4T - public byte FirstPulseStart4TSpace4T; - /// Byte 527 First pulse start time, at Mark 5T and Leading Space 4T - public byte FirstPulseStart5TSpace4T; - /// Byte 528 First pulse start time, at Mark >5T and Leading Space 4T - public byte FirstPulseStartSpace4T; - /// Byte 529 First pulse start time, at Mark 3T and Leading Space 5T - public byte FirstPulseStart3TSpace5T; - /// Byte 530 First pulse start time, at Mark 4T and Leading Space 5T - public byte FirstPulseStart4TSpace5T; - /// Byte 531 First pulse start time, at Mark 5T and Leading Space 5T - public byte FirstPulseStart5TSpace5T; - /// Byte 532 First pulse start time, at Mark >5T and Leading Space 5T - public byte FirstPulseStartSpace5T; - /// Byte 533 First pulse start time, at Mark 3T and Leading Space >5T - public byte FirstPulseStart3TSpace; - /// Byte 534 First pulse start time, at Mark 4T and Leading Space >5T - public byte FirstPulseStart4TSpace; - /// Byte 535 First pulse start time, at Mark 5T and Leading Space >5T - public byte FirstPulseStart5TSpace; - /// Byte 536 First pulse start time, at Mark >5T and Leading Space >5T - public byte FirstPulseStartSpace; - /// Byte 537 First pulse start time, at Mark 3T and Trailing Space 3T - public byte FirstPulse3TStartTSpace3T; - /// Byte 538 First pulse start time, at Mark 4T and Trailing Space 3T - public byte FirstPulse4TStartTSpace3T; - /// Byte 539 First pulse start time, at Mark 5T and Trailing Space 3T - public byte FirstPulse5TStartTSpace3T; - /// Byte 540 First pulse start time, at Mark >5T and Trailing Space 3T - public byte FirstPulseStartTSpace3T; - /// Byte 541 First pulse start time, at Mark 3T and Trailing Space 4T - public byte FirstPulse3TStartTSpace4T; - /// Byte 542 First pulse start time, at Mark 4T and Trailing Space 4T - public byte FirstPulse4TStartTSpace4T; - /// Byte 543 First pulse start time, at Mark 5T and Trailing Space 4T - public byte FirstPulse5TStartTSpace4T; - /// Byte 544 First pulse start time, at Mark >5T and Trailing Space 4T - public byte FirstPulseStartTSpace4T; - /// Byte 545 First pulse start time, at Mark 3T and Trailing Space 5T - public byte FirstPulse3TStartTSpace5T; - /// Byte 546 First pulse start time, at Mark 4T and Trailing Space 5T - public byte FirstPulse4TStartTSpace5T; - /// Byte 547 First pulse start time, at Mark 5T and Trailing Space 5T - public byte FirstPulse5TStartTSpace5T; - /// Byte 548 First pulse start time, at Mark >5T and Trailing Space 5T - public byte FirstPulseStartTSpace5T; - /// Byte 549 First pulse start time, at Mark 3T and Trailing Space >5T - public byte FirstPulse3TStartTSpace; - /// Byte 550 First pulse start time, at Mark 4T and Trailing Space >5T - public byte FirstPulse4TStartTSpace; - /// Byte 551 First pulse start time, at Mark 5T and Trailing Space >5T - public byte FirstPulse5TStartTSpace; - /// Byte 552 First pulse start time, at Mark >5T and Trailing Space >5T - public byte FirstPulseStartTSpace; - /// Bytes 553 to 600 Disk manufacturer's name, space-padded - public string DiskManufacturer; - /// Bytes 601 to 616 Disk manufacturer's supplementary information - public string DiskManufacturerSupplementary; - /// Bytes 617 to 627 Write power control parameters - public byte[] WritePowerControlParams; - /// Byte 619 Ratio of peak power for land tracks to threshold peak power for land tracks - public byte PowerRatioLandThreshold; - /// Byte 620 Target asymmetry - public byte TargetAsymmetry; - /// Byte 621 Temporary peak power - public byte TemporaryPeakPower; - /// Byte 622 Temporary bias power 1 - public byte TemporaryBiasPower1; - /// Byte 623 Temporary bias power 2 - public byte TemporaryBiasPower2; - /// Byte 624 Temporary bias power 3 - public byte TemporaryBiasPower3; - /// Byte 625 Ratio of peak power for groove tracks to threshold peak power for groove tracks - public byte PowerRatioGrooveThreshold; - /// Byte 626 Ratio of peak power for land tracks to threshold 6T peak power for land tracks - public byte PowerRatioLandThreshold6T; - /// Byte 627 Ratio of peak power for groove tracks to threshold 6T peak power for groove tracks - public byte PowerRatioGrooveThreshold6T; - #endregion DVD-RAM PFI, version 0110b - - #region DVD+RW PFI, DVD+R PFI, DVD+R DL PFI and DVD+RW DL PFI - /// Byte 20, bit 6 If set indicates data zone contains extended information for VCPS - public bool VCPS; - /// Byte 21 Indicates restricted usage disk - public byte ApplicationCode; - /// Byte 22 Bitmap of extended information block presence - public byte ExtendedInformation; - /// Bytes 23 to 30 Disk manufacturer ID, null-padded - public string DiskManufacturerID; - /// Bytes 31 to 33 Media type ID, null-padded - public string MediaTypeID; - /// Byte 34 Product revision number - public byte ProductRevision; - /// Byte 35 Indicates how many bytes, up to 63, are used in ADIP's PFI - public byte PFIUsedInADIP; - #endregion DVD+RW PFI, DVD+R PFI, DVD+R DL PFI and DVD+RW DL PFI - - #region DVD+RW PFI, version 0010b - /// Byte 55 Ttop first pulse duration - public byte TopFirstPulseDuration; - /// Byte 56 Tmp multi pulse duration - public byte MultiPulseDuration; - /// Byte 57 dTtop first pulse lead time - public byte FirstPulseLeadTime; - /// Byte 58 dTera erase lead time at reference velocity - public byte EraseLeadTimeRefVelocity; - /// Byte 59 dTera erase lead time at upper velocity - public byte EraseLeadTimeUppVelocity; - #endregion DVD+RW PFI, version 0010b - - #region DVD+R PFI version 0001b and DVD+R DL PFI version 0001b - /// Byte 36 Primary recording velocity for the basic write strategy - public byte PrimaryVelocity; - /// Byte 37 Upper recording velocity for the basic write strategy - public byte UpperVelocity; - /// Byte 38 Wavelength λIND - public byte Wavelength; - /// Byte 39 Normalized write power dependency on wavelength (dP/dλ)/(PIND/λIND) - public byte NormalizedPowerDependency; - /// Byte 40 Maximum read power at primary velocity - public byte MaximumPowerAtPrimaryVelocity; - /// Byte 41 Pind at primary velocity - public byte PindAtPrimaryVelocity; - /// Byte 42 βtarget at primary velocity - public byte BtargetAtPrimaryVelocity; - /// Byte 43 Maximum read power at upper velocity - public byte MaximumPowerAtUpperVelocity; - /// Byte 44 Pind at primary velocity - public byte PindAtUpperVelocity; - /// Byte 45 βtarget at upper velocity - public byte BtargetAtUpperVelocity; - /// Byte 46 Ttop (≥4T) first pulse duration for cm∗ ≥4T at Primary velocity - public byte FirstPulseDuration4TPrimaryVelocity; - /// Byte 47 Ttop (=3T) first pulse duration for cm∗ =3T at Primary velocity - public byte FirstPulseDuration3TPrimaryVelocity; - /// Byte 48 Tmp multi pulse duration at Primary velocity - public byte MultiPulseDurationPrimaryVelocity; - /// Byte 49 Tlp last pulse duration at Primary velocity - public byte LastPulseDurationPrimaryVelocity; - /// Byte 50 dTtop (≥4T) first pulse lead time for cm∗ ≥4T at Primary velocity - public byte FirstPulseLeadTime4TPrimaryVelocity; - /// Byte 51 dTtop (=3T) first pulse lead time for cm∗ =3T at Primary velocity - public byte FirstPulseLeadTime3TPrimaryVelocity; - /// Byte 52 dTle first pulse leading edge shift for ps∗ =3T at Primary velocity - public byte FirstPulseLeadingEdgePrimaryVelocity; - /// Byte 53 Ttop (≥4T) first pulse duration for cm∗ ≥4T at Upper velocity - public byte FirstPulseDuration4TUpperVelocity; - /// Byte 54 Ttop (=3T) first pulse duration for cm∗ =3T at Upper velocity - public byte FirstPulseDuration3TUpperVelocity; - /// Byte 55 Tmp multi pulse duration at Upper velocity - public byte MultiPulseDurationUpperVelocity; - /// Byte 56 Tlp last pulse duration at Upper velocity - public byte LastPulseDurationUpperVelocity; - /// Byte 57 dTtop (≥4T) first pulse lead time for cm∗ ≥4T at Upper velocity - public byte FirstPulseLeadTime4TUpperVelocity; - /// Byte 58 dTtop (=3T) first pulse lead time for cm∗ =3T at Upper velocity - public byte FirstPulseLeadTime3TUpperVelocity; - /// Byte 59 dTle first pulse leading edge shift for ps∗ =3T at Upper velocity - public byte FirstPulseLeadingEdgeUpperVelocity; - #endregion DVD+R PFI version 0001b and DVD+R DL PFI version 0001b - - #region DVD+R DL PFI version 0001b - /// Byte 34, bits 7 to 6 - public DVDLayerStructure LayerStructure; - #endregion DVD+R DL PFI version 0001b - - #region DVD+RW DL PFI - /// Byte 36 Primary recording velocity for the basic write strategy - public byte BasicPrimaryVelocity; - /// Byte 37 Maximum read power at Primary velocity - public byte MaxReadPowerPrimaryVelocity; - /// Byte 38 PIND at Primary velocity - public byte PindPrimaryVelocity; - /// Byte 39 ρ at Primary velocity - public byte PPrimaryVelocity; - /// Byte 40 ε1 at Primary velocity - public byte E1PrimaryVelocity; - /// Byte 41 ε2 at Primary velocity - public byte E2PrimaryVelocity; - /// Byte 42 γtarget at Primary velocity - public byte YtargetPrimaryVelocity; - /// Byte 43 β optimum at Primary velocity - public byte BOptimumPrimaryVelocity; - /// Byte 46 Ttop first pulse duration - public byte TFirstPulseDuration; - /// Byte 47 Tmp multi pulse duration - public byte TMultiPulseDuration; - /// Byte 48 dTtop first pulse lead/lag time for any runlength ≥ 4T - public byte FirstPulseLeadTimeAnyRun; - /// Byte 49 dTtop,3 first pulse lead/lag time for runlengths = 3T - public byte FirstPulseLeadTimeRun3T; - /// Byte 50 dTlp last pulse lead/lag time for any runlength ≥ 5T - public byte LastPulseLeadTimeAnyRun; - /// Byte 51 dTlp,3 last pulse lead/lag time for runlengths = 3T - public byte LastPulseLeadTime3T; - /// Byte 52 dTlp,4 last pulse lead/lag time for runlengths = 4T - public byte LastPulseLeadTime4T; - /// Byte 53 dTera erase lead/lag time when preceding mark length ≥ 5T - public byte ErasePulseLeadTimeAny; - /// Byte 54 dTera,3 erase lead/lag time when preceding mark length = 3T - public byte ErasePulseLeadTime3T; - /// Byte 55 dTera,4 erase lead/lag time when preceding mark length = 4T - public byte ErasePulseLeadTime4T; - #endregion DVD+RW DL PFI - - #region DVD-R DL PFI and DVD-RW DL PFI - /// Byte 21 Maximum recording speed - public DVDRecordingSpeed MaxRecordingSpeed; - /// Byte 22 Minimum recording speed - public DVDRecordingSpeed MinRecordingSpeed; - /// Byte 23 Another recording speed - public DVDRecordingSpeed RecordingSpeed1; - /// Byte 24 Another recording speed - public DVDRecordingSpeed RecordingSpeed2; - /// Byte 25 Another recording speed - public DVDRecordingSpeed RecordingSpeed3; - /// Byte 26 Another recording speed - public DVDRecordingSpeed RecordingSpeed4; - /// Byte 27 Another recording speed - public DVDRecordingSpeed RecordingSpeed5; - /// Byte 28 Another recording speed - public DVDRecordingSpeed RecordingSpeed6; - /// Byte 29 Another recording speed - public DVDRecordingSpeed RecordingSpeed7; - /// Byte 30 Class - public byte Class; - /// Byte 31 Extended version. 0x30 = ECMA-382, 0x20 = ECMA-384 - public byte ExtendedVersion; - /// Byte 36 Start sector number of current RMD in Extra Border Zone - public uint CurrentRMDExtraBorderPSN; - /// Byte 40 Start sector number of Physical Format Information blocks in Extra Border Zone - public uint PFIExtraBorderPSN; - /// Byte 44, bit 0 If NOT set, Control Data Zone is pre-recorded - public bool PreRecordedControlDataInv; - /// Byte 44 bit 1 Lead-in Zone is pre-recorded - public bool PreRecordedLeadIn; - /// Byte 44 bit 3 Lead-out Zone is pre-recorded - public bool PreRecordedLeadOut; - /// Byte 45 bits 0 to 3 AR characteristic of LPP on Layer 1 - public byte ARCharLayer1; - /// Byte 45 bits 4 to 7 Tracking polarity on Layer 1 - public byte TrackPolarityLayer1; - #endregion DVD-R DL PFI and DVD-RW DL PFI - - public DiskCategory RecordedBookType; + default: return ManufacturerFromDVDPlusID(manufacturerId); } } + + public static string ManufacturerFromDVDPlusID(string manufacturerId) + { + string manufacturer = ""; + + switch(manufacturerId) + { + case "CMC MAG": + manufacturer = "CMC Magnetics Corporation"; + + break; + case "INFOME": + manufacturer = "InfoMedia Inc."; + + break; + case "RITEK": + manufacturer = "Ritek Co."; + + break; + case "RICOHJPN": + manufacturer = "Ricoh Company, Ltd."; + + break; + case "ISSM": + manufacturer = "Info Source Digital Media (Zhongshan) Co., Ltd."; + + break; + case "LD": + manufacturer = "Lead Data Inc."; + + break; + case "MAXELL": + manufacturer = "Hitachi Maxell, Ltd."; + + break; + case "MCC": + manufacturer = "Mitsubishi Kagaku Media Co., LTD."; + + break; + case "PRODISC": + manufacturer = "Prodisc Technology Inc."; + + break; + case "Philips": + case "PHILIPS": + + manufacturer = "Philips Components"; + + break; + case "YUDEN000": + manufacturer = "Taiyo Yuden Company Ltd."; + + break; + case "AML": + manufacturer = "Avic Umedisc HK Ltd."; + + break; + case "DAXON": + manufacturer = "Daxon Technology Inc."; + + break; + case "FTI": + manufacturer = "Falcon Technologies International L.L.C."; + + break; + case "GSC503": + manufacturer = "Gigastore Corporation"; + + break; + case "MBIPG101": + manufacturer = "Moser Baer India Ltd."; + + break; + case "OPTODISC": + manufacturer = "OptoDisc Ltd."; + + break; + case "SONY": + manufacturer = "Sony Corporation"; + + break; + case "TDK": + manufacturer = "TDK Corporation"; + + break; + case "SENTINEL": + manufacturer = "Sentinel B.V."; + + break; + case "BeAll000": + manufacturer = "BeALL Developers, Inc."; + + break; + case "MPOMEDIA": + manufacturer = "MPO Disque Compact"; + + break; + case "IMC JPN": + manufacturer = "Intermedia Co., Ltd."; + + break; + case "INFODISC": + manufacturer = "InfoDisc Technology Co., Ltd."; + + break; + case "WFKA11": + manufacturer = "Wealth Fair Investment Inc."; + + break; + case "MAM": + manufacturer = "Manufacturing Advanced Media Europe"; + + break; + case "VDSPMSAB": + manufacturer = "Interaxia Digital Storage Materials AG"; + + break; + case "KIC00000": + manufacturer = "Advanced Media Corporation"; + + break; + case "MJC": + manufacturer = "Megan Media Holdings Berhad"; + + break; + case "MUST": + manufacturer = "Must Technology Co., Ltd."; + + break; + case "IS02": + manufacturer = "Infosmart Technology Ltd."; + + break; + case "DDDessau": + manufacturer = "Digital Disc Dessau GmbH"; + + break; + case "SKYMEDIA": + manufacturer = "Sky Media Manufacturing S.A."; + + break; + case "MICRON": + manufacturer = "Eastgate Technology Ltd."; + + break; + case "VIVA": + manufacturer = "Viva Optical Disc Manufacturing Ltd."; + + break; + case "EMDPZ3": + manufacturer = "E-TOP Mediatek Inc."; + + break; + case "LGEP16": + manufacturer = "LG Electronics Inc."; + + break; + case "POS": + manufacturer = "POSTECH Corporation"; + + break; + case "Dvsn+160": + manufacturer = "Digital Storage Technology Co., Ltd."; + + break; + case "ODMS": + manufacturer = "VDL Optical Disc Manufacturing Systems"; + + break; + } + + return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; + } + + public struct PhysicalFormatInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + + #region PFI common to all + /// Byte 4, bits 7 to 4 Disk category field + public DiskCategory DiskCategory; + /// Byte 4, bits 3 to 0 Media version + public byte PartVersion; + /// Byte 5, bits 7 to 4 120mm if 0, 80mm if 1. If UMD (60mm) 0 also. Reserved rest of values + public DVDSize DiscSize; + /// Byte 5, bits 3 to 0 Maximum data rate + public MaximumRateField MaximumRate; + /// Byte 6, bit 7 Reserved + public bool Reserved3; + /// Byte 6, bits 6 to 5 Number of layers + public byte Layers; + /// Byte 6, bit 4 Track path + public bool TrackPath; + /// Byte 6, bits 3 to 0 Layer type + public LayerTypeFieldMask LayerType; + /// Byte 7, bits 7 to 4 Linear density field + public LinearDensityField LinearDensity; + /// Byte 7, bits 3 to 0 Track density field + public TrackDensityField TrackDensity; + /// Bytes 8 to 11 PSN where Data Area starts + public uint DataAreaStartPSN; + /// Bytes 12 to 15 PSN where Data Area ends + public uint DataAreaEndPSN; + /// Bytes 16 to 19 PSN where Data Area ends in Layer 0 + public uint Layer0EndPSN; + /// + /// Byte 20, bit 7 True if BCA exists. GC/Wii discs do not have this bit set, but there is a BCA, making it + /// unreadable in normal DVD drives + /// + public bool BCA; + /// Byte 20, bits 6 to 0 Reserved + public byte Reserved4; + #endregion PFI common to all + + #region UMD PFI + /// Bytes 21 to 22 UMD only, media attribute, application-defined, part of media specific in rest of discs + public ushort MediaAttribute; + #endregion UMD PFI + + #region DVD-RAM PFI + /// Byte 36 Disc type, respecting case recordability + public DVDRAMDiscType DiscType; + #endregion DVD-RAM PFI + + #region DVD-RAM PFI, Version 0001b + /// Byte 52 Byte 504 in Version 0110b Linear velocity, in tenths of m/s + public byte Velocity; + /// Byte 53 Byte 505 in Version 0110b Read power on disk surface, tenths of mW + public byte ReadPower; + /// Byte 54 Byte 507 in Version 0110b Peak power on disk surface for recording land tracks + public byte PeakPower; + /// Byte 55 Bias power on disk surface for recording land tracks + public byte BiasPower; + /// Byte 56 First pulse starting time for recording on land tracks, ns + public byte FirstPulseStart; + /// Byte 57 Byte 515 in Version 0110b First pulse ending time for recording on land tracks + public byte FirstPulseEnd; + /// Byte 58 Byte 518 in Version 0110b Multiple-pulse duration time for recording on land tracks + public byte MultiplePulseDuration; + /// Byte 59 Byte 519 in Version 0110b Last pulse starting time for recording on land tracks + public byte LastPulseStart; + /// Byte 60 Las pulse ending time for recording on land tracks + public byte LastPulseEnd; + /// Byte 61 Bias power duration for recording on land tracks + public byte BiasPowerDuration; + /// Byte 62 Byte 511 on Version 0110b Peak power for recording on groove tracks + public byte PeakPowerGroove; + /// Byte 63 Bias power for recording on groove tracks + public byte BiasPowerGroove; + /// Byte 64 First pulse starting time on groove tracks + public byte FirstPulseStartGroove; + /// Byte 65 First pulse ending time on groove tracks + public byte FirstPulseEndGroove; + /// Byte 66 Multiple-pulse duration time on groove tracks + public byte MultiplePulseDurationGroove; + /// Byte 67 Last pulse starting time on groove tracks + public byte LastPulseStartGroove; + /// Byte 68 Last pulse ending time on groove tracks + public byte LastPulseEndGroove; + /// Byte 69 Bias power duration for recording on groove tracks + public byte BiasPowerDurationGroove; + #endregion DVD-RAM PFI, Version 0001b + + #region DVD-R PFI, DVD-RW PFI + /// Bytes 36 to 39 Sector number of the first sector of the current Border Out + public uint CurrentBorderOutSector; + /// Bytes 40 to 43 Sector number of the first sector of the next Border In + public uint NextBorderInSector; + #endregion DVD-R PFI, DVD-RW PFI + + #region DVD+RW PFI + /// Byte 36 Linear velocities 0 = CLV from 4,90 m/s to 6,25 m/s 1 = CAV from 3,02 m/s to 7,35 m/s + public byte RecordingVelocity; + /// Byte 37 Maximum read power in milliwatts at maximum velocity mW = 20 * (value - 1) + public byte ReadPowerMaxVelocity; + /// Byte 38 Indicative value of Ptarget in mW at maximum velocity + public byte PIndMaxVelocity; + /// Byte 39 Peak power multiplication factor at maximum velocity + public byte PMaxVelocity; + /// Byte 40 Bias1/write power ration at maximum velocity + public byte E1MaxVelocity; + /// Byte 41 Bias2/write power ration at maximum velocity + public byte E2MaxVelocity; + /// Byte 42 Target value for γ, γtarget at the maximum velocity + public byte YTargetMaxVelocity; + /// Byte 43 Maximum read power in milliwatts at reference velocity (4,90 m/s) mW = 20 * (value - 1) + public byte ReadPowerRefVelocity; + /// Byte 44 Indicative value of Ptarget in mW at reference velocity (4,90 m/s) + public byte PIndRefVelocity; + /// Byte 45 Peak power multiplication factor at reference velocity (4,90 m/s) + public byte PRefVelocity; + /// Byte 46 Bias1/write power ration at reference velocity (4,90 m/s) + public byte E1RefVelocity; + /// Byte 47 Bias2/write power ration at reference velocity (4,90 m/s) + public byte E2RefVelocity; + /// Byte 48 Target value for γ, γtarget at the reference velocity (4,90 m/s) + public byte YTargetRefVelocity; + /// Byte 49 Maximum read power in milliwatts at minimum velocity mW = 20 * (value - 1) + public byte ReadPowerMinVelocity; + /// Byte 50 Indicative value of Ptarget in mW at minimum velocity + public byte PIndMinVelocity; + /// Byte 51 Peak power multiplication factor at minimum velocity + public byte PMinVelocity; + /// Byte 52 Bias1/write power ration at minimum velocity + public byte E1MinVelocity; + /// Byte 53 Bias2/write power ration at minimum velocity + public byte E2MinVelocity; + /// Byte 54 Target value for γ, γtarget at the minimum velocity + public byte YTargetMinVelocity; + #endregion DVD+RW PFI + + #region DVD-RAM PFI, version 0110b + /// Byte 506, bit 7 Mode of adaptative write pulse control + public bool AdaptativeWritePulseControlFlag; + /// Byte 508 Bias power 1 on disk surface for recording land tracks + public byte BiasPower1; + /// Byte 509 Bias power 2 on disk surface for recording land tracks + public byte BiasPower2; + /// Byte 510 Bias power 3 on disk surface for recording land tracks + public byte BiasPower3; + /// Byte 512 Bias power 1 on disk surface for recording groove tracks + public byte BiasPower1Groove; + /// Byte 513 Bias power 2 on disk surface for recording groove tracks + public byte BiasPower2Groove; + /// Byte 514 Bias power 3 on disk surface for recording groove tracks + public byte BiasPower3Groove; + /// Byte 516 First pulse duration + public byte FirstPulseDuration; + /// Byte 520 Bias power 2 duration on land tracks at Velocity 1 + public byte BiasPower2Duration; + /// Byte 521 First pulse start time, at Mark 3T and Leading Space 3T + public byte FirstPulseStart3TSpace3T; + /// Byte 522 First pulse start time, at Mark 4T and Leading Space 3T + public byte FirstPulseStart4TSpace3T; + /// Byte 523 First pulse start time, at Mark 5T and Leading Space 3T + public byte FirstPulseStart5TSpace3T; + /// Byte 524 First pulse start time, at Mark >5T and Leading Space 3T + public byte FirstPulseStartSpace3T; + /// Byte 525 First pulse start time, at Mark 3T and Leading Space 4T + public byte FirstPulseStart3TSpace4T; + /// Byte 526 First pulse start time, at Mark 4T and Leading Space 4T + public byte FirstPulseStart4TSpace4T; + /// Byte 527 First pulse start time, at Mark 5T and Leading Space 4T + public byte FirstPulseStart5TSpace4T; + /// Byte 528 First pulse start time, at Mark >5T and Leading Space 4T + public byte FirstPulseStartSpace4T; + /// Byte 529 First pulse start time, at Mark 3T and Leading Space 5T + public byte FirstPulseStart3TSpace5T; + /// Byte 530 First pulse start time, at Mark 4T and Leading Space 5T + public byte FirstPulseStart4TSpace5T; + /// Byte 531 First pulse start time, at Mark 5T and Leading Space 5T + public byte FirstPulseStart5TSpace5T; + /// Byte 532 First pulse start time, at Mark >5T and Leading Space 5T + public byte FirstPulseStartSpace5T; + /// Byte 533 First pulse start time, at Mark 3T and Leading Space >5T + public byte FirstPulseStart3TSpace; + /// Byte 534 First pulse start time, at Mark 4T and Leading Space >5T + public byte FirstPulseStart4TSpace; + /// Byte 535 First pulse start time, at Mark 5T and Leading Space >5T + public byte FirstPulseStart5TSpace; + /// Byte 536 First pulse start time, at Mark >5T and Leading Space >5T + public byte FirstPulseStartSpace; + /// Byte 537 First pulse start time, at Mark 3T and Trailing Space 3T + public byte FirstPulse3TStartTSpace3T; + /// Byte 538 First pulse start time, at Mark 4T and Trailing Space 3T + public byte FirstPulse4TStartTSpace3T; + /// Byte 539 First pulse start time, at Mark 5T and Trailing Space 3T + public byte FirstPulse5TStartTSpace3T; + /// Byte 540 First pulse start time, at Mark >5T and Trailing Space 3T + public byte FirstPulseStartTSpace3T; + /// Byte 541 First pulse start time, at Mark 3T and Trailing Space 4T + public byte FirstPulse3TStartTSpace4T; + /// Byte 542 First pulse start time, at Mark 4T and Trailing Space 4T + public byte FirstPulse4TStartTSpace4T; + /// Byte 543 First pulse start time, at Mark 5T and Trailing Space 4T + public byte FirstPulse5TStartTSpace4T; + /// Byte 544 First pulse start time, at Mark >5T and Trailing Space 4T + public byte FirstPulseStartTSpace4T; + /// Byte 545 First pulse start time, at Mark 3T and Trailing Space 5T + public byte FirstPulse3TStartTSpace5T; + /// Byte 546 First pulse start time, at Mark 4T and Trailing Space 5T + public byte FirstPulse4TStartTSpace5T; + /// Byte 547 First pulse start time, at Mark 5T and Trailing Space 5T + public byte FirstPulse5TStartTSpace5T; + /// Byte 548 First pulse start time, at Mark >5T and Trailing Space 5T + public byte FirstPulseStartTSpace5T; + /// Byte 549 First pulse start time, at Mark 3T and Trailing Space >5T + public byte FirstPulse3TStartTSpace; + /// Byte 550 First pulse start time, at Mark 4T and Trailing Space >5T + public byte FirstPulse4TStartTSpace; + /// Byte 551 First pulse start time, at Mark 5T and Trailing Space >5T + public byte FirstPulse5TStartTSpace; + /// Byte 552 First pulse start time, at Mark >5T and Trailing Space >5T + public byte FirstPulseStartTSpace; + /// Bytes 553 to 600 Disk manufacturer's name, space-padded + public string DiskManufacturer; + /// Bytes 601 to 616 Disk manufacturer's supplementary information + public string DiskManufacturerSupplementary; + /// Bytes 617 to 627 Write power control parameters + public byte[] WritePowerControlParams; + /// Byte 619 Ratio of peak power for land tracks to threshold peak power for land tracks + public byte PowerRatioLandThreshold; + /// Byte 620 Target asymmetry + public byte TargetAsymmetry; + /// Byte 621 Temporary peak power + public byte TemporaryPeakPower; + /// Byte 622 Temporary bias power 1 + public byte TemporaryBiasPower1; + /// Byte 623 Temporary bias power 2 + public byte TemporaryBiasPower2; + /// Byte 624 Temporary bias power 3 + public byte TemporaryBiasPower3; + /// Byte 625 Ratio of peak power for groove tracks to threshold peak power for groove tracks + public byte PowerRatioGrooveThreshold; + /// Byte 626 Ratio of peak power for land tracks to threshold 6T peak power for land tracks + public byte PowerRatioLandThreshold6T; + /// Byte 627 Ratio of peak power for groove tracks to threshold 6T peak power for groove tracks + public byte PowerRatioGrooveThreshold6T; + #endregion DVD-RAM PFI, version 0110b + + #region DVD+RW PFI, DVD+R PFI, DVD+R DL PFI and DVD+RW DL PFI + /// Byte 20, bit 6 If set indicates data zone contains extended information for VCPS + public bool VCPS; + /// Byte 21 Indicates restricted usage disk + public byte ApplicationCode; + /// Byte 22 Bitmap of extended information block presence + public byte ExtendedInformation; + /// Bytes 23 to 30 Disk manufacturer ID, null-padded + public string DiskManufacturerID; + /// Bytes 31 to 33 Media type ID, null-padded + public string MediaTypeID; + /// Byte 34 Product revision number + public byte ProductRevision; + /// Byte 35 Indicates how many bytes, up to 63, are used in ADIP's PFI + public byte PFIUsedInADIP; + #endregion DVD+RW PFI, DVD+R PFI, DVD+R DL PFI and DVD+RW DL PFI + + #region DVD+RW PFI, version 0010b + /// Byte 55 Ttop first pulse duration + public byte TopFirstPulseDuration; + /// Byte 56 Tmp multi pulse duration + public byte MultiPulseDuration; + /// Byte 57 dTtop first pulse lead time + public byte FirstPulseLeadTime; + /// Byte 58 dTera erase lead time at reference velocity + public byte EraseLeadTimeRefVelocity; + /// Byte 59 dTera erase lead time at upper velocity + public byte EraseLeadTimeUppVelocity; + #endregion DVD+RW PFI, version 0010b + + #region DVD+R PFI version 0001b and DVD+R DL PFI version 0001b + /// Byte 36 Primary recording velocity for the basic write strategy + public byte PrimaryVelocity; + /// Byte 37 Upper recording velocity for the basic write strategy + public byte UpperVelocity; + /// Byte 38 Wavelength λIND + public byte Wavelength; + /// Byte 39 Normalized write power dependency on wavelength (dP/dλ)/(PIND/λIND) + public byte NormalizedPowerDependency; + /// Byte 40 Maximum read power at primary velocity + public byte MaximumPowerAtPrimaryVelocity; + /// Byte 41 Pind at primary velocity + public byte PindAtPrimaryVelocity; + /// Byte 42 βtarget at primary velocity + public byte BtargetAtPrimaryVelocity; + /// Byte 43 Maximum read power at upper velocity + public byte MaximumPowerAtUpperVelocity; + /// Byte 44 Pind at primary velocity + public byte PindAtUpperVelocity; + /// Byte 45 βtarget at upper velocity + public byte BtargetAtUpperVelocity; + /// Byte 46 Ttop (≥4T) first pulse duration for cm∗ ≥4T at Primary velocity + public byte FirstPulseDuration4TPrimaryVelocity; + /// Byte 47 Ttop (=3T) first pulse duration for cm∗ =3T at Primary velocity + public byte FirstPulseDuration3TPrimaryVelocity; + /// Byte 48 Tmp multi pulse duration at Primary velocity + public byte MultiPulseDurationPrimaryVelocity; + /// Byte 49 Tlp last pulse duration at Primary velocity + public byte LastPulseDurationPrimaryVelocity; + /// Byte 50 dTtop (≥4T) first pulse lead time for cm∗ ≥4T at Primary velocity + public byte FirstPulseLeadTime4TPrimaryVelocity; + /// Byte 51 dTtop (=3T) first pulse lead time for cm∗ =3T at Primary velocity + public byte FirstPulseLeadTime3TPrimaryVelocity; + /// Byte 52 dTle first pulse leading edge shift for ps∗ =3T at Primary velocity + public byte FirstPulseLeadingEdgePrimaryVelocity; + /// Byte 53 Ttop (≥4T) first pulse duration for cm∗ ≥4T at Upper velocity + public byte FirstPulseDuration4TUpperVelocity; + /// Byte 54 Ttop (=3T) first pulse duration for cm∗ =3T at Upper velocity + public byte FirstPulseDuration3TUpperVelocity; + /// Byte 55 Tmp multi pulse duration at Upper velocity + public byte MultiPulseDurationUpperVelocity; + /// Byte 56 Tlp last pulse duration at Upper velocity + public byte LastPulseDurationUpperVelocity; + /// Byte 57 dTtop (≥4T) first pulse lead time for cm∗ ≥4T at Upper velocity + public byte FirstPulseLeadTime4TUpperVelocity; + /// Byte 58 dTtop (=3T) first pulse lead time for cm∗ =3T at Upper velocity + public byte FirstPulseLeadTime3TUpperVelocity; + /// Byte 59 dTle first pulse leading edge shift for ps∗ =3T at Upper velocity + public byte FirstPulseLeadingEdgeUpperVelocity; + #endregion DVD+R PFI version 0001b and DVD+R DL PFI version 0001b + + #region DVD+R DL PFI version 0001b + /// Byte 34, bits 7 to 6 + public DVDLayerStructure LayerStructure; + #endregion DVD+R DL PFI version 0001b + + #region DVD+RW DL PFI + /// Byte 36 Primary recording velocity for the basic write strategy + public byte BasicPrimaryVelocity; + /// Byte 37 Maximum read power at Primary velocity + public byte MaxReadPowerPrimaryVelocity; + /// Byte 38 PIND at Primary velocity + public byte PindPrimaryVelocity; + /// Byte 39 ρ at Primary velocity + public byte PPrimaryVelocity; + /// Byte 40 ε1 at Primary velocity + public byte E1PrimaryVelocity; + /// Byte 41 ε2 at Primary velocity + public byte E2PrimaryVelocity; + /// Byte 42 γtarget at Primary velocity + public byte YtargetPrimaryVelocity; + /// Byte 43 β optimum at Primary velocity + public byte BOptimumPrimaryVelocity; + /// Byte 46 Ttop first pulse duration + public byte TFirstPulseDuration; + /// Byte 47 Tmp multi pulse duration + public byte TMultiPulseDuration; + /// Byte 48 dTtop first pulse lead/lag time for any runlength ≥ 4T + public byte FirstPulseLeadTimeAnyRun; + /// Byte 49 dTtop,3 first pulse lead/lag time for runlengths = 3T + public byte FirstPulseLeadTimeRun3T; + /// Byte 50 dTlp last pulse lead/lag time for any runlength ≥ 5T + public byte LastPulseLeadTimeAnyRun; + /// Byte 51 dTlp,3 last pulse lead/lag time for runlengths = 3T + public byte LastPulseLeadTime3T; + /// Byte 52 dTlp,4 last pulse lead/lag time for runlengths = 4T + public byte LastPulseLeadTime4T; + /// Byte 53 dTera erase lead/lag time when preceding mark length ≥ 5T + public byte ErasePulseLeadTimeAny; + /// Byte 54 dTera,3 erase lead/lag time when preceding mark length = 3T + public byte ErasePulseLeadTime3T; + /// Byte 55 dTera,4 erase lead/lag time when preceding mark length = 4T + public byte ErasePulseLeadTime4T; + #endregion DVD+RW DL PFI + + #region DVD-R DL PFI and DVD-RW DL PFI + /// Byte 21 Maximum recording speed + public DVDRecordingSpeed MaxRecordingSpeed; + /// Byte 22 Minimum recording speed + public DVDRecordingSpeed MinRecordingSpeed; + /// Byte 23 Another recording speed + public DVDRecordingSpeed RecordingSpeed1; + /// Byte 24 Another recording speed + public DVDRecordingSpeed RecordingSpeed2; + /// Byte 25 Another recording speed + public DVDRecordingSpeed RecordingSpeed3; + /// Byte 26 Another recording speed + public DVDRecordingSpeed RecordingSpeed4; + /// Byte 27 Another recording speed + public DVDRecordingSpeed RecordingSpeed5; + /// Byte 28 Another recording speed + public DVDRecordingSpeed RecordingSpeed6; + /// Byte 29 Another recording speed + public DVDRecordingSpeed RecordingSpeed7; + /// Byte 30 Class + public byte Class; + /// Byte 31 Extended version. 0x30 = ECMA-382, 0x20 = ECMA-384 + public byte ExtendedVersion; + /// Byte 36 Start sector number of current RMD in Extra Border Zone + public uint CurrentRMDExtraBorderPSN; + /// Byte 40 Start sector number of Physical Format Information blocks in Extra Border Zone + public uint PFIExtraBorderPSN; + /// Byte 44, bit 0 If NOT set, Control Data Zone is pre-recorded + public bool PreRecordedControlDataInv; + /// Byte 44 bit 1 Lead-in Zone is pre-recorded + public bool PreRecordedLeadIn; + /// Byte 44 bit 3 Lead-out Zone is pre-recorded + public bool PreRecordedLeadOut; + /// Byte 45 bits 0 to 3 AR characteristic of LPP on Layer 1 + public byte ARCharLayer1; + /// Byte 45 bits 4 to 7 Tracking polarity on Layer 1 + public byte TrackPolarityLayer1; + #endregion DVD-R DL PFI and DVD-RW DL PFI + + public DiskCategory RecordedBookType; + } } \ No newline at end of file diff --git a/DVD/PRI.cs b/DVD/PRI.cs index fa597e4..3aabd62 100644 --- a/DVD/PRI.cs +++ b/DVD/PRI.cs @@ -35,591 +35,590 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class PRI { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class PRI + public static PreRecordedInformation? Decode(byte[] response) { - public static PreRecordedInformation? Decode(byte[] response) + if(response == null) + return null; + + if(response.Length < 67) + return null; + + var pri = new PreRecordedInformation(); + byte[] tmp; + + pri.DataLength = (ushort)((response[0] << 8) + response[1]); + pri.Reserved1 = response[2]; + pri.Reserved2 = response[3]; + + pri.FieldId1 = response[4]; + pri.FieldId2 = response[12]; + pri.FieldId3 = response[20]; + pri.FieldId4 = response[28]; + pri.FieldId5 = response[36]; + + if(pri.FieldId1 != 1 || + pri.FieldId2 != 2 || + pri.FieldId3 != 3 || + pri.FieldId4 != 4 || + pri.FieldId5 != 5) + return null; + + pri.DiscApplicationCode = response[5]; + pri.DiscPhysicalCode = response[6]; + pri.LastAddressOfDataRecordableArea = (uint)((response[7] << 16) + (response[8] << 8) + response[9]); + pri.PartVersion = (byte)(response[10] >> 4); + pri.ExtensionCode = (byte)(response[10] & 0xF); + pri.Reserved3 = response[11]; + pri.OPCSuggestedCode = response[13]; + pri.WaveLengthCode = response[14]; + + pri.WriteStrategyCode = + (uint)((response[15] << 24) + (response[16] << 16) + (response[17] << 8) + response[18]); + + pri.Reserved4 = response[19]; + pri.ManufacturerId1 = new byte[6]; + pri.Reserved5 = response[27]; + pri.ManufacturerId2 = new byte[6]; + pri.Reserved6 = response[35]; + pri.ManufacturerId3 = new byte[6]; + pri.Reserved7 = response[43]; + pri.Reserved8 = new byte[response.Length - 44]; + + Array.Copy(response, 21, pri.ManufacturerId1, 0, 6); + Array.Copy(response, 29, pri.ManufacturerId2, 0, 6); + Array.Copy(response, 37, pri.ManufacturerId3, 0, 6); + Array.Copy(response, 44, pri.Reserved8, 0, pri.Reserved8.Length); + + tmp = new byte[18]; + + Array.Copy(response, 21, tmp, 0, 6); + Array.Copy(response, 29, tmp, 6, 6); + + // If RW or has part version or has extension code, 3rd manufacturer ID is a write strategy code + if((pri.DiscPhysicalCode & 0x2) > 0 || + pri.PartVersion > 0 || + pri.ExtensionCode > 0) + pri.WriteStrategyCode2 = + (uint)((response[37] << 24) + (response[38] << 16) + (response[39] << 8) + response[40]); + else + Array.Copy(response, 37, tmp, 12, 6); + + pri.ManufacturerId = StringHandlers.CToString(tmp, Encoding.ASCII).Trim(); + + return pri; + } + + public static string Prettify(PreRecordedInformation? pri) + { + if(pri == null) + return null; + + PreRecordedInformation decoded = pri.Value; + var sb = new StringBuilder(); + + if((decoded.DiscApplicationCode & 0x40) > 0) { - if(response == null) - return null; + sb.AppendLine("Disc for unrestricted use."); - if(response.Length < 67) - return null; - - var pri = new PreRecordedInformation(); - byte[] tmp; - - pri.DataLength = (ushort)((response[0] << 8) + response[1]); - pri.Reserved1 = response[2]; - pri.Reserved2 = response[3]; - - pri.FieldId1 = response[4]; - pri.FieldId2 = response[12]; - pri.FieldId3 = response[20]; - pri.FieldId4 = response[28]; - pri.FieldId5 = response[36]; - - if(pri.FieldId1 != 1 || - pri.FieldId2 != 2 || - pri.FieldId3 != 3 || - pri.FieldId4 != 4 || - pri.FieldId5 != 5) - return null; - - pri.DiscApplicationCode = response[5]; - pri.DiscPhysicalCode = response[6]; - pri.LastAddressOfDataRecordableArea = (uint)((response[7] << 16) + (response[8] << 8) + response[9]); - pri.PartVersion = (byte)(response[10] >> 4); - pri.ExtensionCode = (byte)(response[10] & 0xF); - pri.Reserved3 = response[11]; - pri.OPCSuggestedCode = response[13]; - pri.WaveLengthCode = response[14]; - - pri.WriteStrategyCode = - (uint)((response[15] << 24) + (response[16] << 16) + (response[17] << 8) + response[18]); - - pri.Reserved4 = response[19]; - pri.ManufacturerId1 = new byte[6]; - pri.Reserved5 = response[27]; - pri.ManufacturerId2 = new byte[6]; - pri.Reserved6 = response[35]; - pri.ManufacturerId3 = new byte[6]; - pri.Reserved7 = response[43]; - pri.Reserved8 = new byte[response.Length - 44]; - - Array.Copy(response, 21, pri.ManufacturerId1, 0, 6); - Array.Copy(response, 29, pri.ManufacturerId2, 0, 6); - Array.Copy(response, 37, pri.ManufacturerId3, 0, 6); - Array.Copy(response, 44, pri.Reserved8, 0, pri.Reserved8.Length); - - tmp = new byte[18]; - - Array.Copy(response, 21, tmp, 0, 6); - Array.Copy(response, 29, tmp, 6, 6); - - // If RW or has part version or has extension code, 3rd manufacturer ID is a write strategy code - if((pri.DiscPhysicalCode & 0x2) > 0 || - pri.PartVersion > 0 || - pri.ExtensionCode > 0) - pri.WriteStrategyCode2 = - (uint)((response[37] << 24) + (response[38] << 16) + (response[39] << 8) + response[40]); + if((decoded.DiscApplicationCode & 0x3F) > 0) + sb.AppendFormat("Invalid purpose field with value {0}", decoded.DiscApplicationCode & 0x3F). + AppendLine(); else - Array.Copy(response, 37, tmp, 12, 6); + sb.AppendLine("Consumer purpose disc for use in consumer purpose drives"); + } + else + { + sb.AppendLine("Disc for restricted use."); - pri.ManufacturerId = StringHandlers.CToString(tmp, Encoding.ASCII).Trim(); - - return pri; + if((decoded.DiscApplicationCode & 0x3F) > 0) + sb.AppendFormat("Disc for use in special drives according with purpose value {0}", + decoded.DiscApplicationCode & 0x3F).AppendLine(); + else + sb.AppendLine("General purpose disc for use in general purpose drives"); } - public static string Prettify(PreRecordedInformation? pri) + sb.AppendLine((decoded.DiscPhysicalCode & 0x80) > 0 ? "Disc track pitch is 0,74 μm" + : "Unknown track pitch"); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x40) > 0 ? "Reference velocity is 3,49 m/s" + : "Unknown reference velocity"); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x20) > 0 ? "Disc has 80mm diameter" : "Disc has 120mm diameter"); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x10) > 0 ? "Disc reflectivity is between 18% and 30%" + : "Disc reflectivity is between 45% and 85%"); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x04) > 0 ? "Dye is organic" : "Dye is phase change"); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x02) > 0 ? "Disc is RW (rewritable)" : "Disc is R (recordable)"); + + sb.AppendLine((decoded.DiscPhysicalCode & 0x01) > 0 ? "Wavelength is 650nm" : "Unknown wavelength"); + + sb.AppendFormat("Last writable ECC block address: 0x{0:X6}", decoded.LastAddressOfDataRecordableArea). + AppendLine(); + + if(decoded.PartVersion > 0) + sb.AppendFormat("Part version {0}", decoded.PartVersion).AppendLine(); + + bool rw = (decoded.DiscPhysicalCode & 0x02) > 0; + + if(rw) { - if(pri == null) - return null; - - PreRecordedInformation decoded = pri.Value; - var sb = new StringBuilder(); - - if((decoded.DiscApplicationCode & 0x40) > 0) + if((decoded.OPCSuggestedCode & 0xF) > 0) { - sb.AppendLine("Disc for unrestricted use."); + double recordingPower = 0; - if((decoded.DiscApplicationCode & 0x3F) > 0) - sb.AppendFormat("Invalid purpose field with value {0}", decoded.DiscApplicationCode & 0x3F). - AppendLine(); - else - sb.AppendLine("Consumer purpose disc for use in consumer purpose drives"); + switch(decoded.OPCSuggestedCode & 0xF) + { + case 1: + recordingPower = 7.0; + + break; + case 2: + recordingPower = 7.5; + + break; + case 3: + recordingPower = 8.0; + + break; + case 4: + recordingPower = 8.5; + + break; + case 5: + recordingPower = 9.0; + + break; + case 6: + recordingPower = 9.5; + + break; + case 7: + recordingPower = 10.0; + + break; + case 8: + recordingPower = 10.5; + + break; + case 9: + recordingPower = 11.0; + + break; + case 10: + recordingPower = 11.5; + + break; + case 11: + recordingPower = 12.0; + + break; + case 12: + recordingPower = 12.5; + + break; + case 13: + recordingPower = 13.0; + + break; + case 14: + recordingPower = 13.5; + + break; + case 15: + recordingPower = 14.0; + + break; + } + + sb.AppendFormat("Recommended recording power is {0} mW", recordingPower).AppendLine(); } else { - sb.AppendLine("Disc for restricted use."); - - if((decoded.DiscApplicationCode & 0x3F) > 0) - sb.AppendFormat("Disc for use in special drives according with purpose value {0}", - decoded.DiscApplicationCode & 0x3F).AppendLine(); - else - sb.AppendLine("General purpose disc for use in general purpose drives"); + sb.AppendLine("Recording power is not specified"); } - sb.AppendLine((decoded.DiscPhysicalCode & 0x80) > 0 ? "Disc track pitch is 0,74 μm" - : "Unknown track pitch"); - - sb.AppendLine((decoded.DiscPhysicalCode & 0x40) > 0 ? "Reference velocity is 3,49 m/s" - : "Unknown reference velocity"); - - sb.AppendLine((decoded.DiscPhysicalCode & 0x20) > 0 ? "Disc has 80mm diameter" : "Disc has 120mm diameter"); - - sb.AppendLine((decoded.DiscPhysicalCode & 0x10) > 0 ? "Disc reflectivity is between 18% and 30%" - : "Disc reflectivity is between 45% and 85%"); - - sb.AppendLine((decoded.DiscPhysicalCode & 0x04) > 0 ? "Dye is organic" : "Dye is phase change"); - - sb.AppendLine((decoded.DiscPhysicalCode & 0x02) > 0 ? "Disc is RW (rewritable)" : "Disc is R (recordable)"); - - sb.AppendLine((decoded.DiscPhysicalCode & 0x01) > 0 ? "Wavelength is 650nm" : "Unknown wavelength"); - - sb.AppendFormat("Last writable ECC block address: 0x{0:X6}", decoded.LastAddressOfDataRecordableArea). - AppendLine(); - - if(decoded.PartVersion > 0) - sb.AppendFormat("Part version {0}", decoded.PartVersion).AppendLine(); - - bool rw = (decoded.DiscPhysicalCode & 0x02) > 0; - - if(rw) + if((decoded.WaveLengthCode & 0xF) > 0) { - if((decoded.OPCSuggestedCode & 0xF) > 0) + double erasingPower = 0; + + switch(decoded.WaveLengthCode & 0xF) { - double recordingPower = 0; + case 1: + erasingPower = 0.38; - switch(decoded.OPCSuggestedCode & 0xF) - { - case 1: - recordingPower = 7.0; + break; + case 2: + erasingPower = 0.40; - break; - case 2: - recordingPower = 7.5; + break; + case 3: + erasingPower = 0.42; - break; - case 3: - recordingPower = 8.0; + break; + case 4: + erasingPower = 0.44; - break; - case 4: - recordingPower = 8.5; + break; + case 5: + erasingPower = 0.46; - break; - case 5: - recordingPower = 9.0; + break; + case 6: + erasingPower = 0.48; - break; - case 6: - recordingPower = 9.5; + break; + case 7: + erasingPower = 0.50; - break; - case 7: - recordingPower = 10.0; + break; + case 8: + erasingPower = 0.52; - break; - case 8: - recordingPower = 10.5; + break; + case 9: + erasingPower = 0.54; - break; - case 9: - recordingPower = 11.0; + break; + case 10: + erasingPower = 0.56; - break; - case 10: - recordingPower = 11.5; + break; + case 11: + erasingPower = 0.58; - break; - case 11: - recordingPower = 12.0; + break; + case 12: + erasingPower = 0.60; - break; - case 12: - recordingPower = 12.5; + break; + case 13: + erasingPower = 0.62; - break; - case 13: - recordingPower = 13.0; + break; + case 14: + erasingPower = 0.64; - break; - case 14: - recordingPower = 13.5; + break; + case 15: + erasingPower = 0.66; - break; - case 15: - recordingPower = 14.0; - - break; - } - - sb.AppendFormat("Recommended recording power is {0} mW", recordingPower).AppendLine(); - } - else - { - sb.AppendLine("Recording power is not specified"); + break; } - if((decoded.WaveLengthCode & 0xF) > 0) - { - double erasingPower = 0; - - switch(decoded.WaveLengthCode & 0xF) - { - case 1: - erasingPower = 0.38; - - break; - case 2: - erasingPower = 0.40; - - break; - case 3: - erasingPower = 0.42; - - break; - case 4: - erasingPower = 0.44; - - break; - case 5: - erasingPower = 0.46; - - break; - case 6: - erasingPower = 0.48; - - break; - case 7: - erasingPower = 0.50; - - break; - case 8: - erasingPower = 0.52; - - break; - case 9: - erasingPower = 0.54; - - break; - case 10: - erasingPower = 0.56; - - break; - case 11: - erasingPower = 0.58; - - break; - case 12: - erasingPower = 0.60; - - break; - case 13: - erasingPower = 0.62; - - break; - case 14: - erasingPower = 0.64; - - break; - case 15: - erasingPower = 0.66; - - break; - } - - sb.AppendFormat("Recommended erasing power ratio is {0} ε", erasingPower).AppendLine(); - } - else - { - sb.AppendLine("Erasing power ratio is not specified"); - } + sb.AppendFormat("Recommended erasing power ratio is {0} ε", erasingPower).AppendLine(); } else { - if((decoded.OPCSuggestedCode & 0xF) > 0) + sb.AppendLine("Erasing power ratio is not specified"); + } + } + else + { + if((decoded.OPCSuggestedCode & 0xF) > 0) + { + double recordingPower = 0; + + switch(decoded.OPCSuggestedCode & 0xF) { - double recordingPower = 0; + case 1: + recordingPower = 6.0; - switch(decoded.OPCSuggestedCode & 0xF) - { - case 1: - recordingPower = 6.0; + break; + case 2: + recordingPower = 6.5; - break; - case 2: - recordingPower = 6.5; + break; + case 3: + recordingPower = 7.0; - break; - case 3: - recordingPower = 7.0; + break; + case 4: + recordingPower = 7.5; - break; - case 4: - recordingPower = 7.5; + break; + case 5: + recordingPower = 8.0; - break; - case 5: - recordingPower = 8.0; + break; + case 6: + recordingPower = 8.5; - break; - case 6: - recordingPower = 8.5; + break; + case 7: + recordingPower = 9.0; - break; - case 7: - recordingPower = 9.0; + break; + case 8: + recordingPower = 9.5; - break; - case 8: - recordingPower = 9.5; + break; + case 9: + recordingPower = 10.0; - break; - case 9: - recordingPower = 10.0; + break; + case 10: + recordingPower = 10.5; - break; - case 10: - recordingPower = 10.5; + break; + case 11: + recordingPower = 11.0; - break; - case 11: - recordingPower = 11.0; + break; + case 12: + recordingPower = 11.5; - break; - case 12: - recordingPower = 11.5; + break; + case 13: + recordingPower = 12.0; - break; - case 13: - recordingPower = 12.0; - - break; - } - - sb.AppendFormat("Recommended recording power is {0} mW", recordingPower).AppendLine(); + break; } - if(decoded.WaveLengthCode > 0) - { - int wavelength = 0; - - switch(decoded.WaveLengthCode) - { - case 1: - wavelength = 645; - - break; - case 2: - wavelength = 646; - - break; - case 3: - wavelength = 647; - - break; - case 4: - wavelength = 648; - - break; - case 5: - wavelength = 649; - - break; - case 6: - wavelength = 650; - - break; - case 7: - wavelength = 651; - - break; - case 8: - wavelength = 652; - - break; - case 9: - wavelength = 653; - - break; - case 10: - wavelength = 654; - - break; - case 11: - wavelength = 655; - - break; - case 12: - wavelength = 656; - - break; - case 13: - wavelength = 657; - - break; - case 14: - wavelength = 658; - - break; - case 15: - wavelength = 659; - - break; - case 16: - wavelength = 660; - - break; - } - - sb.AppendFormat("Recommended recording power is {0} mW", wavelength).AppendLine(); - } + sb.AppendFormat("Recommended recording power is {0} mW", recordingPower).AppendLine(); } - sb.AppendFormat("Disc manufacturer is {0}", ManufacturerFromPrePit(decoded.ManufacturerId)).AppendLine(); + if(decoded.WaveLengthCode > 0) + { + int wavelength = 0; - return sb.ToString(); + switch(decoded.WaveLengthCode) + { + case 1: + wavelength = 645; + + break; + case 2: + wavelength = 646; + + break; + case 3: + wavelength = 647; + + break; + case 4: + wavelength = 648; + + break; + case 5: + wavelength = 649; + + break; + case 6: + wavelength = 650; + + break; + case 7: + wavelength = 651; + + break; + case 8: + wavelength = 652; + + break; + case 9: + wavelength = 653; + + break; + case 10: + wavelength = 654; + + break; + case 11: + wavelength = 655; + + break; + case 12: + wavelength = 656; + + break; + case 13: + wavelength = 657; + + break; + case 14: + wavelength = 658; + + break; + case 15: + wavelength = 659; + + break; + case 16: + wavelength = 660; + + break; + } + + sb.AppendFormat("Recommended recording power is {0} mW", wavelength).AppendLine(); + } } - public static string Prettify(byte[] response) => Prettify(Decode(response)); + sb.AppendFormat("Disc manufacturer is {0}", ManufacturerFromPrePit(decoded.ManufacturerId)).AppendLine(); - public static string ManufacturerFromPrePit(string manufacturerId) - { - string manufacturer = ""; + return sb.ToString(); + } - // Bad thing is that it also includes a media code... - if(manufacturerId.StartsWith("RITEK", StringComparison.Ordinal)) - manufacturer = "Ritek Co."; - else if(manufacturerId.StartsWith("CMC", StringComparison.Ordinal)) - manufacturer = "CMC Magnetics Corporation"; - else if(manufacturerId.StartsWith("Dvsn-", StringComparison.Ordinal)) - manufacturer = "Digital Storage Technology Co., Ltd."; - else if(manufacturerId.StartsWith("GSC", StringComparison.Ordinal)) - manufacturer = "Gigastore Corporation"; - else if(manufacturerId.StartsWith("INFOMEDIA", StringComparison.Ordinal)) - manufacturer = "InfoMedia Inc."; - else if(manufacturerId.StartsWith("ISSM", StringComparison.Ordinal)) - manufacturer = "Info Source Digital Media (Zhongshan) Co., Ltd."; - else if(manufacturerId.StartsWith("LEADDATA", StringComparison.Ordinal)) - manufacturer = "Lead Data Inc."; - else if(manufacturerId.StartsWith("MCC", StringComparison.Ordinal) || - manufacturerId.StartsWith("MKM", StringComparison.Ordinal)) - manufacturer = "Mitsubishi Kagaku Media Co., LTD."; - else if(manufacturerId.StartsWith("MUST", StringComparison.Ordinal)) - manufacturer = "Must Technology Co., Ltd."; - else if(manufacturerId.StartsWith("MXL", StringComparison.Ordinal)) - manufacturer = "Hitachi Maxell, Ltd."; - else if(manufacturerId.StartsWith("PRINCO", StringComparison.Ordinal)) - manufacturer = "Princo Corporation"; - else if(manufacturerId.StartsWith("Prodisc", StringComparison.Ordinal)) - manufacturer = "Prodisc Technology Inc."; - else if(manufacturerId.StartsWith("SONY", StringComparison.Ordinal) || - manufacturerId.StartsWith("80SONY", StringComparison.Ordinal)) - manufacturer = "Sony Corporation"; - else if(manufacturerId.StartsWith("TCLDS", StringComparison.Ordinal)) - manufacturer = "TCL Technology"; - else if(manufacturerId.StartsWith("TMI", StringComparison.Ordinal)) - manufacturer = "ThaiMedia Co., Ltd. "; - else if(manufacturerId.StartsWith("TY", StringComparison.Ordinal)) - manufacturer = "Taiyo Yuden Company Ltd."; - else if(manufacturerId.StartsWith("UME", StringComparison.Ordinal)) - manufacturer = "Avic Umedisc HK Ltd."; - else if(manufacturerId.StartsWith("DAXON", StringComparison.Ordinal)) - manufacturer = "Daxon Technology Inc."; - else if(manufacturerId.StartsWith("FTI", StringComparison.Ordinal)) - manufacturer = "Falcon Technologies International L.L.C."; - else if(manufacturerId.StartsWith("FUJIFILM", StringComparison.Ordinal)) - manufacturer = "Fuji Photo Film, Co., Ltd."; - else if(manufacturerId.StartsWith("MBI", StringComparison.Ordinal)) - manufacturer = "Moser Baer India Ltd."; - else if(manufacturerId.StartsWith("TT", StringComparison.Ordinal) || - manufacturerId.StartsWith("TDK", StringComparison.Ordinal)) - manufacturer = "TDK Corporation"; - else if(manufacturerId.StartsWith("JVC", StringComparison.Ordinal)) - manufacturer = "Victor Advanced media Co., Ltd."; - else if(manufacturerId.StartsWith("MEI", StringComparison.Ordinal)) - manufacturer = "Matsushita Electric Industrial Co., Ltd."; - else if(manufacturerId.StartsWith("OPTODISC", StringComparison.Ordinal)) - manufacturer = "OptoDisc Ltd."; - else if(manufacturerId.StartsWith("KIC", StringComparison.Ordinal)) - manufacturer = "Advance Media Corporation"; - else if(manufacturerId.StartsWith("IMC", StringComparison.Ordinal)) - manufacturer = "Intermedia Co., Ltd."; - else if(manufacturerId.StartsWith("LGE", StringComparison.Ordinal)) - manufacturer = "LG Electronics Inc."; - else if(manufacturerId.StartsWith("KDT", StringComparison.Ordinal)) - manufacturer = "King Disc Technology Corporation"; - else if(manufacturerId.StartsWith("POS", StringComparison.Ordinal)) - manufacturer = "POSTECH Corporation"; - else if(manufacturerId.StartsWith("VDSPMSAB", StringComparison.Ordinal)) - manufacturer = "Interaxia Digital Storage Materials AG"; - else if(manufacturerId.StartsWith("VANGUARD", StringComparison.Ordinal)) - manufacturer = "Vanguard Disc Inc."; - else if(manufacturerId.StartsWith("MJC", StringComparison.Ordinal)) - manufacturer = "Megan Media Holdings Berhad"; - else if(manufacturerId.StartsWith("DKM", StringComparison.Ordinal) || - manufacturerId.StartsWith("EDMA", StringComparison.Ordinal)) - manufacturer = "E-TOP Mediatek Inc."; - else if(manufacturerId.StartsWith("BeAll", StringComparison.Ordinal)) - manufacturer = "BeALL Developers, Inc."; + public static string Prettify(byte[] response) => Prettify(Decode(response)); - return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; - } + public static string ManufacturerFromPrePit(string manufacturerId) + { + string manufacturer = ""; - public struct PreRecordedInformation - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 == 1 - public byte FieldId1; - /// Byte 5 disc application code - public byte DiscApplicationCode; - /// Byte 6 disc physical code - public byte DiscPhysicalCode; - /// Bytes 7 to 9 last address of data recordable area - public uint LastAddressOfDataRecordableArea; - /// Byte 10, bits 7 to 4 part version - public byte PartVersion; - /// Byte 10, bits 3 to 0 extension code - public byte ExtensionCode; - /// Byte 11 reserved - public byte Reserved3; - /// Byte 12 == 2 - public byte FieldId2; - /// Byte 13 OPC suggested code - public byte OPCSuggestedCode; - /// Byte 14 wavelength code or second part of OPC suggested code - public byte WaveLengthCode; - /// Bytes 15 to 18 write strategy code - public uint WriteStrategyCode; - /// Byte 19 reserved - public byte Reserved4; - /// Byte 20 == 3 - public byte FieldId3; - /// Bytes 21 to 26 first part of manufacturer ID - public byte[] ManufacturerId1; - /// Byte 27 - public byte Reserved5; - /// Byte 28 == 4 - public byte FieldId4; - /// Bytes 29 to 34 second part of manufacturer ID - public byte[] ManufacturerId2; - /// Byte 35 reserved - public byte Reserved6; - /// Byte 36 == 5 - public byte FieldId5; - /// Bytes 37 to 42, third part of manufacturer code or write strategy code for RW and R later versions - public byte[] ManufacturerId3; - /// Byte 43 reserved - public byte Reserved7; - /// Bytes 44 to 68 reserved - public byte[] Reserved8; + // Bad thing is that it also includes a media code... + if(manufacturerId.StartsWith("RITEK", StringComparison.Ordinal)) + manufacturer = "Ritek Co."; + else if(manufacturerId.StartsWith("CMC", StringComparison.Ordinal)) + manufacturer = "CMC Magnetics Corporation"; + else if(manufacturerId.StartsWith("Dvsn-", StringComparison.Ordinal)) + manufacturer = "Digital Storage Technology Co., Ltd."; + else if(manufacturerId.StartsWith("GSC", StringComparison.Ordinal)) + manufacturer = "Gigastore Corporation"; + else if(manufacturerId.StartsWith("INFOMEDIA", StringComparison.Ordinal)) + manufacturer = "InfoMedia Inc."; + else if(manufacturerId.StartsWith("ISSM", StringComparison.Ordinal)) + manufacturer = "Info Source Digital Media (Zhongshan) Co., Ltd."; + else if(manufacturerId.StartsWith("LEADDATA", StringComparison.Ordinal)) + manufacturer = "Lead Data Inc."; + else if(manufacturerId.StartsWith("MCC", StringComparison.Ordinal) || + manufacturerId.StartsWith("MKM", StringComparison.Ordinal)) + manufacturer = "Mitsubishi Kagaku Media Co., LTD."; + else if(manufacturerId.StartsWith("MUST", StringComparison.Ordinal)) + manufacturer = "Must Technology Co., Ltd."; + else if(manufacturerId.StartsWith("MXL", StringComparison.Ordinal)) + manufacturer = "Hitachi Maxell, Ltd."; + else if(manufacturerId.StartsWith("PRINCO", StringComparison.Ordinal)) + manufacturer = "Princo Corporation"; + else if(manufacturerId.StartsWith("Prodisc", StringComparison.Ordinal)) + manufacturer = "Prodisc Technology Inc."; + else if(manufacturerId.StartsWith("SONY", StringComparison.Ordinal) || + manufacturerId.StartsWith("80SONY", StringComparison.Ordinal)) + manufacturer = "Sony Corporation"; + else if(manufacturerId.StartsWith("TCLDS", StringComparison.Ordinal)) + manufacturer = "TCL Technology"; + else if(manufacturerId.StartsWith("TMI", StringComparison.Ordinal)) + manufacturer = "ThaiMedia Co., Ltd. "; + else if(manufacturerId.StartsWith("TY", StringComparison.Ordinal)) + manufacturer = "Taiyo Yuden Company Ltd."; + else if(manufacturerId.StartsWith("UME", StringComparison.Ordinal)) + manufacturer = "Avic Umedisc HK Ltd."; + else if(manufacturerId.StartsWith("DAXON", StringComparison.Ordinal)) + manufacturer = "Daxon Technology Inc."; + else if(manufacturerId.StartsWith("FTI", StringComparison.Ordinal)) + manufacturer = "Falcon Technologies International L.L.C."; + else if(manufacturerId.StartsWith("FUJIFILM", StringComparison.Ordinal)) + manufacturer = "Fuji Photo Film, Co., Ltd."; + else if(manufacturerId.StartsWith("MBI", StringComparison.Ordinal)) + manufacturer = "Moser Baer India Ltd."; + else if(manufacturerId.StartsWith("TT", StringComparison.Ordinal) || + manufacturerId.StartsWith("TDK", StringComparison.Ordinal)) + manufacturer = "TDK Corporation"; + else if(manufacturerId.StartsWith("JVC", StringComparison.Ordinal)) + manufacturer = "Victor Advanced media Co., Ltd."; + else if(manufacturerId.StartsWith("MEI", StringComparison.Ordinal)) + manufacturer = "Matsushita Electric Industrial Co., Ltd."; + else if(manufacturerId.StartsWith("OPTODISC", StringComparison.Ordinal)) + manufacturer = "OptoDisc Ltd."; + else if(manufacturerId.StartsWith("KIC", StringComparison.Ordinal)) + manufacturer = "Advance Media Corporation"; + else if(manufacturerId.StartsWith("IMC", StringComparison.Ordinal)) + manufacturer = "Intermedia Co., Ltd."; + else if(manufacturerId.StartsWith("LGE", StringComparison.Ordinal)) + manufacturer = "LG Electronics Inc."; + else if(manufacturerId.StartsWith("KDT", StringComparison.Ordinal)) + manufacturer = "King Disc Technology Corporation"; + else if(manufacturerId.StartsWith("POS", StringComparison.Ordinal)) + manufacturer = "POSTECH Corporation"; + else if(manufacturerId.StartsWith("VDSPMSAB", StringComparison.Ordinal)) + manufacturer = "Interaxia Digital Storage Materials AG"; + else if(manufacturerId.StartsWith("VANGUARD", StringComparison.Ordinal)) + manufacturer = "Vanguard Disc Inc."; + else if(manufacturerId.StartsWith("MJC", StringComparison.Ordinal)) + manufacturer = "Megan Media Holdings Berhad"; + else if(manufacturerId.StartsWith("DKM", StringComparison.Ordinal) || + manufacturerId.StartsWith("EDMA", StringComparison.Ordinal)) + manufacturer = "E-TOP Mediatek Inc."; + else if(manufacturerId.StartsWith("BeAll", StringComparison.Ordinal)) + manufacturer = "BeALL Developers, Inc."; - public string ManufacturerId; - public uint WriteStrategyCode2; - } + return manufacturer != "" ? $"{manufacturer} (\"{manufacturerId}\")" : $"\"{manufacturerId}\""; + } + + public struct PreRecordedInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 == 1 + public byte FieldId1; + /// Byte 5 disc application code + public byte DiscApplicationCode; + /// Byte 6 disc physical code + public byte DiscPhysicalCode; + /// Bytes 7 to 9 last address of data recordable area + public uint LastAddressOfDataRecordableArea; + /// Byte 10, bits 7 to 4 part version + public byte PartVersion; + /// Byte 10, bits 3 to 0 extension code + public byte ExtensionCode; + /// Byte 11 reserved + public byte Reserved3; + /// Byte 12 == 2 + public byte FieldId2; + /// Byte 13 OPC suggested code + public byte OPCSuggestedCode; + /// Byte 14 wavelength code or second part of OPC suggested code + public byte WaveLengthCode; + /// Bytes 15 to 18 write strategy code + public uint WriteStrategyCode; + /// Byte 19 reserved + public byte Reserved4; + /// Byte 20 == 3 + public byte FieldId3; + /// Bytes 21 to 26 first part of manufacturer ID + public byte[] ManufacturerId1; + /// Byte 27 + public byte Reserved5; + /// Byte 28 == 4 + public byte FieldId4; + /// Bytes 29 to 34 second part of manufacturer ID + public byte[] ManufacturerId2; + /// Byte 35 reserved + public byte Reserved6; + /// Byte 36 == 5 + public byte FieldId5; + /// Bytes 37 to 42, third part of manufacturer code or write strategy code for RW and R later versions + public byte[] ManufacturerId3; + /// Byte 43 reserved + public byte Reserved7; + /// Bytes 44 to 68 reserved + public byte[] Reserved8; + + public string ManufacturerId; + public uint WriteStrategyCode2; } } \ No newline at end of file diff --git a/DVD/RMD.cs b/DVD/RMD.cs index bfe5bbe..0b6279f 100644 --- a/DVD/RMD.cs +++ b/DVD/RMD.cs @@ -32,54 +32,53 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD -{ - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class RMD - { - public struct LastBorderOutRMD - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end RMD in last recorded Border-out - public byte[] RMD; - } +namespace Aaru.Decoders.DVD; - public struct HDMediumStatus - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4, bits 7 to 1 Reserved - public byte Reserved3; - /// Byte 4, bit 0 Test Zone has been extended - public bool ExtendedTestZone; - /// Byte 5 Number of remaining RMDs in RDZ - public byte RemainingRMDs; - /// Bytes 6 to 7 Number of remaining RMDs in current RMZ - public ushort CurrentRemainingRMDs; - } +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class RMD +{ + public struct LastBorderOutRMD + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end RMD in last recorded Border-out + public byte[] RMD; + } + + public struct HDMediumStatus + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bits 7 to 1 Reserved + public byte Reserved3; + /// Byte 4, bit 0 Test Zone has been extended + public bool ExtendedTestZone; + /// Byte 5 Number of remaining RMDs in RDZ + public byte RemainingRMDs; + /// Bytes 6 to 7 Number of remaining RMDs in current RMZ + public ushort CurrentRemainingRMDs; } } \ No newline at end of file diff --git a/DVD/Spare.cs b/DVD/Spare.cs index 90fce4c..0eab4b9 100644 --- a/DVD/Spare.cs +++ b/DVD/Spare.cs @@ -33,77 +33,76 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class Spare { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class Spare + public static SpareAreaInformation? Decode(byte[] response) { - public static SpareAreaInformation? Decode(byte[] response) + if(response?.Length != 16) + return null; + + return new SpareAreaInformation { - if(response?.Length != 16) - return null; + 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]), + UnusedSupplementaryBlocks = + (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), + AllocatedSupplementaryBlocks = + (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]) + }; + } - return new SpareAreaInformation - { - 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]), - UnusedSupplementaryBlocks = - (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), - AllocatedSupplementaryBlocks = - (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]) - }; - } + public static string Prettify(SpareAreaInformation? sai) + { + if(sai == null) + return null; - public static string Prettify(SpareAreaInformation? sai) - { - if(sai == null) - return null; + SpareAreaInformation decoded = sai.Value; + var sb = new StringBuilder(); - SpareAreaInformation decoded = sai.Value; - 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} 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(); + } - return sb.ToString(); - } + public static string Prettify(byte[] response) => Prettify(Decode(response)); - public static string Prettify(byte[] response) => Prettify(Decode(response)); - - public struct SpareAreaInformation - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 7 Data length - public uint UnusedPrimaryBlocks; - /// Bytes 8 to 11 Data length - public uint UnusedSupplementaryBlocks; - /// Bytes 12 to 15 Data length - public uint AllocatedSupplementaryBlocks; - } + public struct SpareAreaInformation + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 Data length + public uint UnusedPrimaryBlocks; + /// Bytes 8 to 11 Data length + public uint UnusedSupplementaryBlocks; + /// Bytes 12 to 15 Data length + public uint AllocatedSupplementaryBlocks; } } \ No newline at end of file diff --git a/DVD/UDI.cs b/DVD/UDI.cs index 3da35d6..15559cb 100644 --- a/DVD/UDI.cs +++ b/DVD/UDI.cs @@ -32,52 +32,51 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.DVD +namespace Aaru.Decoders.DVD; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class UDI { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class UDI + public struct UniqueDiscIdentifier { - public struct UniqueDiscIdentifier - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 Reserved - public byte Reserved3; - /// Byte 5 Reserved - public byte Reserved4; - /// Bytes 6 to 7 Random number - public ushort RandomNumber; - /// Byte 8 to 11 Year - public uint Year; - /// Byte 12 to 13 Month - public ushort Month; - /// Byte 14 to 15 Day - public ushort Day; - /// Byte 16 to 17 Hour - public ushort Hour; - /// Byte 18 to 19 Minute - public ushort Minute; - /// Byte 20 to 21 Second - public ushort Second; - } + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Reserved + public byte Reserved3; + /// Byte 5 Reserved + public byte Reserved4; + /// Bytes 6 to 7 Random number + public ushort RandomNumber; + /// Byte 8 to 11 Year + public uint Year; + /// Byte 12 to 13 Month + public ushort Month; + /// Byte 14 to 15 Day + public ushort Day; + /// Byte 16 to 17 Hour + public ushort Hour; + /// Byte 18 to 19 Minute + public ushort Minute; + /// Byte 20 to 21 Second + public ushort Second; } } \ No newline at end of file diff --git a/Floppy/Amiga.cs b/Floppy/Amiga.cs index 639916f..a4d4bb6 100644 --- a/Floppy/Amiga.cs +++ b/Floppy/Amiga.cs @@ -33,38 +33,37 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; + +/// Methods and structures for Commodore Amiga decoding +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Amiga { - /// Methods and structures for Commodore Amiga decoding - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Amiga + public struct Sector { - public struct Sector - { - /// Set to 0x00 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] zero; - /// Set to 0xA1 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] sync; - /// Set to 0xFF - public byte amiga; - /// Track number - public byte track; - /// Sector number - public byte sector; - /// Remaining sectors til end of writing - public byte remaining; - /// OS dependent tag - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] label; - /// Checksum from to - public uint headerChecksum; - /// Checksum from - public uint dataChecksum; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] - public byte[] data; - } + /// Set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] zero; + /// Set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] sync; + /// Set to 0xFF + public byte amiga; + /// Track number + public byte track; + /// Sector number + public byte sector; + /// Remaining sectors til end of writing + public byte remaining; + /// OS dependent tag + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] label; + /// Checksum from to + public uint headerChecksum; + /// Checksum from + public uint dataChecksum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] + public byte[] data; } } \ No newline at end of file diff --git a/Floppy/Apple2.cs b/Floppy/Apple2.cs index e055468..77d648c 100644 --- a/Floppy/Apple2.cs +++ b/Floppy/Apple2.cs @@ -38,628 +38,627 @@ using System.Linq; using System.Runtime.InteropServices; using Aaru.Console; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; + +/// Methods and structures for Apple ][ floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Apple2 { - /// Methods and structures for Apple ][ floppy decoding - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Apple2 + static readonly byte[] ReadTable5and3 = { - 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 + }; + + static readonly byte[] ReadTable6and2 = + { + // 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 + }; + + /// Decodes the 5and3 encoded data + /// 5and3 encoded data. + public static byte[] Decode5and3(byte[] data) + { + 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++) { - // 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 - }; - - static readonly byte[] ReadTable6and2 = - { - // 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 - }; - - /// Decodes the 5and3 encoded data - /// 5and3 encoded data. - public static byte[] Decode5and3(byte[] data) - { - 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]]; - buffer[i] = carry; - } - - byte[] output = new byte[256]; - - for(int i = 0; i < 51; i++) - { - byte b1 = buffer[(51 * 3) - i]; - byte b2 = buffer[(51 * 2) - i]; - byte b3 = buffer[51 - i]; - byte b4 = (byte)((((b1 & 2) << 1) | (b2 & 2) | ((b3 & 2) >> 1)) & 0xFF); - byte b5 = (byte)((((b1 & 1) << 2) | ((b2 & 1) << 1) | (b3 & 1)) & 0xFF); - output[250 - (5 * i)] = (byte)(((buffer[i + (51 * 3) + 1] << 3) | ((b1 >> 2) & 0x7)) & 0xFF); - output[251 - (5 * i)] = (byte)(((buffer[i + (51 * 4) + 1] << 3) | ((b2 >> 2) & 0x7)) & 0xFF); - output[252 - (5 * i)] = (byte)(((buffer[i + (51 * 5) + 1] << 3) | ((b3 >> 2) & 0x7)) & 0xFF); - output[253 - (5 * i)] = (byte)(((buffer[i + (51 * 6) + 1] << 3) | b4) & 0xFF); - output[254 - (5 * i)] = (byte)(((buffer[i + (51 * 7) + 1] << 3) | b5) & 0xFF); - } - - output[255] = (byte)(((buffer[409] << 3) | (buffer[0] & 0x7)) & 0xFF); - - return output; + carry ^= ReadTable5and3[data[i]]; + buffer[i] = carry; } - /// Decodes the 6and2 encoded data - /// 6and2 encoded data. - public static byte[] Decode6and2(byte[] data) + byte[] output = new byte[256]; + + for(int i = 0; i < 51; i++) { - 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]]; - buffer[i] = carry; - } - - byte[] output = new byte[256]; - - for(uint i = 0; i < 256; i++) - { - output[i] = (byte)((buffer[86 + i] << 2) & 0xFF); - - if(i < 86) - { - output[i] |= (byte)(((buffer[i] & 1) << 1) & 0xFF); - output[i] |= (byte)(((buffer[i] & 2) >> 1) & 0xFF); - } - else if(i < 86 * 2) - { - output[i] |= (byte)(((buffer[i - 86] & 4) >> 1) & 0xFF); - output[i] |= (byte)(((buffer[i - 86] & 8) >> 3) & 0xFF); - } - else - { - output[i] |= (byte)(((buffer[i - (86 * 2)] & 0x10) >> 3) & 0xFF); - output[i] |= (byte)(((buffer[i - (86 * 2)] & 0x20) >> 5) & 0xFF); - } - } - - return output; + byte b1 = buffer[(51 * 3) - i]; + byte b2 = buffer[(51 * 2) - i]; + byte b3 = buffer[51 - i]; + byte b4 = (byte)((((b1 & 2) << 1) | (b2 & 2) | ((b3 & 2) >> 1)) & 0xFF); + byte b5 = (byte)((((b1 & 1) << 2) | ((b2 & 1) << 1) | (b3 & 1)) & 0xFF); + output[250 - (5 * i)] = (byte)(((buffer[i + (51 * 3) + 1] << 3) | ((b1 >> 2) & 0x7)) & 0xFF); + output[251 - (5 * i)] = (byte)(((buffer[i + (51 * 4) + 1] << 3) | ((b2 >> 2) & 0x7)) & 0xFF); + output[252 - (5 * i)] = (byte)(((buffer[i + (51 * 5) + 1] << 3) | ((b3 >> 2) & 0x7)) & 0xFF); + output[253 - (5 * i)] = (byte)(((buffer[i + (51 * 6) + 1] << 3) | b4) & 0xFF); + output[254 - (5 * i)] = (byte)(((buffer[i + (51 * 7) + 1] << 3) | b5) & 0xFF); } - public static byte[] DecodeSector(RawSector sector) + output[255] = (byte)(((buffer[409] << 3) | (buffer[0] & 0x7)) & 0xFF); + + return output; + } + + /// Decodes the 6and2 encoded data + /// 6and2 encoded data. + public static byte[] Decode6and2(byte[] data) + { + 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++) { - 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); - - // DOS 3.3 - return sector.addressField.prologue[2] == 0x96 ? Decode6and2(sector.dataField.data) : null; - - // Unknown - - // Not Apple ][ GCR? + carry ^= ReadTable6and2[data[i]]; + buffer[i] = carry; } - public static RawSector MarshalSector(byte[] data, int offset = 0) => MarshalSector(data, out _, offset); + byte[] output = new byte[256]; - public static RawSector MarshalSector(byte[] data, out int endOffset, int offset = 0) + for(uint i = 0; i < 256; i++) { - endOffset = offset; + output[i] = (byte)((buffer[86 + i] << 2) & 0xFF); - // Not an Apple ][ GCR sector - if(data == null || - data.Length < 363) - return null; - - int position = offset; - - try + if(i < 86) { - while(position < data.Length) + output[i] |= (byte)(((buffer[i] & 1) << 1) & 0xFF); + output[i] |= (byte)(((buffer[i] & 2) >> 1) & 0xFF); + } + else if(i < 86 * 2) + { + output[i] |= (byte)(((buffer[i - 86] & 4) >> 1) & 0xFF); + output[i] |= (byte)(((buffer[i - 86] & 8) >> 3) & 0xFF); + } + else + { + output[i] |= (byte)(((buffer[i - (86 * 2)] & 0x10) >> 3) & 0xFF); + output[i] |= (byte)(((buffer[i - (86 * 2)] & 0x20) >> 5) & 0xFF); + } + } + + return output; + } + + public static byte[] DecodeSector(RawSector sector) + { + 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); + + // DOS 3.3 + return sector.addressField.prologue[2] == 0x96 ? Decode6and2(sector.dataField.data) : null; + + // Unknown + + // Not Apple ][ GCR? + } + + public static RawSector MarshalSector(byte[] data, int offset = 0) => MarshalSector(data, out _, offset); + + public static RawSector MarshalSector(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + + // Not an Apple ][ GCR sector + if(data == null || + data.Length < 363) + return null; + + int position = offset; + + try + { + while(position < data.Length) + { + // Prologue found + if(data[position] == 0xD5 && + data[position + 1] == 0xAA) { - // Prologue found - if(data[position] == 0xD5 && - data[position + 1] == 0xAA) + AaruConsole.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; + + var sector = new RawSector { - AaruConsole.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; - - var sector = new RawSector + addressField = new RawAddressField { - addressField = new RawAddressField + prologue = new[] { - 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], 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] } - }; - - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Volume {0}", - (((sector.addressField.volume[0] & 0x55) << 1) | - (sector.addressField.volume[1] & 0x55)) & 0xFF); - - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Track {0}", - (((sector.addressField.track[0] & 0x55) << 1) | - (sector.addressField.track[1] & 0x55)) & 0xFF); - - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Sector {0}", - (((sector.addressField.sector[0] & 0x55) << 1) | - (sector.addressField.sector[1] & 0x55)) & 0xFF); - - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Checksum {0}", - (((sector.addressField.checksum[0] & 0x55) << 1) | - (sector.addressField.checksum[1] & 0x55)) & 0xFF); - - AaruConsole.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; - var gaps = new MemoryStream(); - - while(data[position] == 0xFF) - { - gaps.WriteByte(data[position]); - syncCount++; - onSync = syncCount >= 5; - position++; } + }; - // Lost sync - if(!onSync) - return null; + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Volume {0}", + (((sector.addressField.volume[0] & 0x55) << 1) | + (sector.addressField.volume[1] & 0x55)) & 0xFF); - // Prologue not found - if(data[position] != 0xD5 || - data[position + 1] != 0xAA) - return null; + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Track {0}", + (((sector.addressField.track[0] & 0x55) << 1) | + (sector.addressField.track[1] & 0x55)) & 0xFF); - sector.innerGap = gaps.ToArray(); - sector.dataField = new RawDataField(); + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Sector {0}", + (((sector.addressField.sector[0] & 0x55) << 1) | + (sector.addressField.sector[1] & 0x55)) & 0xFF); - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Inner gap has {0} bytes", - sector.innerGap.Length); + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Checksum {0}", + (((sector.addressField.checksum[0] & 0x55) << 1) | + (sector.addressField.checksum[1] & 0x55)) & 0xFF); - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Prologue found at {0}", position); - sector.dataField.prologue = new byte[3]; - sector.dataField.prologue[0] = data[position]; - sector.dataField.prologue[1] = data[position + 1]; - sector.dataField.prologue[2] = data[position + 2]; - position += 3; + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Epilogue {0:X2}{1:X2}{2:X2}", + sector.addressField.epilogue[0], sector.addressField.epilogue[1], + sector.addressField.epilogue[2]); - gaps = new MemoryStream(); + position += 14; + int syncCount = 0; + bool onSync = false; + var gaps = new MemoryStream(); - // Read data until epilogue is found - 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; - } - - sector.dataField.data = gaps.ToArray(); - - AaruConsole.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]; - sector.dataField.epilogue[1] = data[position + 2]; - sector.dataField.epilogue[2] = data[position + 3]; - - position += 4; - gaps = new MemoryStream(); - - // Read gap, if any - while(position < data.Length && - data[position] == 0xFF) - { - gaps.WriteByte(data[position]); - position++; - } - - // Reduces last sector gap so doesn't eat next tracks's gap - if(gaps.Length > 5) - { - gaps.SetLength(gaps.Length / 2); - position -= (int)gaps.Length; - } - - sector.gap = gaps.ToArray(); - - // Return current position to be able to read separate sectors - endOffset = position; - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Got {0} bytes of gap", sector.gap.Length); - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Finished sector at {0}", position); - - return sector; + while(data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + syncCount++; + onSync = syncCount >= 5; + position++; } - if(data[position] == 0xFF) + // Lost sync + if(!onSync) + return null; + + // Prologue not found + if(data[position] != 0xD5 || + data[position + 1] != 0xAA) + return null; + + sector.innerGap = gaps.ToArray(); + sector.dataField = new RawDataField(); + + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Inner gap has {0} bytes", + sector.innerGap.Length); + + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Prologue found at {0}", position); + sector.dataField.prologue = new byte[3]; + sector.dataField.prologue[0] = data[position]; + sector.dataField.prologue[1] = data[position + 1]; + sector.dataField.prologue[2] = data[position + 2]; + position += 3; + + gaps = new MemoryStream(); + + // Read data until epilogue is found + while(data[position + 1] != 0xDE || + data[position + 2] != 0xAA) + { + gaps.WriteByte(data[position]); position++; - // Found data that is not sync or a prologue - else - return null; - } - } - catch(IndexOutOfRangeException) - { - return null; - } + // No space left for epilogue + if(position + 4 > data.Length) + return null; + } + sector.dataField.data = gaps.ToArray(); + + AaruConsole.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]; + sector.dataField.epilogue[1] = data[position + 2]; + sector.dataField.epilogue[2] = data[position + 3]; + + position += 4; + gaps = new MemoryStream(); + + // Read gap, if any + while(position < data.Length && + data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + position++; + } + + // Reduces last sector gap so doesn't eat next tracks's gap + if(gaps.Length > 5) + { + gaps.SetLength(gaps.Length / 2); + position -= (int)gaps.Length; + } + + sector.gap = gaps.ToArray(); + + // Return current position to be able to read separate sectors + endOffset = position; + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Got {0} bytes of gap", sector.gap.Length); + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Finished sector at {0}", position); + + return sector; + } + + if(data[position] == 0xFF) + position++; + + // Found data that is not sync or a prologue + else + return null; + } + } + catch(IndexOutOfRangeException) + { return null; } - public static byte[] MarshalAddressField(RawAddressField addressField) + return null; + } + + public static byte[] MarshalAddressField(RawAddressField addressField) + { + if(addressField == null) + return null; + + 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.checksum, 0, addressField.checksum.Length); + raw.Write(addressField.epilogue, 0, addressField.epilogue.Length); + + return raw.ToArray(); + } + + public static byte[] MarshalSector(RawSector sector) + { + if(sector == null) + return null; + + 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.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.WriteByte(sector.dataField.checksum); + raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length); + raw.Write(sector.gap, 0, sector.gap.Length); + + return raw.ToArray(); + } + + public static RawTrack MarshalTrack(byte[] data, int offset = 0) => MarshalTrack(data, out _, offset); + + public static RawTrack MarshalTrack(byte[] data, out int endOffset, int offset = 0) + { + int position = offset; + bool firstSector = true; + bool onSync = false; + var gaps = new MemoryStream(); + int count = 0; + List sectors = new List(); + byte[] trackNumber = new byte[2]; + endOffset = offset; + + while(position < data.Length && + data[position] == 0xFF) { - if(addressField == null) - return null; - - 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.checksum, 0, addressField.checksum.Length); - raw.Write(addressField.epilogue, 0, addressField.epilogue.Length); - - return raw.ToArray(); + gaps.WriteByte(data[position]); + count++; + position++; + onSync = count >= 5; } - public static byte[] MarshalSector(RawSector sector) + if(position >= data.Length) + return null; + + if(!onSync) + return null; + + while(position < data.Length) { + int oldPosition = position; + RawSector sector = MarshalSector(data, out position, position); + if(sector == null) - return null; + break; - 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.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.WriteByte(sector.dataField.checksum); - raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length); - raw.Write(sector.gap, 0, sector.gap.Length); - - return raw.ToArray(); - } - - public static RawTrack MarshalTrack(byte[] data, int offset = 0) => MarshalTrack(data, out _, offset); - - public static RawTrack MarshalTrack(byte[] data, out int endOffset, int offset = 0) - { - int position = offset; - bool firstSector = true; - bool onSync = false; - var gaps = new MemoryStream(); - int count = 0; - List sectors = new List(); - byte[] trackNumber = new byte[2]; - endOffset = offset; - - while(position < data.Length && - data[position] == 0xFF) + if(firstSector) { - gaps.WriteByte(data[position]); - count++; - position++; - onSync = count >= 5; + trackNumber[0] = sector.addressField.track[0]; + trackNumber[1] = sector.addressField.track[1]; + firstSector = false; } - if(position >= data.Length) - return null; - - if(!onSync) - return null; - - while(position < data.Length) + if(sector.addressField.track[0] != trackNumber[0] || + sector.addressField.track[1] != trackNumber[1]) { - int oldPosition = position; - RawSector sector = MarshalSector(data, out position, position); + position = oldPosition; - if(sector == null) - break; - - if(firstSector) - { - trackNumber[0] = sector.addressField.track[0]; - trackNumber[1] = sector.addressField.track[1]; - firstSector = false; - } - - if(sector.addressField.track[0] != trackNumber[0] || - sector.addressField.track[1] != trackNumber[1]) - { - position = oldPosition; - - break; - } - - AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Adding sector {0} of track {1}", - (((sector.addressField.sector[0] & 0x55) << 1) | - (sector.addressField.sector[1] & 0x55)) & 0xFF, - (((sector.addressField.track[0] & 0x55) << 1) | - (sector.addressField.track[1] & 0x55)) & 0xFF); - - sectors.Add(sector); + break; } - if(sectors.Count == 0) - return null; + AaruConsole.DebugWriteLine("Apple ][ GCR Decoder", "Adding sector {0} of track {1}", + (((sector.addressField.sector[0] & 0x55) << 1) | + (sector.addressField.sector[1] & 0x55)) & 0xFF, + (((sector.addressField.track[0] & 0x55) << 1) | + (sector.addressField.track[1] & 0x55)) & 0xFF); - var track = new RawTrack - { - gap = gaps.ToArray(), - sectors = sectors.ToArray() - }; - - endOffset = position; - - return track; + sectors.Add(sector); } - public static byte[] MarshalTrack(RawTrack track) + if(sectors.Count == 0) + return null; + + var track = new RawTrack { - if(track == null) - return null; + gap = gaps.ToArray(), + sectors = sectors.ToArray() + }; - var raw = new MemoryStream(); - raw.Write(track.gap, 0, track.gap.Length); + endOffset = position; - foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) - raw.Write(rawSector, 0, rawSector.Length); + return track; + } - return raw.ToArray(); - } + public static byte[] MarshalTrack(RawTrack track) + { + if(track == null) + return null; - public static List MarshalDisk(byte[] data, int offset = 0) => MarshalDisk(data, out _, offset); + var raw = new MemoryStream(); + raw.Write(track.gap, 0, track.gap.Length); - public static List MarshalDisk(byte[] data, out int endOffset, int offset = 0) + foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) + raw.Write(rawSector, 0, rawSector.Length); + + return raw.ToArray(); + } + + public static List MarshalDisk(byte[] data, int offset = 0) => MarshalDisk(data, out _, offset); + + public static List MarshalDisk(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + List tracks = new List(); + int position = offset; + + RawTrack track = MarshalTrack(data, out position, position); + + while(track != null) { - endOffset = offset; - List tracks = new List(); - 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; - - endOffset = position; - - return tracks; + tracks.Add(track); + track = MarshalTrack(data, out position, position); } - public static byte[] MarshalDisk(List disk) => MarshalDisk(disk.ToArray()); + if(tracks.Count == 0) + return null; - public static byte[] MarshalDisk(RawTrack[] disk) - { - if(disk == null) - return null; + endOffset = position; - var raw = new MemoryStream(); + return tracks; + } - foreach(byte[] rawTrack in disk.Select(MarshalTrack)) - raw.Write(rawTrack, 0, rawTrack.Length); + public static byte[] MarshalDisk(List disk) => MarshalDisk(disk.ToArray()); - return raw.ToArray(); - } + public static byte[] MarshalDisk(RawTrack[] disk) + { + if(disk == null) + return null; - public static bool IsApple2GCR(byte[] data) - { - RawSector sector = MarshalSector(data, out int position); + var raw = new MemoryStream(); - return sector != null && position != 0; - } + foreach(byte[] rawTrack in disk.Select(MarshalTrack)) + raw.Write(rawTrack, 0, rawTrack.Length); - /// GCR-encoded Apple ][ GCR floppy track - public class RawTrack - { - /// Track preamble, set to self-sync 0xFF, between 40 and 95 bytes - public byte[] gap; - public RawSector[] sectors; - } + return raw.ToArray(); + } - /// GCR-encoded Apple ][ GCR floppy sector - public class RawSector - { - /// Address field - public RawAddressField addressField; - /// Data field - public RawDataField dataField; - /// Track preamble, set to self-sync 0xFF, between 14 and 24 bytes - public byte[] gap; - /// Track preamble, set to self-sync 0xFF, between 5 and 10 bytes - public byte[] innerGap; - } + public static bool IsApple2GCR(byte[] data) + { + RawSector sector = MarshalSector(data, out int position); - /// GCR-encoded Apple ][ GCR floppy sector address field - public class RawAddressField - { - /// - /// decodedChecksum = decodedVolume ^ decodedTrack ^ decodedSector checksum[0] = (decodedChecksum >> 1) | 0xAA - /// checksum[1] = decodedChecksum | 0xAA - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] checksum; - /// Always 0xDE, 0xAA, 0xEB - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] epilogue; - /// Always 0xD5, 0xAA, 0x96 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] prologue; - /// Sector number encoded as: sector[0] = (decodedSector >> 1) | 0xAA sector[1] = decodedSector | 0xAA - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] sector; - /// Track number encoded as: track[0] = (decodedTrack >> 1) | 0xAA track[1] = decodedTrack | 0xAA - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] track; - /// Volume number encoded as: volume[0] = (decodedVolume >> 1) | 0xAA volume[1] = decodedVolume | 0xAA - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] volume; - } + return sector != null && position != 0; + } - /// GCR-encoded Apple ][ GCR floppy sector data field - public class RawDataField - { - public byte checksum; - /// Encoded data bytes. 410 bytes for 5to3 (aka DOS 3.2) format 342 bytes for 6to2 (aka DOS 3.3) format - public byte[] data; - /// Always 0xDE, 0xAA, 0xEB - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] epilogue; - /// Always 0xD5, 0xAA, 0xAD - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] prologue; - } + /// GCR-encoded Apple ][ GCR floppy track + public class RawTrack + { + /// Track preamble, set to self-sync 0xFF, between 40 and 95 bytes + public byte[] gap; + public RawSector[] sectors; + } + + /// GCR-encoded Apple ][ GCR floppy sector + public class RawSector + { + /// Address field + public RawAddressField addressField; + /// Data field + public RawDataField dataField; + /// Track preamble, set to self-sync 0xFF, between 14 and 24 bytes + public byte[] gap; + /// Track preamble, set to self-sync 0xFF, between 5 and 10 bytes + public byte[] innerGap; + } + + /// GCR-encoded Apple ][ GCR floppy sector address field + public class RawAddressField + { + /// + /// decodedChecksum = decodedVolume ^ decodedTrack ^ decodedSector checksum[0] = (decodedChecksum >> 1) | 0xAA + /// checksum[1] = decodedChecksum | 0xAA + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] checksum; + /// Always 0xDE, 0xAA, 0xEB + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] epilogue; + /// Always 0xD5, 0xAA, 0x96 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; + /// Sector number encoded as: sector[0] = (decodedSector >> 1) | 0xAA sector[1] = decodedSector | 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] sector; + /// Track number encoded as: track[0] = (decodedTrack >> 1) | 0xAA track[1] = decodedTrack | 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] track; + /// Volume number encoded as: volume[0] = (decodedVolume >> 1) | 0xAA volume[1] = decodedVolume | 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] volume; + } + + /// GCR-encoded Apple ][ GCR floppy sector data field + public class RawDataField + { + public byte checksum; + /// Encoded data bytes. 410 bytes for 5to3 (aka DOS 3.2) format 342 bytes for 6to2 (aka DOS 3.3) format + public byte[] data; + /// Always 0xDE, 0xAA, 0xEB + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] epilogue; + /// Always 0xD5, 0xAA, 0xAD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; } } \ No newline at end of file diff --git a/Floppy/AppleSony.cs b/Floppy/AppleSony.cs index 3bdb52c..676e9dd 100644 --- a/Floppy/AppleSony.cs +++ b/Floppy/AppleSony.cs @@ -37,477 +37,475 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; +// Information from: +// Inside Macintosh, Volume II, ISBN 0-201-17732-3 + +/// Methods and structures for Apple Sony GCR floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class AppleSony { - // Information from: - // Inside Macintosh, Volume II, ISBN 0-201-17732-3 - - /// Methods and structures for Apple Sony GCR floppy decoding - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class AppleSony + public static byte[] DecodeSector(RawSector sector) { - public static byte[] DecodeSector(RawSector sector) + 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; + var ms = new MemoryStream(); + + int j = 0; + byte w3 = 0; + + for(int i = 0; i <= 174; i++) { - if(sector.addressField.prologue[0] != 0xD5 || - sector.addressField.prologue[1] != 0xAA || - sector.addressField.prologue[2] != 0x96) - return null; + byte w4 = nib_data[j++]; + byte w1 = nib_data[j++]; + byte w2 = nib_data[j++]; - 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(); + if(i != 174) + w3 = nib_data[j++]; - 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++]; - - bf1[i] = (byte)(((w1 & 0x3F) | ((w4 << 2) & 0xC0)) & 0x0F); - bf2[i] = (byte)(((w2 & 0x3F) | ((w4 << 4) & 0xC0)) & 0x0F); - bf3[i] = (byte)(((w3 & 0x3F) | ((w4 << 6) & 0xC0)) & 0x0F); - } - - j = 0; - uint ck1 = 0; - uint ck2 = 0; - uint ck3 = 0; - - while(true) - { - ck1 = (ck1 & 0xFF) << 1; - - if((ck1 & 0x0100) > 0) - ck1++; - - byte carry = (byte)((bf1[j] ^ ck1) & 0xFF); - ck3 += carry; - - if((ck1 & 0x0100) > 0) - { - ck3++; - ck1 &= 0xFF; - } - - ms.WriteByte(carry); - - carry = (byte)((bf2[j] ^ ck3) & 0xFF); - ck2 += carry; - - if(ck3 > 0xFF) - { - ck2++; - ck3 &= 0xFF; - } - - ms.WriteByte(carry); - - if(ms.Length == 524) - break; - - carry = (byte)((bf3[j] ^ ck2) & 0xFF); - ck1 += carry; - - if(ck2 > 0xFF) - { - ck1++; - ck2 &= 0xFF; - } - - ms.WriteByte(carry); - j++; - } - - return ms.ToArray(); - - // Not Apple Sony GCR? + bf1[i] = (byte)(((w1 & 0x3F) | ((w4 << 2) & 0xC0)) & 0x0F); + bf2[i] = (byte)(((w2 & 0x3F) | ((w4 << 4) & 0xC0)) & 0x0F); + bf3[i] = (byte)(((w3 & 0x3F) | ((w4 << 6) & 0xC0)) & 0x0F); } - public static RawSector MarshalSector(byte[] data, int offset = 0) => MarshalSector(data, out _, offset); + j = 0; + uint ck1 = 0; + uint ck2 = 0; + uint ck3 = 0; - public static RawSector MarshalSector(byte[] data, out int endOffset, int offset = 0) + while(true) { - endOffset = offset; + ck1 = (ck1 & 0xFF) << 1; - // Not an Apple ][ GCR sector - if(data == null || - data.Length < 363) - return null; + if((ck1 & 0x0100) > 0) + ck1++; - int position = offset; + byte carry = (byte)((bf1[j] ^ ck1) & 0xFF); + ck3 += carry; - try + if((ck1 & 0x0100) > 0) { - while(position < data.Length) + ck3++; + ck1 &= 0xFF; + } + + ms.WriteByte(carry); + + carry = (byte)((bf2[j] ^ ck3) & 0xFF); + ck2 += carry; + + if(ck3 > 0xFF) + { + ck2++; + ck3 &= 0xFF; + } + + ms.WriteByte(carry); + + if(ms.Length == 524) + break; + + carry = (byte)((bf3[j] ^ ck2) & 0xFF); + ck1 += carry; + + if(ck2 > 0xFF) + { + ck1++; + ck2 &= 0xFF; + } + + ms.WriteByte(carry); + j++; + } + + return ms.ToArray(); + + // Not Apple Sony GCR? + } + + public static RawSector MarshalSector(byte[] data, int offset = 0) => MarshalSector(data, out _, offset); + + public static RawSector MarshalSector(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + + // Not an Apple ][ GCR sector + if(data == null || + data.Length < 363) + return null; + + int position = offset; + + try + { + while(position < data.Length) + { + // Prologue found + if(data[position] == 0xD5 && + data[position + 1] == 0xAA && + data[position + 2] == 0x96) { - // Prologue found - 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; + + var sector = new RawSector { - // Epilogue not in correct position - if(data[position + 8] != 0xDE || - data[position + 9] != 0xAA) - return null; - - 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] - } - } - }; - - position += 10; - int syncCount = 0; - bool onSync = false; - var gaps = new MemoryStream(); - - while(data[position] == 0xFF) - { - gaps.WriteByte(data[position]); - syncCount++; - onSync = syncCount >= 5; - position++; - } - - // Lost sync - if(!onSync) - return null; - - // Prologue not found - if(data[position] != 0xDE || - data[position + 1] != 0xAA || - data[position + 2] != 0xAD) - return null; - - sector.innerGap = gaps.ToArray(); - - sector.dataField = new RawDataField + addressField = new RawAddressField { 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) - { - gaps.WriteByte(data[position]); - position++; - - // No space left for epilogue - if(position + 7 > data.Length) - return null; + 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] + } } + }; - sector.dataField.data = gaps.ToArray(); - sector.dataField.checksum = new byte[4]; - sector.dataField.checksum[0] = data[position]; - sector.dataField.checksum[1] = data[position + 2]; - sector.dataField.checksum[2] = data[position + 3]; - sector.dataField.checksum[3] = data[position + 4]; - sector.dataField.epilogue = new byte[2]; - sector.dataField.epilogue[0] = data[position + 5]; - sector.dataField.epilogue[1] = data[position + 6]; + position += 10; + int syncCount = 0; + bool onSync = false; + var gaps = new MemoryStream(); - position += 7; - gaps = new MemoryStream(); - - // Read gap, if any - while(position < data.Length && - data[position] == 0xFF) - { - gaps.WriteByte(data[position]); - position++; - } - - // Reduces last sector gap so doesn't eat next tracks's gap - if(gaps.Length > 5) - { - gaps.SetLength(gaps.Length / 2); - position -= (int)gaps.Length; - } - - sector.gap = gaps.ToArray(); - - // Return current position to be able to read separate sectors - endOffset = position; - - return sector; + while(data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + syncCount++; + onSync = syncCount >= 5; + position++; } - if(data[position] == 0xFF) + // Lost sync + if(!onSync) + return null; + + // Prologue not found + 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] + }; + + position += 4; + + gaps = new MemoryStream(); + + // Read data until epilogue is found + while(data[position + 4] != 0xD5 || + data[position + 5] != 0xAA) + { + gaps.WriteByte(data[position]); position++; - // Found data that is not sync or a prologue - else - return null; - } - } - catch(IndexOutOfRangeException) - { - return null; - } + // No space left for epilogue + if(position + 7 > data.Length) + return null; + } + sector.dataField.data = gaps.ToArray(); + sector.dataField.checksum = new byte[4]; + sector.dataField.checksum[0] = data[position]; + sector.dataField.checksum[1] = data[position + 2]; + sector.dataField.checksum[2] = data[position + 3]; + sector.dataField.checksum[3] = data[position + 4]; + sector.dataField.epilogue = new byte[2]; + sector.dataField.epilogue[0] = data[position + 5]; + sector.dataField.epilogue[1] = data[position + 6]; + + position += 7; + gaps = new MemoryStream(); + + // Read gap, if any + while(position < data.Length && + data[position] == 0xFF) + { + gaps.WriteByte(data[position]); + position++; + } + + // Reduces last sector gap so doesn't eat next tracks's gap + if(gaps.Length > 5) + { + gaps.SetLength(gaps.Length / 2); + position -= (int)gaps.Length; + } + + sector.gap = gaps.ToArray(); + + // Return current position to be able to read separate sectors + endOffset = position; + + return sector; + } + + if(data[position] == 0xFF) + position++; + + // Found data that is not sync or a prologue + else + return null; + } + } + catch(IndexOutOfRangeException) + { return null; } - public static byte[] MarshalAddressField(RawAddressField addressField) + return null; + } + + public static byte[] MarshalAddressField(RawAddressField addressField) + { + if(addressField == null) + return null; + + var raw = new MemoryStream(); + raw.Write(addressField.prologue, 0, addressField.prologue.Length); + raw.WriteByte(addressField.track); + raw.WriteByte(addressField.sector); + raw.WriteByte(addressField.side); + raw.WriteByte((byte)addressField.format); + raw.WriteByte(addressField.checksum); + + return raw.ToArray(); + } + + public static byte[] MarshalSector(RawSector sector) + { + if(sector == null) + return null; + + 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.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.checksum, 0, sector.dataField.checksum.Length); + raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length); + raw.Write(sector.gap, 0, sector.gap.Length); + + return raw.ToArray(); + } + + public static RawTrack MarshalTrack(byte[] data, int offset = 0) => MarshalTrack(data, out _, offset); + + public static RawTrack MarshalTrack(byte[] data, out int endOffset, int offset = 0) + { + int position = offset; + bool firstSector = true; + bool onSync = false; + var gaps = new MemoryStream(); + int count = 0; + List sectors = new List(); + byte trackNumber = 0; + byte sideNumber = 0; + endOffset = offset; + + while(position < data.Length && + data[position] == 0xFF) { - if(addressField == null) - return null; - - var raw = new MemoryStream(); - raw.Write(addressField.prologue, 0, addressField.prologue.Length); - raw.WriteByte(addressField.track); - raw.WriteByte(addressField.sector); - raw.WriteByte(addressField.side); - raw.WriteByte((byte)addressField.format); - raw.WriteByte(addressField.checksum); - - return raw.ToArray(); + gaps.WriteByte(data[position]); + count++; + position++; + onSync = count >= 5; } - public static byte[] MarshalSector(RawSector sector) + if(position >= data.Length) + return null; + + if(!onSync) + return null; + + while(position < data.Length) { + int oldPosition = position; + RawSector sector = MarshalSector(data, out position, position); + if(sector == null) - return null; + break; - 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.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.checksum, 0, sector.dataField.checksum.Length); - raw.Write(sector.dataField.epilogue, 0, sector.dataField.epilogue.Length); - raw.Write(sector.gap, 0, sector.gap.Length); - - return raw.ToArray(); - } - - public static RawTrack MarshalTrack(byte[] data, int offset = 0) => MarshalTrack(data, out _, offset); - - public static RawTrack MarshalTrack(byte[] data, out int endOffset, int offset = 0) - { - int position = offset; - bool firstSector = true; - bool onSync = false; - var gaps = new MemoryStream(); - int count = 0; - List sectors = new List(); - byte trackNumber = 0; - byte sideNumber = 0; - endOffset = offset; - - while(position < data.Length && - data[position] == 0xFF) + if(firstSector) { - gaps.WriteByte(data[position]); - count++; - position++; - onSync = count >= 5; + trackNumber = sector.addressField.track; + sideNumber = sector.addressField.side; + firstSector = false; } - if(position >= data.Length) - return null; - - if(!onSync) - return null; - - while(position < data.Length) + if(sector.addressField.track != trackNumber || + sector.addressField.side != sideNumber) { - int oldPosition = position; - RawSector sector = MarshalSector(data, out position, position); + position = oldPosition; - if(sector == null) - break; - - if(firstSector) - { - trackNumber = sector.addressField.track; - sideNumber = sector.addressField.side; - firstSector = false; - } - - if(sector.addressField.track != trackNumber || - sector.addressField.side != sideNumber) - { - position = oldPosition; - - break; - } - - sectors.Add(sector); + break; } - if(sectors.Count == 0) - return null; - - var track = new RawTrack - { - gap = gaps.ToArray(), - sectors = sectors.ToArray() - }; - - endOffset = position; - - return track; + sectors.Add(sector); } - public static byte[] MarshalTrack(RawTrack track) + if(sectors.Count == 0) + return null; + + var track = new RawTrack { - if(track == null) - return null; + gap = gaps.ToArray(), + sectors = sectors.ToArray() + }; - var raw = new MemoryStream(); - raw.Write(track.gap, 0, track.gap.Length); + endOffset = position; - foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) - raw.Write(rawSector, 0, rawSector.Length); + return track; + } - return raw.ToArray(); - } + public static byte[] MarshalTrack(RawTrack track) + { + if(track == null) + return null; - public static List MarshalDisk(byte[] data, int offset = 0) => MarshalDisk(data, out _, offset); + var raw = new MemoryStream(); + raw.Write(track.gap, 0, track.gap.Length); - public static List MarshalDisk(byte[] data, out int endOffset, int offset = 0) + foreach(byte[] rawSector in track.sectors.Select(MarshalSector)) + raw.Write(rawSector, 0, rawSector.Length); + + return raw.ToArray(); + } + + public static List MarshalDisk(byte[] data, int offset = 0) => MarshalDisk(data, out _, offset); + + public static List MarshalDisk(byte[] data, out int endOffset, int offset = 0) + { + endOffset = offset; + List tracks = new List(); + int position = offset; + + RawTrack track = MarshalTrack(data, out position, position); + + while(track != null) { - endOffset = offset; - List tracks = new List(); - 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; - - endOffset = position; - - return tracks; + tracks.Add(track); + track = MarshalTrack(data, out position, position); } - public static byte[] MarshalDisk(List disk) => MarshalDisk(disk.ToArray()); + if(tracks.Count == 0) + return null; - public static byte[] MarshalDisk(RawTrack[] disk) - { - if(disk == null) - return null; + endOffset = position; - var raw = new MemoryStream(); + return tracks; + } - foreach(byte[] rawTrack in disk.Select(MarshalTrack)) - raw.Write(rawTrack, 0, rawTrack.Length); + public static byte[] MarshalDisk(List disk) => MarshalDisk(disk.ToArray()); - return raw.ToArray(); - } + public static byte[] MarshalDisk(RawTrack[] disk) + { + if(disk == null) + return null; - public static bool IsAppleSonyGCR(byte[] data) - { - RawSector sector = MarshalSector(data, out int position); + var raw = new MemoryStream(); - return sector != null && position != 0; - } + foreach(byte[] rawTrack in disk.Select(MarshalTrack)) + raw.Write(rawTrack, 0, rawTrack.Length); - /// GCR-encoded Apple Sony GCR floppy track - public class RawTrack - { - /// Track preamble, set to self-sync 0xFF, 36 bytes - public byte[] gap; - public RawSector[] sectors; - } + return raw.ToArray(); + } - /// GCR-encoded Apple Sony GCR floppy sector - public class RawSector - { - /// Address field - public RawAddressField addressField; - /// Data field - public RawDataField dataField; - /// Track preamble, set to self-sync 0xFF, unknown size - public byte[] gap; - /// Track preamble, set to self-sync 0xFF, 6 bytes - public byte[] innerGap; - } + public static bool IsAppleSonyGCR(byte[] data) + { + RawSector sector = MarshalSector(data, out int position); - /// GCR-encoded Apple Sony GCR floppy sector address field - public class RawAddressField - { - /// Checksum - public byte checksum; - /// Always 0xDE, 0xAA - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] epilogue; - /// Disk format - public AppleEncodedFormat format; - /// Always 0xD5, 0xAA, 0x96 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] prologue; - /// Encoded sector number - public byte sector; - /// Encoded side number - public byte side; - /// Encoded (decodedTrack & 0x3F) - public byte track; - } + return sector != null && position != 0; + } - /// GCR-encoded Apple ][ GCR floppy sector data field - public class RawDataField - { - /// Checksum - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] checksum; - /// Encoded data bytes. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 698)] - public byte[] data; - /// Always 0xDE, 0xAA - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] epilogue; - /// Always 0xD5, 0xAA, 0xAD - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] prologue; - /// Spare, usually - public byte spare; - } + /// GCR-encoded Apple Sony GCR floppy track + public class RawTrack + { + /// Track preamble, set to self-sync 0xFF, 36 bytes + public byte[] gap; + public RawSector[] sectors; + } + + /// GCR-encoded Apple Sony GCR floppy sector + public class RawSector + { + /// Address field + public RawAddressField addressField; + /// Data field + public RawDataField dataField; + /// Track preamble, set to self-sync 0xFF, unknown size + public byte[] gap; + /// Track preamble, set to self-sync 0xFF, 6 bytes + public byte[] innerGap; + } + + /// GCR-encoded Apple Sony GCR floppy sector address field + public class RawAddressField + { + /// Checksum + public byte checksum; + /// Always 0xDE, 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] epilogue; + /// Disk format + public AppleEncodedFormat format; + /// Always 0xD5, 0xAA, 0x96 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; + /// Encoded sector number + public byte sector; + /// Encoded side number + public byte side; + /// Encoded (decodedTrack & 0x3F) + public byte track; + } + + /// GCR-encoded Apple ][ GCR floppy sector data field + public class RawDataField + { + /// Checksum + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] checksum; + /// Encoded data bytes. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 698)] + public byte[] data; + /// Always 0xDE, 0xAA + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] epilogue; + /// Always 0xD5, 0xAA, 0xAD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] prologue; + /// Spare, usually + public byte spare; } } \ No newline at end of file diff --git a/Floppy/Commodore.cs b/Floppy/Commodore.cs index 22c0a08..aa4f5d3 100644 --- a/Floppy/Commodore.cs +++ b/Floppy/Commodore.cs @@ -33,42 +33,41 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Aaru.Decoders.Floppy -{ - /// Methods and structures for Commodore GCR floppy decoding - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Commodore - { - /// Decoded Commodore GCR sector header - public struct SectorHeader - { - /// Always 0x08 - public byte id; - /// XOR of following fields - public byte checksum; - /// Sector number - public byte sector; - /// Track number - public byte track; - /// Format ID, unknown meaning - public ushort format; - /// Filled with 0x0F - public ushort fill; - } +namespace Aaru.Decoders.Floppy; - /// Decoded Commodore GCR sector data - public struct SectorData - { - /// Always 0x07 - public byte id; - /// User data - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] - public byte data; - /// XOR of - public byte checksum; - /// Filled with 0x0F - public ushort fill; - } +/// Methods and structures for Commodore GCR floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Commodore +{ + /// Decoded Commodore GCR sector header + public struct SectorHeader + { + /// Always 0x08 + public byte id; + /// XOR of following fields + public byte checksum; + /// Sector number + public byte sector; + /// Track number + public byte track; + /// Format ID, unknown meaning + public ushort format; + /// Filled with 0x0F + public ushort fill; + } + + /// Decoded Commodore GCR sector data + public struct SectorData + { + /// Always 0x07 + public byte id; + /// User data + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public byte data; + /// XOR of + public byte checksum; + /// Filled with 0x0F + public ushort fill; } } \ No newline at end of file diff --git a/Floppy/Enums.cs b/Floppy/Enums.cs index dc725a4..83a64af 100644 --- a/Floppy/Enums.cs +++ b/Floppy/Enums.cs @@ -32,47 +32,46 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; + +/// In-sector code for sector size +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum IBMSectorSizeCode : byte { - /// In-sector code for sector size - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum IBMSectorSizeCode : byte - { - /// 128 bytes/sector - EighthKilo = 0, - /// 256 bytes/sector - QuarterKilo = 1, - /// 512 bytes/sector - HalfKilo = 2, - /// 1024 bytes/sector - Kilo = 3, - /// 2048 bytes/sector - TwiceKilo = 4, - /// 4096 bytes/sector - FriceKilo = 5, - /// 8192 bytes/sector - TwiceFriceKilo = 6, - /// 16384 bytes/sector - FricelyFriceKilo = 7 - } + /// 128 bytes/sector + EighthKilo = 0, + /// 256 bytes/sector + QuarterKilo = 1, + /// 512 bytes/sector + HalfKilo = 2, + /// 1024 bytes/sector + Kilo = 3, + /// 2048 bytes/sector + TwiceKilo = 4, + /// 4096 bytes/sector + FriceKilo = 5, + /// 8192 bytes/sector + TwiceFriceKilo = 6, + /// 16384 bytes/sector + FricelyFriceKilo = 7 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum IBMIdType : byte - { - IndexMark = 0xFC, AddressMark = 0xFE, DataMark = 0xFB, - DeletedDataMark = 0xF8 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum IBMIdType : byte +{ + IndexMark = 0xFC, AddressMark = 0xFE, DataMark = 0xFB, + DeletedDataMark = 0xF8 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum AppleEncodedFormat : byte - { - /// Disk is an Apple II 3.5" disk - AppleII = 0x96, - /// Disk is an Apple Lisa 3.5" disk - Lisa = 0x97, - /// Disk is an Apple Macintosh single-sided 3.5" disk - MacSingleSide = 0x9A, - /// Disk is an Apple Macintosh double-sided 3.5" disk - MacDoubleSide = 0xD9 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum AppleEncodedFormat : byte +{ + /// Disk is an Apple II 3.5" disk + AppleII = 0x96, + /// Disk is an Apple Lisa 3.5" disk + Lisa = 0x97, + /// Disk is an Apple Macintosh single-sided 3.5" disk + MacSingleSide = 0x9A, + /// Disk is an Apple Macintosh double-sided 3.5" disk + MacDoubleSide = 0xD9 } \ No newline at end of file diff --git a/Floppy/ISO.cs b/Floppy/ISO.cs index 64fdbd0..d6da8e5 100644 --- a/Floppy/ISO.cs +++ b/Floppy/ISO.cs @@ -33,89 +33,87 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for ISO floppy decoding (also used by Atari ST and others) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class ISO { - // Information from: - // National Semiconductor PC87332VLJ datasheet - // SMsC FDC37C78 datasheet - // Intel 82078 datasheet - // Intel 82077AA datasheet - // Toshiba TC8566AF datasheet - // Fujitsu MB8876A datasheet - // ECMA-147 - // ECMA-100 - - /// Methods and structures for ISO floppy decoding (also used by Atari ST and others) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class ISO + /// ISO floppy track, also used by Atari ST and others + public struct Track { - /// ISO floppy track, also used by Atari ST and others - public struct Track - { - /// Start of track, 32 bytes set to 0x4E - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] innerGap; - /// Track sectors - public Sector[] sectors; - /// Undefined size - public byte[] gap; - } + /// Start of track, 32 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] innerGap; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } - /// Raw demodulated format for IBM System 34 floppies - public struct Sector - { - /// Sector address mark - public AddressMark addressMark; - /// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] - public byte[] innerGap; - /// Sector data block - public DataBlock dataBlock; - /// Variable bytes set to 0x4E, ECMA defines 54 - public byte[] outerGap; - } + /// Raw demodulated format for IBM System 34 floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable bytes set to 0x4E, ECMA defines 54 + public byte[] outerGap; + } - /// Sector address mark for IBM System 34 floppies, contains sync word - public struct AddressMark - { - /// 12 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xA1 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] aone; - /// Set to - public IBMIdType type; - /// Track number - public byte track; - /// Side number - public byte side; - /// Sector number - public byte sector; - /// - /// - /// - public IBMSectorSizeCode sectorSize; - /// CRC16 from to end of - public ushort crc; - } + /// Sector address mark for IBM System 34 floppies, contains sync word + public struct AddressMark + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } - /// Sector data block for IBM System 34 floppies - public struct DataBlock - { - /// 12 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xA1 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] aone; - /// Set to or to - public IBMIdType type; - /// User data - public byte[] data; - /// CRC16 from to end of - public ushort crc; - } + /// Sector data block for IBM System 34 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; } } \ No newline at end of file diff --git a/Floppy/Perpendicular.cs b/Floppy/Perpendicular.cs index 97cf709..f791315 100644 --- a/Floppy/Perpendicular.cs +++ b/Floppy/Perpendicular.cs @@ -33,107 +33,105 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for perpendicular MFM floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Perpendicular { - // Information from: - // National Semiconductor PC87332VLJ datasheet - // SMsC FDC37C78 datasheet - // Intel 82078 datasheet - // Intel 82077AA datasheet - // Toshiba TC8566AF datasheet - // Fujitsu MB8876A datasheet - // ECMA-147 - // ECMA-100 - - /// Methods and structures for perpendicular MFM floppy decoding - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Perpendicular + /// Perpendicular floppy track + public struct Track { - /// Perpendicular floppy track - public struct Track - { - /// Start of track - public TrackPreamble trackStart; - /// Track sectors - public Sector[] sectors; - /// Undefined size - public byte[] gap; - } + /// Start of track + public TrackPreamble trackStart; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } - /// Raw demodulated format for perpendicular floppies - public struct Sector - { - /// Sector address mark - public AddressMark addressMark; - /// 41 bytes set to 0x4E - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 41)] - public byte[] innerGap; - /// Sector data block - public DataBlock dataBlock; - /// Variable-sized inter-sector gap, ECMA defines 83 bytes - public byte[] outerGap; - } + /// Raw demodulated format for perpendicular floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 41 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 41)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable-sized inter-sector gap, ECMA defines 83 bytes + public byte[] outerGap; + } - /// Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others - public struct TrackPreamble - { - /// Gap from index pulse, 80 bytes set to 0x4E - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] - public byte[] gap; - /// 12 bytes set to 0x00 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xC2 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] ctwo; - /// Set to - public IBMIdType type; - /// Gap until first sector, 50 bytes to 0x4E - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] - public byte[] gap1; - } + /// Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others + public struct TrackPreamble + { + /// Gap from index pulse, 80 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] + public byte[] gap; + /// 12 bytes set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xC2 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] ctwo; + /// Set to + public IBMIdType type; + /// Gap until first sector, 50 bytes to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] + public byte[] gap1; + } - /// Sector address mark for IBM System 34 floppies, contains sync word - public struct AddressMark - { - /// 12 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xA1 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] aone; - /// Set to - public IBMIdType type; - /// Track number - public byte track; - /// Side number - public byte side; - /// Sector number - public byte sector; - /// - /// - /// - public IBMSectorSizeCode sectorSize; - /// CRC16 from to end of - public ushort crc; - } + /// Sector address mark for IBM System 34 floppies, contains sync word + public struct AddressMark + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } - /// Sector data block for IBM System 34 floppies - public struct DataBlock - { - /// 12 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xA1 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] aone; - /// Set to or to - public IBMIdType type; - /// User data - public byte[] data; - /// CRC16 from to end of - public ushort crc; - } + /// Sector data block for IBM System 34 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; } } \ No newline at end of file diff --git a/Floppy/System34.cs b/Floppy/System34.cs index b267df1..5809d22 100644 --- a/Floppy/System34.cs +++ b/Floppy/System34.cs @@ -33,107 +33,105 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for IBM System 34 floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class System34 { - // Information from: - // National Semiconductor PC87332VLJ datasheet - // SMsC FDC37C78 datasheet - // Intel 82078 datasheet - // Intel 82077AA datasheet - // Toshiba TC8566AF datasheet - // Fujitsu MB8876A datasheet - // ECMA-147 - // ECMA-100 - - /// Methods and structures for IBM System 34 floppy decoding - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class System34 + /// Track format for IBM System 34 floppy Used by IBM PC, Apple Macintosh (high-density only), and a lot others + public struct Track { - /// Track format for IBM System 34 floppy Used by IBM PC, Apple Macintosh (high-density only), and a lot others - public struct Track - { - /// Start of track - public TrackPreamble trackStart; - /// Track sectors - public Sector[] sectors; - /// Undefined size - public byte[] gap; - } + /// Start of track + public TrackPreamble trackStart; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } - /// Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others - public struct TrackPreamble - { - /// Gap from index pulse, 80 bytes set to 0x4E - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] - public byte[] gap; - /// 12 bytes set to 0x00 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xC2 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] ctwo; - /// Set to - public IBMIdType type; - /// Gap until first sector, 50 bytes to 0x4E - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] - public byte[] gap1; - } + /// Start of IBM PC MFM floppy track Used by IBM PC, Apple Macintosh (high-density only), and a lot others + public struct TrackPreamble + { + /// Gap from index pulse, 80 bytes set to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] + public byte[] gap; + /// 12 bytes set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xC2 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] ctwo; + /// Set to + public IBMIdType type; + /// Gap until first sector, 50 bytes to 0x4E + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] + public byte[] gap1; + } - /// Raw demodulated format for IBM System 34 floppies - public struct Sector - { - /// Sector address mark - public AddressMark addressMark; - /// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] - public byte[] innerGap; - /// Sector data block - public DataBlock dataBlock; - /// Variable bytes set to 0x4E, ECMA defines 54 - public byte[] outerGap; - } + /// Raw demodulated format for IBM System 34 floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 22 bytes set to 0x4E, set to 0x22 on Commodore 1581 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 22)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable bytes set to 0x4E, ECMA defines 54 + public byte[] outerGap; + } - /// Sector address mark for IBM System 34 floppies, contains sync word - public struct AddressMark - { - /// 12 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xA1 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] aone; - /// Set to - public IBMIdType type; - /// Track number - public byte track; - /// Side number - public byte side; - /// Sector number - public byte sector; - /// - /// - /// - public IBMSectorSizeCode sectorSize; - /// CRC16 from to end of - public ushort crc; - } + /// Sector address mark for IBM System 34 floppies, contains sync word + public struct AddressMark + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } - /// Sector data block for IBM System 34 floppies - public struct DataBlock - { - /// 12 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// 3 bytes set to 0xA1 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] aone; - /// Set to or to - public IBMIdType type; - /// User data - public byte[] data; - /// CRC16 from to end of - public ushort crc; - } + /// Sector data block for IBM System 34 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// 3 bytes set to 0xA1 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] aone; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; } } \ No newline at end of file diff --git a/Floppy/System3740.cs b/Floppy/System3740.cs index b5303d4..287e0aa 100644 --- a/Floppy/System3740.cs +++ b/Floppy/System3740.cs @@ -33,98 +33,96 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; -namespace Aaru.Decoders.Floppy +namespace Aaru.Decoders.Floppy; +// Information from: +// National Semiconductor PC87332VLJ datasheet +// SMsC FDC37C78 datasheet +// Intel 82078 datasheet +// Intel 82077AA datasheet +// Toshiba TC8566AF datasheet +// Fujitsu MB8876A datasheet +// ECMA-147 +// ECMA-100 + +/// Methods and structures for IBM System 3740 floppy decoding +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class System3740 { - // Information from: - // National Semiconductor PC87332VLJ datasheet - // SMsC FDC37C78 datasheet - // Intel 82078 datasheet - // Intel 82077AA datasheet - // Toshiba TC8566AF datasheet - // Fujitsu MB8876A datasheet - // ECMA-147 - // ECMA-100 - - /// Methods and structures for IBM System 3740 floppy decoding - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class System3740 + /// Track format for IBM System 3740 floppy + public struct Track { - /// Track format for IBM System 3740 floppy - public struct Track - { - /// Start of track - public TrackPreamble trackStart; - /// Track sectors - public Sector[] sectors; - /// Undefined size - public byte[] gap; - } + /// Start of track + public TrackPreamble trackStart; + /// Track sectors + public Sector[] sectors; + /// Undefined size + public byte[] gap; + } - /// Start of IBM PC FM floppy track - public struct TrackPreamble - { - /// Gap from index pulse, 80 bytes set to 0xFF - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] - public byte[] gap; - /// 6 bytes set to 0x00 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] zero; - /// Set to - public IBMIdType type; - /// Gap until first sector, 26 bytes to 0xFF - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] - public byte[] gap1; - } + /// Start of IBM PC FM floppy track + public struct TrackPreamble + { + /// Gap from index pulse, 80 bytes set to 0xFF + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] + public byte[] gap; + /// 6 bytes set to 0x00 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] zero; + /// Set to + public IBMIdType type; + /// Gap until first sector, 26 bytes to 0xFF + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] + public byte[] gap1; + } - /// Raw demodulated format for IBM System 3740 floppies - public struct Sector - { - /// Sector address mark - public AddressMark addressMark; - /// 11 bytes set to 0xFF - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public byte[] innerGap; - /// Sector data block - public DataBlock dataBlock; - /// Variable bytes set to 0xFF - public byte[] outerGap; - } + /// Raw demodulated format for IBM System 3740 floppies + public struct Sector + { + /// Sector address mark + public AddressMark addressMark; + /// 11 bytes set to 0xFF + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] innerGap; + /// Sector data block + public DataBlock dataBlock; + /// Variable bytes set to 0xFF + public byte[] outerGap; + } - /// Sector address mark for IBM System 3740 floppies, contains sync word - public struct AddressMark - { - /// 6 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] zero; - /// Set to - public IBMIdType type; - /// Track number - public byte track; - /// Side number - public byte side; - /// Sector number - public byte sector; - /// - /// - /// - public IBMSectorSizeCode sectorSize; - /// CRC16 from to end of - public ushort crc; - } + /// Sector address mark for IBM System 3740 floppies, contains sync word + public struct AddressMark + { + /// 6 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] zero; + /// Set to + public IBMIdType type; + /// Track number + public byte track; + /// Side number + public byte side; + /// Sector number + public byte sector; + /// + /// + /// + public IBMSectorSizeCode sectorSize; + /// CRC16 from to end of + public ushort crc; + } - /// Sector data block for IBM System 3740 floppies - public struct DataBlock - { - /// 12 bytes set to 0 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] zero; - /// Set to or to - public IBMIdType type; - /// User data - public byte[] data; - /// CRC16 from to end of - public ushort crc; - } + /// Sector data block for IBM System 3740 floppies + public struct DataBlock + { + /// 12 bytes set to 0 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] zero; + /// Set to or to + public IBMIdType type; + /// User data + public byte[] data; + /// CRC16 from to end of + public ushort crc; } } \ No newline at end of file diff --git a/LisaTag.cs b/LisaTag.cs index 5495e1d..1f6f4d7 100644 --- a/LisaTag.cs +++ b/LisaTag.cs @@ -34,473 +34,472 @@ using System; using System.Diagnostics.CodeAnalysis; using Aaru.Helpers; -namespace Aaru.Decoders +namespace Aaru.Decoders; + +/// Represents a Lisa Office 7/7 sector tag +[SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "NotAccessedField.Global"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), + SuppressMessage("ReSharper", "StructMemberCanBeMadeReadOnly")] +public static class LisaTag { - /// Represents a Lisa Office 7/7 sector tag - [SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "NotAccessedField.Global"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), - SuppressMessage("ReSharper", "StructMemberCanBeMadeReadOnly")] - public static class LisaTag + /// Decodes tag from a 3.5" Sony micro-floppy + /// Byte array containing raw tag data + /// Decoded tag in Sony's format + public static SonyTag? DecodeSonyTag(byte[] tag) { - /// Decodes tag from a 3.5" Sony micro-floppy - /// Byte array containing raw tag data - /// Decoded tag in Sony's format - public static SonyTag? DecodeSonyTag(byte[] tag) + if(tag == null || + tag.Length != 12) + return null; + + var snTag = new SonyTag { - if(tag == null || - tag.Length != 12) - return null; + 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), + PrevBlock = (ushort)(BigEndianBitConverter.ToUInt16(tag, 10) & 0x7FF) + }; - var snTag = new SonyTag - { - 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), - PrevBlock = (ushort)(BigEndianBitConverter.ToUInt16(tag, 10) & 0x7FF) - }; + snTag.IsLast = snTag.NextBlock == 0x7FF; + snTag.IsFirst = snTag.PrevBlock == 0x7FF; - snTag.IsLast = snTag.NextBlock == 0x7FF; - snTag.IsFirst = snTag.PrevBlock == 0x7FF; + return snTag; + } - return snTag; + /// Decodes tag from a Profile + /// Byte array containing raw tag data + /// Decoded tag in Profile's format + public static ProfileTag? DecodeProfileTag(byte[] tag) + { + if(tag == null || + tag.Length != 20) + return null; + + var phTag = new ProfileTag(); + + byte[] tmp = new byte[4]; + + phTag.Version = BigEndianBitConverter.ToUInt16(tag, 0); + phTag.Kind = (byte)((tag[2] & 0xC0) >> 6); + phTag.Reserved = (byte)(tag[2] & 0x3F); + phTag.Volume = tag[3]; + phTag.FileId = BigEndianBitConverter.ToInt16(tag, 4); + phTag.ValidChk |= (tag[6] & 0x80) == 0x80; + phTag.UsedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + + tmp[0] = 0x00; + tmp[1] = tag[8]; + tmp[2] = tag[9]; + tmp[3] = tag[10]; + phTag.AbsPage = BigEndianBitConverter.ToUInt32(tmp, 0); + + phTag.Checksum = tag[11]; + phTag.RelPage = BigEndianBitConverter.ToUInt16(tag, 12); + + tmp[0] = 0x00; + tmp[1] = tag[14]; + tmp[2] = tag[15]; + tmp[3] = tag[16]; + phTag.NextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + tmp[0] = 0x00; + tmp[1] = tag[17]; + tmp[2] = tag[18]; + tmp[3] = tag[19]; + phTag.PrevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + phTag.IsLast = phTag.NextBlock == 0xFFFFFF; + phTag.IsFirst = phTag.PrevBlock == 0xFFFFFF; + + return phTag; + } + + /// Decodes tag from a Priam + /// Byte array containing raw tag data + /// Decoded tag in Priam's format + public static PriamTag? DecodePriamTag(byte[] tag) + { + if(tag == null || + tag.Length != 24) + return null; + + var pmTag = new PriamTag(); + + byte[] tmp = new byte[4]; + + pmTag.Version = BigEndianBitConverter.ToUInt16(tag, 0); + pmTag.Kind = (byte)((tag[2] & 0xC0) >> 6); + pmTag.Reserved = (byte)(tag[2] & 0x3F); + pmTag.Volume = tag[3]; + pmTag.FileId = BigEndianBitConverter.ToInt16(tag, 4); + pmTag.ValidChk |= (tag[6] & 0x80) == 0x80; + pmTag.UsedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + + tmp[0] = 0x00; + tmp[1] = tag[8]; + tmp[2] = tag[9]; + tmp[3] = tag[10]; + pmTag.AbsPage = BigEndianBitConverter.ToUInt32(tmp, 0); + + pmTag.Checksum = tag[11]; + pmTag.RelPage = BigEndianBitConverter.ToUInt16(tag, 12); + + tmp[0] = 0x00; + tmp[1] = tag[14]; + tmp[2] = tag[15]; + tmp[3] = tag[16]; + pmTag.NextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + tmp[0] = 0x00; + tmp[1] = tag[17]; + tmp[2] = tag[18]; + tmp[3] = tag[19]; + pmTag.PrevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); + + pmTag.DiskSize = BigEndianBitConverter.ToUInt32(tag, 20); + + pmTag.IsLast = pmTag.NextBlock == 0xFFFFFF; + pmTag.IsFirst = pmTag.PrevBlock == 0xFFFFFF; + + return pmTag; + } + + /// Decodes tag from any known format + /// Byte array containing raw tag data + /// Decoded tag in Priam's format + public static PriamTag? DecodeTag(byte[] tag) + { + if(tag == null) + return null; + + PriamTag pmTag; + + switch(tag.Length) + { + case 12: + SonyTag? snTag = DecodeSonyTag(tag); + + if(snTag == null) + return null; + + pmTag = new PriamTag(); + pmTag.AbsPage = 0; + pmTag.Checksum = 0; + pmTag.DiskSize = 0; + pmTag.FileId = snTag.Value.FileId; + pmTag.Kind = snTag.Value.Kind; + pmTag.NextBlock = snTag.Value.NextBlock; + pmTag.PrevBlock = snTag.Value.PrevBlock; + pmTag.RelPage = snTag.Value.RelPage; + pmTag.Reserved = snTag.Value.Reserved; + pmTag.UsedBytes = 0; + pmTag.ValidChk = false; + pmTag.Version = snTag.Value.Version; + pmTag.Volume = snTag.Value.Volume; + pmTag.IsFirst = snTag.Value.IsFirst; + pmTag.IsLast = snTag.Value.IsLast; + + return pmTag; + case 20: + ProfileTag? phTag = DecodeProfileTag(tag); + + if(phTag == null) + return null; + + pmTag = new PriamTag(); + pmTag.AbsPage = phTag.Value.AbsPage; + pmTag.Checksum = phTag.Value.Checksum; + pmTag.DiskSize = 0; + pmTag.FileId = phTag.Value.FileId; + pmTag.Kind = phTag.Value.Kind; + pmTag.NextBlock = phTag.Value.NextBlock; + pmTag.PrevBlock = phTag.Value.PrevBlock; + pmTag.RelPage = phTag.Value.RelPage; + pmTag.Reserved = phTag.Value.Reserved; + pmTag.UsedBytes = phTag.Value.UsedBytes; + pmTag.ValidChk = phTag.Value.ValidChk; + pmTag.Version = phTag.Value.Version; + pmTag.Volume = phTag.Value.Volume; + pmTag.IsFirst = phTag.Value.IsFirst; + pmTag.IsLast = phTag.Value.IsLast; + + return pmTag; + case 24: return DecodePriamTag(tag); + default: return null; } + } - /// Decodes tag from a Profile - /// Byte array containing raw tag data - /// Decoded tag in Profile's format - public static ProfileTag? DecodeProfileTag(byte[] tag) + /// LisaOS tag as stored on Apple Profile and FileWare disks (20 bytes) + public struct ProfileTag + { + /// 0x00, Lisa OS version number + public ushort Version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte Kind; + /// 0x02 bits 5 to 0, reserved + public byte Reserved; + /// 0x03, disk volume number + public byte Volume; + /// 0x04, file ID + public short FileId; + /// 0x06 bit 7, checksum valid? + public bool ValidChk; + /// 0x06 bits 6 to 0, used bytes in block + public ushort UsedBytes; + /// 0x08, 3 bytes, absolute page number + public uint AbsPage; + /// 0x0B, checksum of data + public byte Checksum; + /// 0x0C, relative page number + public ushort RelPage; + /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block + public uint NextBlock; + /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block + public uint PrevBlock; + + /// On-memory value for easy first block search. + public bool IsFirst; + /// On-memory value for easy last block search. + public bool IsLast; + + /// Converts this tag to Priam DataTower format + public PriamTag ToPriam() => new PriamTag { - if(tag == null || - tag.Length != 20) - return null; + 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 + }; - var phTag = new ProfileTag(); + /// Converts this tag to Sony format + 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 + }; - byte[] tmp = new byte[4]; + /// Gets a byte array representation of this tag + public byte[] GetBytes() + { + byte[] tagBytes = new byte[20]; - phTag.Version = BigEndianBitConverter.ToUInt16(tag, 0); - phTag.Kind = (byte)((tag[2] & 0xC0) >> 6); - phTag.Reserved = (byte)(tag[2] & 0x3F); - phTag.Volume = tag[3]; - phTag.FileId = BigEndianBitConverter.ToInt16(tag, 4); - phTag.ValidChk |= (tag[6] & 0x80) == 0x80; - phTag.UsedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + 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); - tmp[0] = 0x00; - tmp[1] = tag[8]; - tmp[2] = tag[9]; - tmp[3] = tag[10]; - phTag.AbsPage = BigEndianBitConverter.ToUInt32(tmp, 0); + if(ValidChk) + tagBytes[6] += 0x80; - phTag.Checksum = tag[11]; - phTag.RelPage = BigEndianBitConverter.ToUInt16(tag, 12); + 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[0] = 0x00; - tmp[1] = tag[14]; - tmp[2] = tag[15]; - tmp[3] = tag[16]; - phTag.NextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); - - tmp[0] = 0x00; - tmp[1] = tag[17]; - tmp[2] = tag[18]; - tmp[3] = tag[19]; - phTag.PrevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); - - phTag.IsLast = phTag.NextBlock == 0xFFFFFF; - phTag.IsFirst = phTag.PrevBlock == 0xFFFFFF; - - return phTag; + return tagBytes; } + } - /// Decodes tag from a Priam - /// Byte array containing raw tag data - /// Decoded tag in Priam's format - public static PriamTag? DecodePriamTag(byte[] tag) + /// LisaOS tag as stored on Priam DataTower disks (24 bytes) + public struct PriamTag + { + /// 0x00, Lisa OS version number + public ushort Version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte Kind; + /// 0x02 bits 5 to 0, reserved + public byte Reserved; + /// 0x03, disk volume number + public byte Volume; + /// 0x04, file ID + public short FileId; + /// 0x06 bit 7, checksum valid? + public bool ValidChk; + /// 0x06 bits 6 to 0, used bytes in block + public ushort UsedBytes; + /// 0x08, 3 bytes, absolute page number + public uint AbsPage; + /// 0x0B, checksum of data + public byte Checksum; + /// 0x0C, relative page number + public ushort RelPage; + /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block + public uint NextBlock; + /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block + public uint PrevBlock; + /// 0x14, disk size + public uint DiskSize; + + /// On-memory value for easy first block search. + public bool IsFirst; + /// On-memory value for easy last block search. + public bool IsLast; + + /// Converts this tag to Apple Profile format + public ProfileTag ToProfile() => new ProfileTag { - if(tag == null || - tag.Length != 24) - return null; + 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 + }; - var pmTag = new PriamTag(); + /// Converts this tag to Sony format + 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 + }; - byte[] tmp = new byte[4]; + /// Gets a byte array representation of this tag + public byte[] GetBytes() + { + byte[] tagBytes = new byte[24]; - pmTag.Version = BigEndianBitConverter.ToUInt16(tag, 0); - pmTag.Kind = (byte)((tag[2] & 0xC0) >> 6); - pmTag.Reserved = (byte)(tag[2] & 0x3F); - pmTag.Volume = tag[3]; - pmTag.FileId = BigEndianBitConverter.ToInt16(tag, 4); - pmTag.ValidChk |= (tag[6] & 0x80) == 0x80; - pmTag.UsedBytes = (ushort)(BigEndianBitConverter.ToUInt16(tag, 6) & 0x7FFF); + 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); - tmp[0] = 0x00; - tmp[1] = tag[8]; - tmp[2] = tag[9]; - tmp[3] = tag[10]; - pmTag.AbsPage = BigEndianBitConverter.ToUInt32(tmp, 0); + if(ValidChk) + tagBytes[6] += 0x80; - pmTag.Checksum = tag[11]; - pmTag.RelPage = BigEndianBitConverter.ToUInt16(tag, 12); + 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); - tmp[0] = 0x00; - tmp[1] = tag[14]; - tmp[2] = tag[15]; - tmp[3] = tag[16]; - pmTag.NextBlock = BigEndianBitConverter.ToUInt32(tmp, 0); - - tmp[0] = 0x00; - tmp[1] = tag[17]; - tmp[2] = tag[18]; - tmp[3] = tag[19]; - pmTag.PrevBlock = BigEndianBitConverter.ToUInt32(tmp, 0); - - pmTag.DiskSize = BigEndianBitConverter.ToUInt32(tag, 20); - - pmTag.IsLast = pmTag.NextBlock == 0xFFFFFF; - pmTag.IsFirst = pmTag.PrevBlock == 0xFFFFFF; - - return pmTag; + return tagBytes; } + } - /// Decodes tag from any known format - /// Byte array containing raw tag data - /// Decoded tag in Priam's format - public static PriamTag? DecodeTag(byte[] tag) + /// LisaOS tag as stored on Apple Sony disks (12 bytes) + public struct SonyTag + { + /// 0x00, Lisa OS version number + public ushort Version; + /// 0x02 bits 7 to 6, kind of info in this block + public byte Kind; + /// 0x02 bits 5 to 0, reserved + public byte Reserved; + /// 0x03, disk volume number + public byte Volume; + /// 0x04, file ID + public short FileId; + /// 0x06, relative page number + public ushort RelPage; + /// 0x08, 3 bytes, next block, 0x7FF if it's last block, 0x8000 set if block is valid + public ushort NextBlock; + /// 0x0A, 3 bytes, previous block, 0x7FF if it's first block + public ushort PrevBlock; + + /// On-memory value for easy first block search. + public bool IsFirst; + /// On-memory value for easy last block search. + public bool IsLast; + + /// Converts this tag to Apple Profile format + public ProfileTag ToProfile() => new ProfileTag { - if(tag == null) - return null; + 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 + }; - PriamTag pmTag; - - switch(tag.Length) - { - case 12: - SonyTag? snTag = DecodeSonyTag(tag); - - if(snTag == null) - return null; - - pmTag = new PriamTag(); - pmTag.AbsPage = 0; - pmTag.Checksum = 0; - pmTag.DiskSize = 0; - pmTag.FileId = snTag.Value.FileId; - pmTag.Kind = snTag.Value.Kind; - pmTag.NextBlock = snTag.Value.NextBlock; - pmTag.PrevBlock = snTag.Value.PrevBlock; - pmTag.RelPage = snTag.Value.RelPage; - pmTag.Reserved = snTag.Value.Reserved; - pmTag.UsedBytes = 0; - pmTag.ValidChk = false; - pmTag.Version = snTag.Value.Version; - pmTag.Volume = snTag.Value.Volume; - pmTag.IsFirst = snTag.Value.IsFirst; - pmTag.IsLast = snTag.Value.IsLast; - - return pmTag; - case 20: - ProfileTag? phTag = DecodeProfileTag(tag); - - if(phTag == null) - return null; - - pmTag = new PriamTag(); - pmTag.AbsPage = phTag.Value.AbsPage; - pmTag.Checksum = phTag.Value.Checksum; - pmTag.DiskSize = 0; - pmTag.FileId = phTag.Value.FileId; - pmTag.Kind = phTag.Value.Kind; - pmTag.NextBlock = phTag.Value.NextBlock; - pmTag.PrevBlock = phTag.Value.PrevBlock; - pmTag.RelPage = phTag.Value.RelPage; - pmTag.Reserved = phTag.Value.Reserved; - pmTag.UsedBytes = phTag.Value.UsedBytes; - pmTag.ValidChk = phTag.Value.ValidChk; - pmTag.Version = phTag.Value.Version; - pmTag.Volume = phTag.Value.Volume; - pmTag.IsFirst = phTag.Value.IsFirst; - pmTag.IsLast = phTag.Value.IsLast; - - return pmTag; - case 24: return DecodePriamTag(tag); - default: return null; - } - } - - /// LisaOS tag as stored on Apple Profile and FileWare disks (20 bytes) - public struct ProfileTag + /// Converts this tag to Priam DataTower format + public PriamTag ToPriam() => new PriamTag { - /// 0x00, Lisa OS version number - public ushort Version; - /// 0x02 bits 7 to 6, kind of info in this block - public byte Kind; - /// 0x02 bits 5 to 0, reserved - public byte Reserved; - /// 0x03, disk volume number - public byte Volume; - /// 0x04, file ID - public short FileId; - /// 0x06 bit 7, checksum valid? - public bool ValidChk; - /// 0x06 bits 6 to 0, used bytes in block - public ushort UsedBytes; - /// 0x08, 3 bytes, absolute page number - public uint AbsPage; - /// 0x0B, checksum of data - public byte Checksum; - /// 0x0C, relative page number - public ushort RelPage; - /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block - public uint NextBlock; - /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block - public uint PrevBlock; + 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 + }; - /// On-memory value for easy first block search. - public bool IsFirst; - /// On-memory value for easy last block search. - public bool IsLast; - - /// Converts this tag to Priam DataTower format - 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 - }; - - /// Converts this tag to Sony format - 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 - }; - - /// Gets a byte array representation of this tag - 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; - } - } - - /// LisaOS tag as stored on Priam DataTower disks (24 bytes) - public struct PriamTag + /// Gets a byte array representation of this tag + public byte[] GetBytes() { - /// 0x00, Lisa OS version number - public ushort Version; - /// 0x02 bits 7 to 6, kind of info in this block - public byte Kind; - /// 0x02 bits 5 to 0, reserved - public byte Reserved; - /// 0x03, disk volume number - public byte Volume; - /// 0x04, file ID - public short FileId; - /// 0x06 bit 7, checksum valid? - public bool ValidChk; - /// 0x06 bits 6 to 0, used bytes in block - public ushort UsedBytes; - /// 0x08, 3 bytes, absolute page number - public uint AbsPage; - /// 0x0B, checksum of data - public byte Checksum; - /// 0x0C, relative page number - public ushort RelPage; - /// 0x0E, 3 bytes, next block, 0xFFFFFF if it's last block - public uint NextBlock; - /// 0x11, 3 bytes, previous block, 0xFFFFFF if it's first block - public uint PrevBlock; - /// 0x14, disk size - public uint DiskSize; + byte[] tagBytes = new byte[12]; - /// On-memory value for easy first block search. - public bool IsFirst; - /// On-memory value for easy last block search. - public bool IsLast; + 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); - /// Converts this tag to Apple Profile format - 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 - }; - - /// Converts this tag to Sony format - 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 - }; - - /// Gets a byte array representation of this tag - 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; - } - } - - /// LisaOS tag as stored on Apple Sony disks (12 bytes) - public struct SonyTag - { - /// 0x00, Lisa OS version number - public ushort Version; - /// 0x02 bits 7 to 6, kind of info in this block - public byte Kind; - /// 0x02 bits 5 to 0, reserved - public byte Reserved; - /// 0x03, disk volume number - public byte Volume; - /// 0x04, file ID - public short FileId; - /// 0x06, relative page number - public ushort RelPage; - /// 0x08, 3 bytes, next block, 0x7FF if it's last block, 0x8000 set if block is valid - public ushort NextBlock; - /// 0x0A, 3 bytes, previous block, 0x7FF if it's first block - public ushort PrevBlock; - - /// On-memory value for easy first block search. - public bool IsFirst; - /// On-memory value for easy last block search. - public bool IsLast; - - /// Converts this tag to Apple Profile format - 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 - }; - - /// Converts this tag to Priam DataTower format - 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 - }; - - /// Gets a byte array representation of this tag - 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; - } + return tagBytes; } } } \ No newline at end of file diff --git a/MMC/CID.cs b/MMC/CID.cs index 8545b68..bed69b5 100644 --- a/MMC/CID.cs +++ b/MMC/CID.cs @@ -35,180 +35,179 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.MMC +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global")] +public class CID { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global")] - public class CID + public byte ApplicationID; + public byte CRC; + public byte DeviceType; + public byte Manufacturer; + public byte ManufacturingDate; + public string ProductName; + public byte ProductRevision; + public uint ProductSerialNumber; +} + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Decoders +{ + public static CID DecodeCID(uint[] response) { - public byte ApplicationID; - public byte CRC; - public byte DeviceType; - public byte Manufacturer; - public byte ManufacturingDate; - public string ProductName; - public byte ProductRevision; - public uint ProductSerialNumber; + if(response?.Length != 4) + return null; + + byte[] data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCID(data); } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Decoders + public static CID DecodeCID(byte[] response) { - public static CID DecodeCID(uint[] response) + if(response?.Length != 16) + return null; + + var cid = new CID { - if(response?.Length != 4) - return null; + Manufacturer = response[0], + DeviceType = (byte)(response[1] & 0x03), + ProductRevision = response[9], + ProductSerialNumber = Swapping.Swap(BitConverter.ToUInt32(response, 10)), + ManufacturingDate = response[14], + CRC = (byte)((response[15] & 0xFE) >> 1) + }; - byte[] data = new byte[16]; + byte[] tmp = new byte[6]; + Array.Copy(response, 3, tmp, 0, 6); + cid.ProductName = StringHandlers.CToString(tmp); - byte[] tmp = BitConverter.GetBytes(response[0]); - Array.Copy(tmp, 0, data, 0, 4); - tmp = BitConverter.GetBytes(response[1]); - Array.Copy(tmp, 0, data, 4, 4); - tmp = BitConverter.GetBytes(response[2]); - Array.Copy(tmp, 0, data, 8, 4); - tmp = BitConverter.GetBytes(response[3]); - Array.Copy(tmp, 0, data, 12, 4); - - return DecodeCID(data); - } - - public static CID DecodeCID(byte[] response) - { - if(response?.Length != 16) - return null; - - var cid = new CID - { - Manufacturer = response[0], - DeviceType = (byte)(response[1] & 0x03), - ProductRevision = response[9], - ProductSerialNumber = Swapping.Swap(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); - - return cid; - } - - public static string PrettifyCID(CID cid) - { - if(cid == null) - return null; - - 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("\tCID CRC: 0x{0:X2}", cid.CRC).AppendLine(); - - return sb.ToString(); - } - - public static string PrettifyCID(uint[] response) => PrettifyCID(DecodeCID(response)); - - public static string PrettifyCID(byte[] response) => PrettifyCID(DecodeCID(response)); + return cid; } + + public static string PrettifyCID(CID cid) + { + if(cid == null) + return null; + + 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("\tCID CRC: 0x{0:X2}", cid.CRC).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyCID(uint[] response) => PrettifyCID(DecodeCID(response)); + + public static string PrettifyCID(byte[] response) => PrettifyCID(DecodeCID(response)); } \ No newline at end of file diff --git a/MMC/CSD.cs b/MMC/CSD.cs index d0b7ae1..9ed834e 100644 --- a/MMC/CSD.cs +++ b/MMC/CSD.cs @@ -34,651 +34,650 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.MMC +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class CSD { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public class CSD + public ushort Classes; + public bool ContentProtection; + public bool Copy; + public byte CRC; + public byte DefaultECC; + public bool DSRImplemented; + public byte ECC; + public byte EraseGroupSize; + public byte EraseGroupSizeMultiplier; + public byte FileFormat; + 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")] +public static partial class Decoders +{ + public static CSD DecodeCSD(uint[] response) { - public ushort Classes; - public bool ContentProtection; - public bool Copy; - public byte CRC; - public byte DefaultECC; - public bool DSRImplemented; - public byte ECC; - public byte EraseGroupSize; - public byte EraseGroupSizeMultiplier; - public byte FileFormat; - 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; + if(response?.Length != 4) + return null; + + byte[] data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCSD(data); } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Decoders + public static CSD DecodeCSD(byte[] response) { - public static CSD DecodeCSD(uint[] response) + if(response?.Length != 16) + return null; + + return new CSD { - if(response?.Length != 4) - return null; + Structure = (byte)((response[0] & 0xC0) >> 6), + Version = (byte)((response[0] & 0x3C) >> 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, + Size = (ushort)(((response[6] & 0x03) << 10) + (response[7] << 2) + ((response[8] & 0xC0) >> 6)), + ReadCurrentAtVddMin = (byte)((response[8] & 0x38) >> 3), + ReadCurrentAtVddMax = (byte)(response[8] & 0x07), + WriteCurrentAtVddMin = (byte)((response[9] & 0xE0) >> 5), + WriteCurrentAtVddMax = (byte)((response[9] & 0x1C) >> 2), + SizeMultiplier = (byte)(((response[9] & 0x03) << 1) + ((response[10] & 0x80) >> 7)), + EraseGroupSize = (byte)((response[10] & 0x7C) >> 2), + EraseGroupSizeMultiplier = (byte)(((response[10] & 0x03) << 3) + ((response[11] & 0xE0) >> 5)), + WriteProtectGroupSize = (byte)(response[11] & 0x1F), + WriteProtectGroupEnable = (response[12] & 0x80) == 0x80, + DefaultECC = (byte)((response[12] & 0x60) >> 5), + WriteSpeedFactor = (byte)((response[12] & 0x1C) >> 2), + WriteBlockLength = (byte)(((response[12] & 0x03) << 2) + ((response[13] & 0xC0) >> 6)), + WritesPartialBlocks = (response[13] & 0x20) == 0x20, + ContentProtection = (response[13] & 0x01) == 0x01, + FileFormatGroup = (response[14] & 0x80) == 0x80, + Copy = (response[14] & 0x40) == 0x40, + PermanentWriteProtect = (response[14] & 0x20) == 0x20, + TemporaryWriteProtect = (response[14] & 0x10) == 0x10, + FileFormat = (byte)((response[14] & 0x0C) >> 2), + ECC = (byte)(response[14] & 0x03), + CRC = (byte)((response[15] & 0xFE) >> 1) + }; + } - byte[] data = new byte[16]; + public static string PrettifyCSD(CSD csd) + { + if(csd == null) + return null; - byte[] tmp = BitConverter.GetBytes(response[0]); - Array.Copy(tmp, 0, data, 0, 4); - tmp = BitConverter.GetBytes(response[1]); - Array.Copy(tmp, 0, data, 4, 4); - tmp = BitConverter.GetBytes(response[2]); - Array.Copy(tmp, 0, data, 8, 4); - tmp = BitConverter.GetBytes(response[3]); - Array.Copy(tmp, 0, data, 12, 4); + double unitFactor = 0; + double multiplier = 0; + string unit = ""; - return DecodeCSD(data); + 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; } - public static CSD DecodeCSD(byte[] response) + switch(csd.TAAC & 0x07) { - if(response?.Length != 16) - return null; + case 0: + unit = "ns"; + unitFactor = 1; - return new CSD - { - Structure = (byte)((response[0] & 0xC0) >> 6), - Version = (byte)((response[0] & 0x3C) >> 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, - Size = (ushort)(((response[6] & 0x03) << 10) + (response[7] << 2) + ((response[8] & 0xC0) >> 6)), - ReadCurrentAtVddMin = (byte)((response[8] & 0x38) >> 3), - ReadCurrentAtVddMax = (byte)(response[8] & 0x07), - WriteCurrentAtVddMin = (byte)((response[9] & 0xE0) >> 5), - WriteCurrentAtVddMax = (byte)((response[9] & 0x1C) >> 2), - SizeMultiplier = (byte)(((response[9] & 0x03) << 1) + ((response[10] & 0x80) >> 7)), - EraseGroupSize = (byte)((response[10] & 0x7C) >> 2), - EraseGroupSizeMultiplier = (byte)(((response[10] & 0x03) << 3) + ((response[11] & 0xE0) >> 5)), - WriteProtectGroupSize = (byte)(response[11] & 0x1F), - WriteProtectGroupEnable = (response[12] & 0x80) == 0x80, - DefaultECC = (byte)((response[12] & 0x60) >> 5), - WriteSpeedFactor = (byte)((response[12] & 0x1C) >> 2), - WriteBlockLength = (byte)(((response[12] & 0x03) << 2) + ((response[13] & 0xC0) >> 6)), - WritesPartialBlocks = (response[13] & 0x20) == 0x20, - ContentProtection = (response[13] & 0x01) == 0x01, - FileFormatGroup = (response[14] & 0x80) == 0x80, - Copy = (response[14] & 0x40) == 0x40, - PermanentWriteProtect = (response[14] & 0x20) == 0x20, - TemporaryWriteProtect = (response[14] & 0x10) == 0x10, - FileFormat = (byte)((response[14] & 0x0C) >> 2), - ECC = (byte)(response[14] & 0x03), - CRC = (byte)((response[15] & 0xFE) >> 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; } - public static string PrettifyCSD(CSD csd) + switch((csd.TAAC & 0x78) >> 3) { - if(csd == null) - return null; + case 0: + multiplier = 0; - double unitFactor = 0; - double multiplier = 0; - string unit = ""; + break; + case 1: + multiplier = 1; - var sb = new StringBuilder(); - sb.AppendLine("MultiMediaCard Device Specific Data Register:"); + break; + case 2: + multiplier = 1.2; - switch(csd.Structure) + 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; + } + + double result = unitFactor * multiplier; + sb.AppendFormat("\tAsynchronous data access time is {0}{1}", result, unit).AppendLine(); + + 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; + } + + switch((csd.Speed & 0x78) >> 3) + { + 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; + } + + result = unitFactor * multiplier; + 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.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"); + + result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2); + 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(); + + 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; + } + + switch(csd.ReadCurrentAtVddMax & 0x07) + { + 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; + } + + switch(csd.WriteCurrentAtVddMin & 0x07) + { + 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; + } + + switch(csd.WriteCurrentAtVddMax & 0x07) + { + 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; + } + + // TODO: Check specification + unitFactor = Convert.ToDouble(csd.EraseGroupSize); + multiplier = Convert.ToDouble(csd.EraseGroupSizeMultiplier); + result = (unitFactor + 1) * (multiplier + 1); + sb.AppendFormat("\tDevice can erase a minimum of {0} blocks at a time", (int)result).AppendLine(); + + 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(); + } + 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(); + + 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.ContentProtection) + sb.AppendLine("\tDevice supports content protection"); + + if(!csd.Copy) + sb.AppendLine("\tDevice contents are original"); + + if(csd.PermanentWriteProtect) + sb.AppendLine("\tDevice is permanently write protected"); + + if(csd.TemporaryWriteProtect) + sb.AppendLine("\tDevice is temporarily write protected"); + + if(!csd.FileFormatGroup) + switch(csd.FileFormat) { case 0: - sb.AppendLine("\tRegister version 1.0"); + sb.AppendLine("\tDevice is formatted like a hard disk"); break; case 1: - sb.AppendLine("\tRegister version 1.1"); + sb.AppendLine("\tDevice is formatted like a floppy disk using Microsoft FAT"); 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; - } - - switch(csd.TAAC & 0x07) - { - 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; - } - - switch((csd.TAAC & 0x78) >> 3) - { - 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; - } - - double result = unitFactor * multiplier; - sb.AppendFormat("\tAsynchronous data access time is {0}{1}", result, unit).AppendLine(); - - 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; + sb.AppendLine("\tDevice uses Universal File Format"); break; default: - unit = "unknown"; - unitFactor = 0; + sb.AppendFormat("\tDevice uses unknown file format code {0}", csd.FileFormat).AppendLine(); break; } - - switch((csd.Speed & 0x78) >> 3) - { - 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; - } - - result = unitFactor * multiplier; - 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.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"); - - result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2); - 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(); - - 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; - } - - switch(csd.ReadCurrentAtVddMax & 0x07) - { - 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; - } - - switch(csd.WriteCurrentAtVddMin & 0x07) - { - 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; - } - - switch(csd.WriteCurrentAtVddMax & 0x07) - { - 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; - } - - // TODO: Check specification - unitFactor = Convert.ToDouble(csd.EraseGroupSize); - multiplier = Convert.ToDouble(csd.EraseGroupSizeMultiplier); - result = (unitFactor + 1) * (multiplier + 1); - sb.AppendFormat("\tDevice can erase a minimum of {0} blocks at a time", (int)result).AppendLine(); - - 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(); - } - 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)). + else + sb.AppendFormat("\tDevice uses unknown file format code {0} and file format group 1", csd.FileFormat). 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(); + switch(csd.ECC) + { + case 0: + sb.AppendLine("\tDevice currently uses no ECC"); - if(csd.WritesPartialBlocks) - sb.AppendLine("\tDevice allows writing partial blocks"); + break; + case 1: + sb.AppendLine("\tDevice currently uses BCH(542, 512) ECC by default"); - if(csd.ContentProtection) - sb.AppendLine("\tDevice supports content protection"); + break; + case 2: + sb.AppendFormat("\tDevice currently uses unknown ECC code {0}", csd.DefaultECC).AppendLine(); - if(!csd.Copy) - sb.AppendLine("\tDevice contents are original"); - - if(csd.PermanentWriteProtect) - sb.AppendLine("\tDevice is permanently 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(); - - 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; - } - - sb.AppendFormat("\tCSD CRC: 0x{0:X2}", csd.CRC).AppendLine(); - - return sb.ToString(); + break; } - public static string PrettifyCSD(uint[] response) => PrettifyCSD(DecodeCSD(response)); + sb.AppendFormat("\tCSD CRC: 0x{0:X2}", csd.CRC).AppendLine(); - public static string PrettifyCSD(byte[] response) => PrettifyCSD(DecodeCSD(response)); + return sb.ToString(); } + + public static string PrettifyCSD(uint[] response) => PrettifyCSD(DecodeCSD(response)); + + public static string PrettifyCSD(byte[] response) => PrettifyCSD(DecodeCSD(response)); } \ No newline at end of file diff --git a/MMC/ExtendedCSD.cs b/MMC/ExtendedCSD.cs index f51b560..facf333 100644 --- a/MMC/ExtendedCSD.cs +++ b/MMC/ExtendedCSD.cs @@ -35,1194 +35,1193 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; -namespace Aaru.Decoders.MMC +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"), + StructLayout(LayoutKind.Sequential, Pack = 1)] +public class ExtendedCSD { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"), - StructLayout(LayoutKind.Sequential, Pack = 1)] - public class ExtendedCSD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public byte[] Reserved0; + public byte CommandQueueModeEnable; + public byte SecureRemovalType; + public byte ProductStateAwarenessEnablement; + public uint MaxPreLoadingDataSize; + public uint PreLoadingDataSize; + public byte FFUStatus; + public ushort Reserved1; + public byte ModeOperationCodes; + public byte ModeConfig; + public byte BarrierControl; + public byte CacheFlushing; + public byte CacheControl; + public byte PowerOffNotification; + public byte PackedCommandFailureIndex; + public byte PackedCommandStatus; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] + public byte[] ContextConfiguration; + public ushort ExtendedPartitionsAttribute; + public ushort ExceptionEventsStatus; + public ushort ExceptionEventsControl; + public byte DyncapNeeded; + public byte Class6CommandsControl; + public byte InitializationTimeoutAfterEmulationChange; + public byte SectorSize; + public byte SectorSizeEmulation; + public byte NativeSectorSize; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] VendorSpecific; + public ushort Reserved2; + public byte SupportsProgramCxDInDDR; + public byte PeriodicWakeUp; + public byte PackageCaseTemperatureControl; + public byte ProductionStateAwareness; + public byte BadBlockManagementMode; + public byte Reserved3; + public uint EnhancedUserDataStartAddress; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] EnhancedUserDataAreaSize; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] GeneralPurposePartitionSize; + public byte PartitioningSetting; + public byte PartitionsAttribute; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] MaxEnhancedAreaSize; + public PartitioningSupport PartitioningSupport; + public byte HPIManagement; + public byte HWResetFunction; + public byte EnableBackgroundOperationsHandshake; + public byte ManuallyStartBackgroundOperations; + public byte StartSanitizeOperation; + public byte WriteReliabilityParameterRegister; + public byte WriteReliabilitySettingRegister; + public byte RPMBSize; + public byte FirmwareConfiguration; + public byte Reserved4; + public UserAreaWriteProtectionRegister UserAreaWriteProtectionRegister; + public byte Reserved5; + public BootAreaWriteProtectionRegister BootAreaWriteProtectionRegister; + public byte BootWriteProtectionStatus; + public HighCapacityEraseGroupDefinition HighCapacityEraseGroupDefinition; + public byte Reserved6; + public byte BootBusConditions; + public BootConfigProtection BootConfigProtection; + public byte PartitionConfiguration; + public byte Reserved7; + public byte ErasedMemoryContent; + public byte Reserved8; + public byte BusWidth; + public byte StrobeSupport; + public byte HighSpeedInterfaceTiming; + public byte Reserved9; + public byte PowerClass; + public byte Reserved10; + public byte CommandSetRevision; + public byte Reserved11; + public byte CommandSet; + public byte Revision; + public byte Reserved12; + public byte Structure; + public byte Reserved13; + public DeviceType DeviceType; + public DriverStrength DriverStrength; + public byte OutOfInterruptBusyTiming; + public byte PartitionSwitchingTime; + public byte PowerClass52_195; + public byte PowerClass26_195; + public byte PowerClass52; + public byte PowerClass26; + public byte Reserved14; + public byte MinimumReadPerformance26_4; + public byte MinimumWritePerformance26_4; + public byte MinimumReadPerformance26; + public byte MinimumWritePerformance26; + public byte MinimumReadPerformance52; + public byte MinimumWritePerformance52; + public SecureWriteProtectInformation SecureWriteProtectInformation; + public uint SectorCount; + public byte SleepNotificationTimeout; + public byte SleepAwakeTimeout; + public byte ProductionStateAwarenessTimeout; + public byte SleepCurrentVccQ; + public byte SleepCurrentVcc; + public byte HighCapacityWriteProtectGroupSize; + public byte ReliableWriteSectorCount; + public byte HighCapacityEraseTimeout; + public byte HighCapacityEraseUnitSize; + public byte AccessSize; + public byte BootPartitionSize; + public byte Reserved15; + public BootInformation BootInformation; + public byte SecureTRIMMultiplier; + public byte SecureEraseMultiplier; + public SecureFeatureSupport SecureFeatureSupport; + public byte TRIMMultiplier; + public byte Reserved16; + public byte MinimumReadPerformanceDDR52; + public byte MinimumWritePerformanceDDR52; + public byte PowerClassDDR200_130; + public byte PowerClassDDR200_195; + public byte PowerClassDDR52_195; + public byte PowerClassDDR52; + public CacheFlushingPolicy CacheFlushingPolicy; + public byte InitializationTimeAfterPartition; + public uint CorrectlyProgrammedSectors; + public byte BackgroundOperationsStatus; + public byte PowerOffNotificationTimeout; + public byte GenericCMD6Timeout; + public uint CacheSize; + public byte PowerClassDDR200; + public ulong FirmwareVersion; + public ushort DeviceVersion; + public byte OptimalTrimUnitSize; + public byte OptimalWriteSize; + public byte OptimalReadSize; + public byte PreEOLInformation; + public byte DeviceLifeEstimationTypeA; + public byte DeviceLifeEstimationTypeB; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] VendorHealthReport; + public uint NumberOfFWSectorsCorrectlyProgrammed; + public byte Reserved17; + public byte CMDQueuingDepth; + public CMDQueuingSupport CMDQueuingSupport; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)] + public byte[] Reserved18; + public byte BarrierSupport; + public uint FFUArgument; + public byte OperationCodesTimeout; + public FFUFeatures FFUFeatures; + public SupportedModes SupportedModes; + public ExtendedPartitionsSupport ExtendedPartitionsSupport; + public byte LargeUnitSize; + public byte ContextManagementCaps; + public byte TagResourcesSize; + public byte TagUnitSize; + public DataTagSupport DataTagSupport; + public byte MaxPackedWriteCommands; + public byte MaxPackedReadCommands; + public BackgroundOperationsSupport BackgroundOperationsSupport; + public HPIFeatures HPIFeatures; + public DeviceSupportedCommandSets SupportedCommandSets; + public byte ExtendedSecurityCommandsError; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] Reserved19; +} + +[Flags] +public enum DeviceSupportedCommandSets : byte +{ + Standard = 1 << 0 +} + +[Flags] +public enum HPIFeatures : byte +{ + Supported = 1 << 0, CMD12 = 1 << 1 +} + +[Flags] +public enum BackgroundOperationsSupport : byte +{ + Supported = 1 << 0 +} + +[Flags] +public enum DataTagSupport : byte +{ + Supported = 1 << 0 +} + +[Flags] +public enum ExtendedPartitionsSupport : byte +{ + SystemCode = 1 << 0, NonPersistent = 1 << 1 +} + +[Flags] +public enum SupportedModes : byte +{ + FFU = 1 << 0, VendorSpecific = 1 << 1 +} + +[Flags] +public enum FFUFeatures : byte +{ + SupportedModeOperationCodes = 1 << 0 +} + +[Flags] +public enum CMDQueuingSupport : byte +{ + Supported = 1 << 0 +} + +[Flags] +public enum CacheFlushingPolicy : byte +{ + FIFO = 1 << 0 +} + +[Flags] +public enum SecureFeatureSupport : byte +{ + Purge = 1 << 0, Defective = 1 << 2, Trim = 1 << 4, + Sanitize = 1 << 6 +} + +[Flags] +public enum BootInformation : byte +{ + Alternative = 1 << 0, DDR = 1 << 1, HighSpeed = 1 << 2 +} + +[Flags] +public enum SecureWriteProtectInformation : byte +{ + Supported = 1 << 0, Enabled = 1 << 1 +} + +[Flags] +public enum DriverStrength : byte +{ + Type0 = 1 << 0, Type1 = 1 << 1, Type2 = 1 << 2, + Type3 = 1 << 3, Type4 = 1 << 4 +} + +[Flags] +public enum DeviceType : byte +{ + HS_26 = 1 << 0, HS_52 = 1 << 1, HS_DDR_52 = 1 << 2, + HS_DDR_52_LV = 1 << 3, HS200_18 = 1 << 4, HS200_12 = 1 << 5, + HS400_18 = 1 << 6, HS400_12 = 1 << 7 +} + +[Flags] +public enum BootConfigProtection : byte +{ + PowerCycle = 1 << 0, Permanent = 1 << 4 +} + +[Flags] +public enum HighCapacityEraseGroupDefinition : byte +{ + Enabled = 1 << 0 +} + +[Flags] +public enum BootAreaWriteProtectionRegister : byte +{ + PowerOn = 1 << 0, PowerOnArea2 = 1 << 1, Permanent = 1 << 2, + PermanentArea2 = 1 << 3, PermanentDisable = 1 << 4, PowerOnDisable = 1 << 6, + Selected = 1 << 7 +} + +[Flags] +public enum UserAreaWriteProtectionRegister : byte +{ + ApplyPowerOn = 1 << 0, ApplyPermanent = 1 << 2, DisablePowerOn = 1 << 3, + DisablePermanent = 1 << 4, DisableWriteProtect = 1 << 6, DisablePassword = 1 << 7 +} + +[Flags] +public enum PartitioningSupport : byte +{ + Supported = 1 << 0, Enhanced = 1 << 1, Extended = 1 << 2 +} + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Decoders +{ + public static ExtendedCSD DecodeExtendedCSD(byte[] response) { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] - public byte[] Reserved0; - public byte CommandQueueModeEnable; - public byte SecureRemovalType; - public byte ProductStateAwarenessEnablement; - public uint MaxPreLoadingDataSize; - public uint PreLoadingDataSize; - public byte FFUStatus; - public ushort Reserved1; - public byte ModeOperationCodes; - public byte ModeConfig; - public byte BarrierControl; - public byte CacheFlushing; - public byte CacheControl; - public byte PowerOffNotification; - public byte PackedCommandFailureIndex; - public byte PackedCommandStatus; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] - public byte[] ContextConfiguration; - public ushort ExtendedPartitionsAttribute; - public ushort ExceptionEventsStatus; - public ushort ExceptionEventsControl; - public byte DyncapNeeded; - public byte Class6CommandsControl; - public byte InitializationTimeoutAfterEmulationChange; - public byte SectorSize; - public byte SectorSizeEmulation; - public byte NativeSectorSize; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public byte[] VendorSpecific; - public ushort Reserved2; - public byte SupportsProgramCxDInDDR; - public byte PeriodicWakeUp; - public byte PackageCaseTemperatureControl; - public byte ProductionStateAwareness; - public byte BadBlockManagementMode; - public byte Reserved3; - public uint EnhancedUserDataStartAddress; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] EnhancedUserDataAreaSize; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] GeneralPurposePartitionSize; - public byte PartitioningSetting; - public byte PartitionsAttribute; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] MaxEnhancedAreaSize; - public PartitioningSupport PartitioningSupport; - public byte HPIManagement; - public byte HWResetFunction; - public byte EnableBackgroundOperationsHandshake; - public byte ManuallyStartBackgroundOperations; - public byte StartSanitizeOperation; - public byte WriteReliabilityParameterRegister; - public byte WriteReliabilitySettingRegister; - public byte RPMBSize; - public byte FirmwareConfiguration; - public byte Reserved4; - public UserAreaWriteProtectionRegister UserAreaWriteProtectionRegister; - public byte Reserved5; - public BootAreaWriteProtectionRegister BootAreaWriteProtectionRegister; - public byte BootWriteProtectionStatus; - public HighCapacityEraseGroupDefinition HighCapacityEraseGroupDefinition; - public byte Reserved6; - public byte BootBusConditions; - public BootConfigProtection BootConfigProtection; - public byte PartitionConfiguration; - public byte Reserved7; - public byte ErasedMemoryContent; - public byte Reserved8; - public byte BusWidth; - public byte StrobeSupport; - public byte HighSpeedInterfaceTiming; - public byte Reserved9; - public byte PowerClass; - public byte Reserved10; - public byte CommandSetRevision; - public byte Reserved11; - public byte CommandSet; - public byte Revision; - public byte Reserved12; - public byte Structure; - public byte Reserved13; - public DeviceType DeviceType; - public DriverStrength DriverStrength; - public byte OutOfInterruptBusyTiming; - public byte PartitionSwitchingTime; - public byte PowerClass52_195; - public byte PowerClass26_195; - public byte PowerClass52; - public byte PowerClass26; - public byte Reserved14; - public byte MinimumReadPerformance26_4; - public byte MinimumWritePerformance26_4; - public byte MinimumReadPerformance26; - public byte MinimumWritePerformance26; - public byte MinimumReadPerformance52; - public byte MinimumWritePerformance52; - public SecureWriteProtectInformation SecureWriteProtectInformation; - public uint SectorCount; - public byte SleepNotificationTimeout; - public byte SleepAwakeTimeout; - public byte ProductionStateAwarenessTimeout; - public byte SleepCurrentVccQ; - public byte SleepCurrentVcc; - public byte HighCapacityWriteProtectGroupSize; - public byte ReliableWriteSectorCount; - public byte HighCapacityEraseTimeout; - public byte HighCapacityEraseUnitSize; - public byte AccessSize; - public byte BootPartitionSize; - public byte Reserved15; - public BootInformation BootInformation; - public byte SecureTRIMMultiplier; - public byte SecureEraseMultiplier; - public SecureFeatureSupport SecureFeatureSupport; - public byte TRIMMultiplier; - public byte Reserved16; - public byte MinimumReadPerformanceDDR52; - public byte MinimumWritePerformanceDDR52; - public byte PowerClassDDR200_130; - public byte PowerClassDDR200_195; - public byte PowerClassDDR52_195; - public byte PowerClassDDR52; - public CacheFlushingPolicy CacheFlushingPolicy; - public byte InitializationTimeAfterPartition; - public uint CorrectlyProgrammedSectors; - public byte BackgroundOperationsStatus; - public byte PowerOffNotificationTimeout; - public byte GenericCMD6Timeout; - public uint CacheSize; - public byte PowerClassDDR200; - public ulong FirmwareVersion; - public ushort DeviceVersion; - public byte OptimalTrimUnitSize; - public byte OptimalWriteSize; - public byte OptimalReadSize; - public byte PreEOLInformation; - public byte DeviceLifeEstimationTypeA; - public byte DeviceLifeEstimationTypeB; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] VendorHealthReport; - public uint NumberOfFWSectorsCorrectlyProgrammed; - public byte Reserved17; - public byte CMDQueuingDepth; - public CMDQueuingSupport CMDQueuingSupport; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 177)] - public byte[] Reserved18; - public byte BarrierSupport; - public uint FFUArgument; - public byte OperationCodesTimeout; - public FFUFeatures FFUFeatures; - public SupportedModes SupportedModes; - public ExtendedPartitionsSupport ExtendedPartitionsSupport; - public byte LargeUnitSize; - public byte ContextManagementCaps; - public byte TagResourcesSize; - public byte TagUnitSize; - public DataTagSupport DataTagSupport; - public byte MaxPackedWriteCommands; - public byte MaxPackedReadCommands; - public BackgroundOperationsSupport BackgroundOperationsSupport; - public HPIFeatures HPIFeatures; - public DeviceSupportedCommandSets SupportedCommandSets; - public byte ExtendedSecurityCommandsError; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] Reserved19; + if(response?.Length != 512) + return null; + + var handle = GCHandle.Alloc(response, GCHandleType.Pinned); + var csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD)); + handle.Free(); + + return csd; } - [Flags] - public enum DeviceSupportedCommandSets : byte + public static string PrettifyExtendedCSD(ExtendedCSD csd) { - Standard = 1 << 0 - } + if(csd == null) + return null; - [Flags] - public enum HPIFeatures : byte - { - Supported = 1 << 0, CMD12 = 1 << 1 - } + var sb = new StringBuilder(); + sb.AppendLine("MultiMediaCard Extended Device Specific Data Register:"); - [Flags] - public enum BackgroundOperationsSupport : byte - { - Supported = 1 << 0 - } + double unit; - [Flags] - public enum DataTagSupport : byte - { - Supported = 1 << 0 - } - - [Flags] - public enum ExtendedPartitionsSupport : byte - { - SystemCode = 1 << 0, NonPersistent = 1 << 1 - } - - [Flags] - public enum SupportedModes : byte - { - FFU = 1 << 0, VendorSpecific = 1 << 1 - } - - [Flags] - public enum FFUFeatures : byte - { - SupportedModeOperationCodes = 1 << 0 - } - - [Flags] - public enum CMDQueuingSupport : byte - { - Supported = 1 << 0 - } - - [Flags] - public enum CacheFlushingPolicy : byte - { - FIFO = 1 << 0 - } - - [Flags] - public enum SecureFeatureSupport : byte - { - Purge = 1 << 0, Defective = 1 << 2, Trim = 1 << 4, - Sanitize = 1 << 6 - } - - [Flags] - public enum BootInformation : byte - { - Alternative = 1 << 0, DDR = 1 << 1, HighSpeed = 1 << 2 - } - - [Flags] - public enum SecureWriteProtectInformation : byte - { - Supported = 1 << 0, Enabled = 1 << 1 - } - - [Flags] - public enum DriverStrength : byte - { - Type0 = 1 << 0, Type1 = 1 << 1, Type2 = 1 << 2, - Type3 = 1 << 3, Type4 = 1 << 4 - } - - [Flags] - public enum DeviceType : byte - { - HS_26 = 1 << 0, HS_52 = 1 << 1, HS_DDR_52 = 1 << 2, - HS_DDR_52_LV = 1 << 3, HS200_18 = 1 << 4, HS200_12 = 1 << 5, - HS400_18 = 1 << 6, HS400_12 = 1 << 7 - } - - [Flags] - public enum BootConfigProtection : byte - { - PowerCycle = 1 << 0, Permanent = 1 << 4 - } - - [Flags] - public enum HighCapacityEraseGroupDefinition : byte - { - Enabled = 1 << 0 - } - - [Flags] - public enum BootAreaWriteProtectionRegister : byte - { - PowerOn = 1 << 0, PowerOnArea2 = 1 << 1, Permanent = 1 << 2, - PermanentArea2 = 1 << 3, PermanentDisable = 1 << 4, PowerOnDisable = 1 << 6, - Selected = 1 << 7 - } - - [Flags] - public enum UserAreaWriteProtectionRegister : byte - { - ApplyPowerOn = 1 << 0, ApplyPermanent = 1 << 2, DisablePowerOn = 1 << 3, - DisablePermanent = 1 << 4, DisableWriteProtect = 1 << 6, DisablePassword = 1 << 7 - } - - [Flags] - public enum PartitioningSupport : byte - { - Supported = 1 << 0, Enhanced = 1 << 1, Extended = 1 << 2 - } - - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Decoders - { - public static ExtendedCSD DecodeExtendedCSD(byte[] response) - { - if(response?.Length != 512) - return null; - - var handle = GCHandle.Alloc(response, GCHandleType.Pinned); - var csd = (ExtendedCSD)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(ExtendedCSD)); - handle.Free(); - - return csd; - } - - public static string PrettifyExtendedCSD(ExtendedCSD csd) - { - if(csd == null) - return null; - - var sb = new StringBuilder(); - sb.AppendLine("MultiMediaCard Extended Device Specific Data Register:"); - - double unit; - - if(csd.ExtendedSecurityCommandsError != 0) - sb.AppendFormat("\tLast extended security error was {0}", csd.ExtendedSecurityCommandsError). - AppendLine(); - - if(csd.SupportedCommandSets.HasFlag(DeviceSupportedCommandSets.Standard)) - sb.AppendLine("\tDevice supports standard MMC command set"); - - if(((int)csd.SupportedCommandSets & 0xFE) != 0) - sb.AppendFormat("\tDevice supports unknown command sets 0x{0:X2}", (int)csd.SupportedCommandSets); - - if(csd.HPIFeatures.HasFlag(HPIFeatures.Supported)) - sb.AppendLine(csd.HPIFeatures.HasFlag(HPIFeatures.CMD12) ? "\tDevice implements HPI using CMD12" - : "\tDevice implements HPI using CMD13"); - - if(csd.BackgroundOperationsSupport.HasFlag(BackgroundOperationsSupport.Supported)) - sb.AppendLine("\tDevice supports background operations"); - - sb.AppendFormat("\tDevice supports a maximum of {0} packed reads and {1} packed writes", - csd.MaxPackedReadCommands, csd.MaxPackedWriteCommands).AppendLine(); - - if(csd.DataTagSupport.HasFlag(DataTagSupport.Supported)) - { - sb.AppendLine("\tDevice supports Data Tag"); - sb.AppendFormat("\tTags must be in units of {0} sectors", Math.Pow(2, csd.TagUnitSize)).AppendLine(); - sb.AppendFormat("\tTag resources size is {0}.", csd.TagResourcesSize).AppendLine(); - } - - if(csd.ContextManagementCaps != 0) - { - sb.AppendFormat("\tMax context ID is {0}.", csd.ContextManagementCaps & 0xF).AppendLine(); - - sb.AppendFormat("\tLarge unit maximum multiplier is {0}.", - ((csd.ContextManagementCaps & 0x70) >> 4) + 1).AppendLine(); - } - - sb.AppendFormat("\tLarge unit size is {0} MiB", csd.LargeUnitSize + 1).AppendLine(); - - if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.NonPersistent)) - sb.AppendLine("\tDevice supports non-persistent extended partitions"); - - if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.SystemCode)) - sb.AppendLine("\tDevice supports system code extended partitions"); - - if(csd.SupportedModes.HasFlag(SupportedModes.FFU)) - { - sb.AppendLine("\tDevice supports FFU"); - - if(csd.FFUFeatures.HasFlag(FFUFeatures.SupportedModeOperationCodes)) - { - // todo public byte ModeOperationCodes - - if(csd.OperationCodesTimeout > 0) - { - unit = Math.Pow(2, csd.OperationCodesTimeout) * 100; - - if(unit > 1000000) - sb. - AppendFormat("\t\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}s", - unit / 1000000).AppendLine(); - else if(unit > 1000) - sb. - AppendFormat("\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}ms", - unit / 1000).AppendLine(); - else - sb. - AppendFormat("\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}µs", - unit).AppendLine(); - } - } - } - - if(csd.SupportedModes.HasFlag(SupportedModes.VendorSpecific)) - sb.AppendLine("\tDevice supports Vendor Specific Mode"); - - if(csd.BarrierSupport == 0x01) - { - sb.AppendLine("\tDevice supports the barrier command"); - } - - if(csd.CMDQueuingSupport.HasFlag(CMDQueuingSupport.Supported)) - 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). + if(csd.ExtendedSecurityCommandsError != 0) + sb.AppendFormat("\tLast extended security error was {0}", csd.ExtendedSecurityCommandsError). AppendLine(); - switch(csd.DeviceLifeEstimationTypeB) - { - case 1: - sb.AppendLine("\tDevice used between 0% and 10% of its estimated life time"); + if(csd.SupportedCommandSets.HasFlag(DeviceSupportedCommandSets.Standard)) + sb.AppendLine("\tDevice supports standard MMC command set"); - break; - case 2: - sb.AppendLine("\tDevice used between 10% and 20% of its estimated life time"); + if(((int)csd.SupportedCommandSets & 0xFE) != 0) + sb.AppendFormat("\tDevice supports unknown command sets 0x{0:X2}", (int)csd.SupportedCommandSets); - break; - case 3: - sb.AppendLine("\tDevice used between 20% and 30% of its estimated life time"); + if(csd.HPIFeatures.HasFlag(HPIFeatures.Supported)) + sb.AppendLine(csd.HPIFeatures.HasFlag(HPIFeatures.CMD12) ? "\tDevice implements HPI using CMD12" + : "\tDevice implements HPI using CMD13"); - break; - case 4: - sb.AppendLine("\tDevice used between 30% and 40% of its estimated life time"); + if(csd.BackgroundOperationsSupport.HasFlag(BackgroundOperationsSupport.Supported)) + sb.AppendLine("\tDevice supports background operations"); - break; - case 5: - sb.AppendLine("\tDevice used between 40% and 50% of its estimated life time"); + sb.AppendFormat("\tDevice supports a maximum of {0} packed reads and {1} packed writes", + csd.MaxPackedReadCommands, csd.MaxPackedWriteCommands).AppendLine(); - 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; - } - - switch(csd.DeviceLifeEstimationTypeA) - { - 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; - } - - switch(csd.PreEOLInformation) - { - 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; - } - - if(csd.OptimalReadSize == 0) - sb.AppendLine("\tDevice does not report an optimal read size"); - else - sb.AppendFormat("\tOptimal read size is {0} KiB", 4 * csd.OptimalReadSize).AppendLine(); - - if(csd.OptimalWriteSize == 0) - sb.AppendLine("\tDevice does not report an optimal write size"); - else - sb.AppendFormat("\tOptimal write size is {0} KiB", 4 * csd.OptimalWriteSize).AppendLine(); - - if(csd.OptimalTrimUnitSize == 0) - sb.AppendLine("\tDevice does not report an optimal trim size"); - else - sb.AppendFormat("\tOptimal trim size is {0} KiB", 4 * Math.Pow(2, csd.OptimalTrimUnitSize - 1)). - AppendLine(); - - 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 / 8).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", - 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; - } - - sb.AppendFormat("\tLast WRITE MULTIPLE command correctly programmed {0} sectors", - csd.CorrectlyProgrammedSectors).AppendLine(); - - if(csd.InitializationTimeAfterPartition > 0) - sb.AppendFormat("\tDevice takes a maximum of {0} ms for initialization after partition", - csd.InitializationTimeAfterPartition * 100).AppendLine(); - - if(csd.CacheFlushingPolicy.HasFlag(CacheFlushingPolicy.FIFO)) - sb.AppendLine("\tDevice uses a FIFO policy for cache flushing"); - - if(csd.TRIMMultiplier > 0) - sb.AppendFormat("\tDevice takes a maximum of {0} ms for trimming a single erase group", - csd.TRIMMultiplier * 300).AppendLine(); - - if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Sanitize)) - sb.AppendLine("\tDevice supports the sanitize operation"); - - if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Trim)) - sb.AppendLine("\tDevice supports supports the secure and insecure trim operations"); - - if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Defective)) - sb.AppendLine("\tDevice supports automatic erase on retired defective blocks"); - - if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Purge)) - 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.HasFlag(BootInformation.HighSpeed)) - sb.AppendLine("\tDevice supports high speed timing on boot"); - - if(csd.BootInformation.HasFlag(BootInformation.DDR)) - sb.AppendLine("\tDevice supports dual data rate on boot"); - - if(csd.BootInformation.HasFlag(BootInformation.Alternative)) - 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", - 512 * Math.Pow(2, (csd.AccessSize & 0x0F) - 1) / 1024.0).AppendLine(); - - if(csd.HighCapacityEraseUnitSize > 0) - sb.AppendFormat("\tDevice erase groups are {0} KiB", csd.HighCapacityEraseUnitSize * 512).AppendLine(); - - if(csd.HighCapacityEraseTimeout > 0) - sb.AppendFormat("\tDevice takes a maximum of {0} ms for erasing a single erase group", - csd.HighCapacityEraseTimeout * 300).AppendLine(); - - if(csd.HighCapacityWriteProtectGroupSize > 0) - sb.AppendFormat("\tDevice smallest write protect group is made of {0} erase groups", - csd.HighCapacityWriteProtectGroupSize).AppendLine(); - - 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(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(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(); - else if(unit > 1000) - 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(); - } - - 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(); - else if(unit > 1000) - sb.AppendFormat("\tDevice takes a maximum of {0} μs to transition between sleep and standby states", - unit / 1000).AppendLine(); - else - sb.AppendFormat("\tDevice takes a maximum of {0} ns to transition between sleep and standby states", - unit).AppendLine(); - } - - 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(); - 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 has {0} sectors", csd.SectorCount).AppendLine(); - - if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Supported)) - { - sb.AppendLine("\tDevice supports secure write protection"); - - if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Enabled)) - sb.AppendLine("\tDevice has secure write protection enabled"); - } - - unit = csd.MinimumReadPerformance26 * 300; - - 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(); - - unit = csd.MinimumReadPerformance26_4 * 300; - - if(csd.MinimumReadPerformance26_4 == 0) - sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode"); - else - sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz 4-bit mode", - unit / 1000).AppendLine(); - - unit = csd.MinimumReadPerformance52 * 300; - - 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(); - - unit = csd.MinimumReadPerformanceDDR52 * 600; - - 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(); - - unit = csd.MinimumWritePerformance26 * 300; - - 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(); - - unit = csd.MinimumWritePerformance26_4 * 300; - - if(csd.MinimumWritePerformance26_4 == 0) - sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode"); - else - sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz 4-bit mode", - unit / 1000).AppendLine(); - - unit = csd.MinimumWritePerformance52 * 300; - - 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(); - - unit = csd.MinimumWritePerformanceDDR52 * 600; - - 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(); - - if(csd.PartitionSwitchingTime > 0) - sb.AppendFormat("\tDevice can take a maximum of {0} ms when switching partitions", - csd.PartitionSwitchingTime * 10).AppendLine(); - - if(csd.OutOfInterruptBusyTiming > 0) - sb.AppendFormat("\tDevice can take a maximum of {0} ms when releasing from an interrupt", - csd.OutOfInterruptBusyTiming * 10).AppendLine(); - - if(csd.DriverStrength.HasFlag(DriverStrength.Type0)) - sb.AppendLine("\tDevice supports I/O driver strength type 0."); - - if(csd.DriverStrength.HasFlag(DriverStrength.Type1)) - sb.AppendLine("\tDevice supports I/O driver strength type 1."); - - if(csd.DriverStrength.HasFlag(DriverStrength.Type2)) - sb.AppendLine("\tDevice supports I/O driver strength type 2."); - - if(csd.DriverStrength.HasFlag(DriverStrength.Type3)) - sb.AppendLine("\tDevice supports I/O driver strength type 3."); - - if(csd.DriverStrength.HasFlag(DriverStrength.Type4)) - sb.AppendLine("\tDevice supports I/O driver strength type 4."); - - if(csd.DeviceType.HasFlag(DeviceType.HS_26)) - sb.AppendLine("\tDevice supports 26 Mhz mode"); - - if(csd.DeviceType.HasFlag(DeviceType.HS_52)) - sb.AppendLine("\tDevice supports 52 Mhz mode"); - - if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52)) - sb.AppendLine("\tDevice supports DDR 52 Mhz mode at 1.8V or 3V"); - - if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52_LV)) - sb.AppendLine("\tDevice supports DDR 52 Mhz mode 1.2V"); - - if(csd.DeviceType.HasFlag(DeviceType.HS200_18)) - sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.8V"); - - if(csd.DeviceType.HasFlag(DeviceType.HS200_12)) - sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.2V"); - - if(csd.DeviceType.HasFlag(DeviceType.HS400_18)) - sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.8V"); - - if(csd.DeviceType.HasFlag(DeviceType.HS400_12)) - 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(); - - switch(csd.CommandSet) - { - case 0: - sb.AppendLine("\tDevice follows compatibility MMC command set."); - - break; - case 1: - switch(csd.CommandSetRevision) - { - case 0: - sb.AppendLine("\tDevice follows standard MMC command set v4.0."); - - break; - default: - sb.AppendFormat("\tDevice follows standard MMC command set with unknown version code {0}.", - csd.CommandSetRevision).AppendLine(); - - break; - } - - break; - default: - sb.AppendFormat("\tDevice follows unknown MMC command set code {0} with revision code {1}.", - csd.CommandSet, csd.CommandSetRevision).AppendLine(); - - break; - } - - switch(csd.HighSpeedInterfaceTiming & 0x0F) - { - case 0: break; - case 1: - sb.AppendLine("\tDevice is in High Speed mode."); - - break; - case 2: - sb.AppendLine("\tDevice is in HS-200 mode."); - - break; - case 3: - sb.AppendLine("\tDevice is in HS-400 mode."); - - break; - default: - sb.AppendFormat("\tDevice has unknown timing mode {0}.", csd.HighSpeedInterfaceTiming & 0x0F). - AppendLine(); - - break; - } - - sb.AppendFormat("\tSelected driver strength is type {0}.", (csd.HighSpeedInterfaceTiming & 0xF0) >> 4). - 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"); - } - - switch(csd.BusWidth & 0x0F) - { - 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; - } - - switch(csd.ErasedMemoryContent) - { - case 0: - case 1: - sb.AppendFormat("\tErased memory range shall be '{0}'.", csd.ErasedMemoryContent).AppendLine(); - - break; - default: - sb.AppendFormat("\tUnknown erased memory content code {0}", csd.ErasedMemoryContent).AppendLine(); - - break; - } - - if((csd.PartitionConfiguration & 0x40) == 0x40) - 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; - } - - switch(csd.PartitionConfiguration & 0x07) - { - 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.BootConfigProtection.HasFlag(BootConfigProtection.Permanent)) - sb.AppendLine("\tChange of the boot configuration register bits is permanently disabled."); - else if(csd.BootConfigProtection.HasFlag(BootConfigProtection.PowerCycle)) - sb.AppendLine("\tChange of the boot configuration register bits is disabled until the next power cycle."); - - switch(csd.BootBusConditions & 0x03) - { - case 0: - sb.AppendLine("\tDevice will boot up in x1 SDR or x4 DDR bus width."); - - break; - case 1: - sb.AppendLine("\tDevice will boot up in x4 SDR or DDR bus width."); - - break; - case 2: - sb.AppendLine("\tDevice will boot up in x8 SDR or DDR bus width."); - - break; - case 3: - sb.AppendLine("\tUnknown boot condition for bus width with code 3."); - - break; - } - - sb.AppendLine((csd.BootBusConditions & 4) == 4 - ? "\tDevice will retain boot conditions after boot operation." - : "\tDevice will reset boot conditions to compatibility mode after boot operation."); - - switch((csd.BootBusConditions & 0x24) >> 3) - { - case 0: - sb.AppendLine("\tDevice will use single data rate with compatible timings in boot operation."); - - break; - case 1: - sb.AppendLine("\tDevice will use single data rate with high speed timings in boot operation."); - - break; - case 2: - sb.AppendLine("\tDevice will use dual data rate in boot operation."); - - break; - case 3: - sb.AppendLine("\tDevice will use unknown boot mode with code 3."); - - break; - } - - if(csd.HighCapacityEraseGroupDefinition.HasFlag(HighCapacityEraseGroupDefinition.Enabled)) - sb.AppendLine("\tDevice will use high capacity erase unit size, timeout and write protect group size definitions."); - - switch(csd.BootWriteProtectionStatus & 0x03) - { - case 0: - sb.AppendLine("\tBoot area 1 is not protected"); - - break; - case 1: - sb.AppendLine("\tBoot area 1 is power on protected"); - - break; - case 2: - sb.AppendLine("\tBoot area 1 is permanently protected"); - - break; - } - - switch((csd.BootWriteProtectionStatus & 0x0C) >> 2) - { - case 0: - sb.AppendLine("\tBoot area 2 is not protected"); - - break; - case 1: - sb.AppendLine("\tBoot area 2 is power on protected"); - - break; - case 2: - sb.AppendLine("\tBoot area 2 is permanently protected"); - - break; - } - - if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Permanent)) - { - if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected)) - { - sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister. - PermanentArea2) - ? "\tBoot area 2 is permanently write protected." - : "\tBoot area 1 is permanently write protected."); - } - else - sb.AppendLine("\tBoth boot areas are permanently write protected."); - } - else if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOn)) - { - if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected)) - { - sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister. - PowerOnArea2) - ? "\tBoot area 2 is write protected until next power cycle." - : "\tBoot area 1 is write protected until next power cycle."); - } - else - sb.AppendLine("\tBoth boot areas are write protected until next power cycle."); - } - - if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PermanentDisable)) - sb.AppendLine("\tPermanent write protection of boot areas is disabled."); - - if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnDisable)) - sb.AppendLine("\tPower cycled write protection of boot areas is disabled."); - - if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePassword)) - sb.AppendLine("\tUse of password protection features is permanently disabled."); - - if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisableWriteProtect)) - sb.AppendLine("\tUse of permanent write protection is disabled."); - - if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePermanent)) - sb.AppendLine("\tPermanent write protection is disabled."); - - if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePowerOn)) - sb.AppendLine("\tPower cycled write protection is disabled."); - - if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPermanent)) - sb.AppendLine("\tPermanent write protection will be applied to selected group."); - - if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPowerOn)) - sb.AppendLine("\tPower cycled write protection will be applied to selected group."); - - 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(); - - if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Supported)) - { - sb.AppendLine("\tDevice supports partitioning features"); - - if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Enhanced)) - sb.AppendLine("\tDevice can have enhanced technological features in partitions and user data area"); - - if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Extended)) - sb.AppendLine("\tDevice can have extended partitions attribute."); - } - - 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; - } - - switch(csd.SectorSizeEmulation) - { - 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(); - - break; - } - - switch(csd.SectorSize) - { - 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.CommandQueueModeEnable & 0x01) == 0x01) - sb.AppendLine("\tDevice has enabled command queuing"); - - return sb.ToString(); + if(csd.DataTagSupport.HasFlag(DataTagSupport.Supported)) + { + sb.AppendLine("\tDevice supports Data Tag"); + sb.AppendFormat("\tTags must be in units of {0} sectors", Math.Pow(2, csd.TagUnitSize)).AppendLine(); + sb.AppendFormat("\tTag resources size is {0}.", csd.TagResourcesSize).AppendLine(); } - public static string PrettifyExtendedCSD(byte[] response) => PrettifyExtendedCSD(DecodeExtendedCSD(response)); + if(csd.ContextManagementCaps != 0) + { + sb.AppendFormat("\tMax context ID is {0}.", csd.ContextManagementCaps & 0xF).AppendLine(); + + sb.AppendFormat("\tLarge unit maximum multiplier is {0}.", + ((csd.ContextManagementCaps & 0x70) >> 4) + 1).AppendLine(); + } + + sb.AppendFormat("\tLarge unit size is {0} MiB", csd.LargeUnitSize + 1).AppendLine(); + + if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.NonPersistent)) + sb.AppendLine("\tDevice supports non-persistent extended partitions"); + + if(csd.ExtendedPartitionsSupport.HasFlag(ExtendedPartitionsSupport.SystemCode)) + sb.AppendLine("\tDevice supports system code extended partitions"); + + if(csd.SupportedModes.HasFlag(SupportedModes.FFU)) + { + sb.AppendLine("\tDevice supports FFU"); + + if(csd.FFUFeatures.HasFlag(FFUFeatures.SupportedModeOperationCodes)) + { + // todo public byte ModeOperationCodes + + if(csd.OperationCodesTimeout > 0) + { + unit = Math.Pow(2, csd.OperationCodesTimeout) * 100; + + if(unit > 1000000) + sb. + AppendFormat("\t\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}s", + unit / 1000000).AppendLine(); + else if(unit > 1000) + sb. + AppendFormat("\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}ms", + unit / 1000).AppendLine(); + else + sb. + AppendFormat("\tMaximum timeout for switch command when setting a value to the mode operation codes field is {0:D2}µs", + unit).AppendLine(); + } + } + } + + if(csd.SupportedModes.HasFlag(SupportedModes.VendorSpecific)) + sb.AppendLine("\tDevice supports Vendor Specific Mode"); + + if(csd.BarrierSupport == 0x01) + { + sb.AppendLine("\tDevice supports the barrier command"); + } + + if(csd.CMDQueuingSupport.HasFlag(CMDQueuingSupport.Supported)) + 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(); + + 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; + } + + switch(csd.DeviceLifeEstimationTypeA) + { + 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; + } + + switch(csd.PreEOLInformation) + { + 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; + } + + if(csd.OptimalReadSize == 0) + sb.AppendLine("\tDevice does not report an optimal read size"); + else + sb.AppendFormat("\tOptimal read size is {0} KiB", 4 * csd.OptimalReadSize).AppendLine(); + + if(csd.OptimalWriteSize == 0) + sb.AppendLine("\tDevice does not report an optimal write size"); + else + sb.AppendFormat("\tOptimal write size is {0} KiB", 4 * csd.OptimalWriteSize).AppendLine(); + + if(csd.OptimalTrimUnitSize == 0) + sb.AppendLine("\tDevice does not report an optimal trim size"); + else + sb.AppendFormat("\tOptimal trim size is {0} KiB", 4 * Math.Pow(2, csd.OptimalTrimUnitSize - 1)). + AppendLine(); + + 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 / 8).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", + 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; + } + + sb.AppendFormat("\tLast WRITE MULTIPLE command correctly programmed {0} sectors", + csd.CorrectlyProgrammedSectors).AppendLine(); + + if(csd.InitializationTimeAfterPartition > 0) + sb.AppendFormat("\tDevice takes a maximum of {0} ms for initialization after partition", + csd.InitializationTimeAfterPartition * 100).AppendLine(); + + if(csd.CacheFlushingPolicy.HasFlag(CacheFlushingPolicy.FIFO)) + sb.AppendLine("\tDevice uses a FIFO policy for cache flushing"); + + if(csd.TRIMMultiplier > 0) + sb.AppendFormat("\tDevice takes a maximum of {0} ms for trimming a single erase group", + csd.TRIMMultiplier * 300).AppendLine(); + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Sanitize)) + sb.AppendLine("\tDevice supports the sanitize operation"); + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Trim)) + sb.AppendLine("\tDevice supports supports the secure and insecure trim operations"); + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Defective)) + sb.AppendLine("\tDevice supports automatic erase on retired defective blocks"); + + if(csd.SecureFeatureSupport.HasFlag(SecureFeatureSupport.Purge)) + 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.HasFlag(BootInformation.HighSpeed)) + sb.AppendLine("\tDevice supports high speed timing on boot"); + + if(csd.BootInformation.HasFlag(BootInformation.DDR)) + sb.AppendLine("\tDevice supports dual data rate on boot"); + + if(csd.BootInformation.HasFlag(BootInformation.Alternative)) + 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", + 512 * Math.Pow(2, (csd.AccessSize & 0x0F) - 1) / 1024.0).AppendLine(); + + if(csd.HighCapacityEraseUnitSize > 0) + sb.AppendFormat("\tDevice erase groups are {0} KiB", csd.HighCapacityEraseUnitSize * 512).AppendLine(); + + if(csd.HighCapacityEraseTimeout > 0) + sb.AppendFormat("\tDevice takes a maximum of {0} ms for erasing a single erase group", + csd.HighCapacityEraseTimeout * 300).AppendLine(); + + if(csd.HighCapacityWriteProtectGroupSize > 0) + sb.AppendFormat("\tDevice smallest write protect group is made of {0} erase groups", + csd.HighCapacityWriteProtectGroupSize).AppendLine(); + + 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(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(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(); + else if(unit > 1000) + 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(); + } + + 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(); + else if(unit > 1000) + sb.AppendFormat("\tDevice takes a maximum of {0} μs to transition between sleep and standby states", + unit / 1000).AppendLine(); + else + sb.AppendFormat("\tDevice takes a maximum of {0} ns to transition between sleep and standby states", + unit).AppendLine(); + } + + 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(); + 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 has {0} sectors", csd.SectorCount).AppendLine(); + + if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Supported)) + { + sb.AppendLine("\tDevice supports secure write protection"); + + if(csd.SecureWriteProtectInformation.HasFlag(SecureWriteProtectInformation.Enabled)) + sb.AppendLine("\tDevice has secure write protection enabled"); + } + + unit = csd.MinimumReadPerformance26 * 300; + + 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(); + + unit = csd.MinimumReadPerformance26_4 * 300; + + if(csd.MinimumReadPerformance26_4 == 0) + sb.AppendLine("\tDevice cannot achieve 2.4MB/s reading in SDR 26Mhz 4-bit mode"); + else + sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s reading in SDR 26Mhz 4-bit mode", + unit / 1000).AppendLine(); + + unit = csd.MinimumReadPerformance52 * 300; + + 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(); + + unit = csd.MinimumReadPerformanceDDR52 * 600; + + 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(); + + unit = csd.MinimumWritePerformance26 * 300; + + 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(); + + unit = csd.MinimumWritePerformance26_4 * 300; + + if(csd.MinimumWritePerformance26_4 == 0) + sb.AppendLine("\tDevice cannot achieve 2.4MB/s writing in SDR 26Mhz 4-bit mode"); + else + sb.AppendFormat("\tDevice can achieve a minimum of {0}MB/s writing in SDR 26Mhz 4-bit mode", + unit / 1000).AppendLine(); + + unit = csd.MinimumWritePerformance52 * 300; + + 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(); + + unit = csd.MinimumWritePerformanceDDR52 * 600; + + 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(); + + if(csd.PartitionSwitchingTime > 0) + sb.AppendFormat("\tDevice can take a maximum of {0} ms when switching partitions", + csd.PartitionSwitchingTime * 10).AppendLine(); + + if(csd.OutOfInterruptBusyTiming > 0) + sb.AppendFormat("\tDevice can take a maximum of {0} ms when releasing from an interrupt", + csd.OutOfInterruptBusyTiming * 10).AppendLine(); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type0)) + sb.AppendLine("\tDevice supports I/O driver strength type 0."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type1)) + sb.AppendLine("\tDevice supports I/O driver strength type 1."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type2)) + sb.AppendLine("\tDevice supports I/O driver strength type 2."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type3)) + sb.AppendLine("\tDevice supports I/O driver strength type 3."); + + if(csd.DriverStrength.HasFlag(DriverStrength.Type4)) + sb.AppendLine("\tDevice supports I/O driver strength type 4."); + + if(csd.DeviceType.HasFlag(DeviceType.HS_26)) + sb.AppendLine("\tDevice supports 26 Mhz mode"); + + if(csd.DeviceType.HasFlag(DeviceType.HS_52)) + sb.AppendLine("\tDevice supports 52 Mhz mode"); + + if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52)) + sb.AppendLine("\tDevice supports DDR 52 Mhz mode at 1.8V or 3V"); + + if(csd.DeviceType.HasFlag(DeviceType.HS_DDR_52_LV)) + sb.AppendLine("\tDevice supports DDR 52 Mhz mode 1.2V"); + + if(csd.DeviceType.HasFlag(DeviceType.HS200_18)) + sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.8V"); + + if(csd.DeviceType.HasFlag(DeviceType.HS200_12)) + sb.AppendLine("\tDevice supports HS-200 mode (SDR 200Mhz) at 1.2V"); + + if(csd.DeviceType.HasFlag(DeviceType.HS400_18)) + sb.AppendLine("\tDevice supports HS-400 mode (DDR 200Mhz) at 1.8V"); + + if(csd.DeviceType.HasFlag(DeviceType.HS400_12)) + 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(); + + switch(csd.CommandSet) + { + case 0: + sb.AppendLine("\tDevice follows compatibility MMC command set."); + + break; + case 1: + switch(csd.CommandSetRevision) + { + case 0: + sb.AppendLine("\tDevice follows standard MMC command set v4.0."); + + break; + default: + sb.AppendFormat("\tDevice follows standard MMC command set with unknown version code {0}.", + csd.CommandSetRevision).AppendLine(); + + break; + } + + break; + default: + sb.AppendFormat("\tDevice follows unknown MMC command set code {0} with revision code {1}.", + csd.CommandSet, csd.CommandSetRevision).AppendLine(); + + break; + } + + switch(csd.HighSpeedInterfaceTiming & 0x0F) + { + case 0: break; + case 1: + sb.AppendLine("\tDevice is in High Speed mode."); + + break; + case 2: + sb.AppendLine("\tDevice is in HS-200 mode."); + + break; + case 3: + sb.AppendLine("\tDevice is in HS-400 mode."); + + break; + default: + sb.AppendFormat("\tDevice has unknown timing mode {0}.", csd.HighSpeedInterfaceTiming & 0x0F). + AppendLine(); + + break; + } + + sb.AppendFormat("\tSelected driver strength is type {0}.", (csd.HighSpeedInterfaceTiming & 0xF0) >> 4). + 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"); + } + + switch(csd.BusWidth & 0x0F) + { + 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; + } + + switch(csd.ErasedMemoryContent) + { + case 0: + case 1: + sb.AppendFormat("\tErased memory range shall be '{0}'.", csd.ErasedMemoryContent).AppendLine(); + + break; + default: + sb.AppendFormat("\tUnknown erased memory content code {0}", csd.ErasedMemoryContent).AppendLine(); + + break; + } + + if((csd.PartitionConfiguration & 0x40) == 0x40) + 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; + } + + switch(csd.PartitionConfiguration & 0x07) + { + 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.BootConfigProtection.HasFlag(BootConfigProtection.Permanent)) + sb.AppendLine("\tChange of the boot configuration register bits is permanently disabled."); + else if(csd.BootConfigProtection.HasFlag(BootConfigProtection.PowerCycle)) + sb.AppendLine("\tChange of the boot configuration register bits is disabled until the next power cycle."); + + switch(csd.BootBusConditions & 0x03) + { + case 0: + sb.AppendLine("\tDevice will boot up in x1 SDR or x4 DDR bus width."); + + break; + case 1: + sb.AppendLine("\tDevice will boot up in x4 SDR or DDR bus width."); + + break; + case 2: + sb.AppendLine("\tDevice will boot up in x8 SDR or DDR bus width."); + + break; + case 3: + sb.AppendLine("\tUnknown boot condition for bus width with code 3."); + + break; + } + + sb.AppendLine((csd.BootBusConditions & 4) == 4 + ? "\tDevice will retain boot conditions after boot operation." + : "\tDevice will reset boot conditions to compatibility mode after boot operation."); + + switch((csd.BootBusConditions & 0x24) >> 3) + { + case 0: + sb.AppendLine("\tDevice will use single data rate with compatible timings in boot operation."); + + break; + case 1: + sb.AppendLine("\tDevice will use single data rate with high speed timings in boot operation."); + + break; + case 2: + sb.AppendLine("\tDevice will use dual data rate in boot operation."); + + break; + case 3: + sb.AppendLine("\tDevice will use unknown boot mode with code 3."); + + break; + } + + if(csd.HighCapacityEraseGroupDefinition.HasFlag(HighCapacityEraseGroupDefinition.Enabled)) + sb.AppendLine("\tDevice will use high capacity erase unit size, timeout and write protect group size definitions."); + + switch(csd.BootWriteProtectionStatus & 0x03) + { + case 0: + sb.AppendLine("\tBoot area 1 is not protected"); + + break; + case 1: + sb.AppendLine("\tBoot area 1 is power on protected"); + + break; + case 2: + sb.AppendLine("\tBoot area 1 is permanently protected"); + + break; + } + + switch((csd.BootWriteProtectionStatus & 0x0C) >> 2) + { + case 0: + sb.AppendLine("\tBoot area 2 is not protected"); + + break; + case 1: + sb.AppendLine("\tBoot area 2 is power on protected"); + + break; + case 2: + sb.AppendLine("\tBoot area 2 is permanently protected"); + + break; + } + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Permanent)) + { + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected)) + { + sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister. + PermanentArea2) + ? "\tBoot area 2 is permanently write protected." + : "\tBoot area 1 is permanently write protected."); + } + else + sb.AppendLine("\tBoth boot areas are permanently write protected."); + } + else if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOn)) + { + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.Selected)) + { + sb.AppendLine(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister. + PowerOnArea2) + ? "\tBoot area 2 is write protected until next power cycle." + : "\tBoot area 1 is write protected until next power cycle."); + } + else + sb.AppendLine("\tBoth boot areas are write protected until next power cycle."); + } + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PermanentDisable)) + sb.AppendLine("\tPermanent write protection of boot areas is disabled."); + + if(csd.BootAreaWriteProtectionRegister.HasFlag(BootAreaWriteProtectionRegister.PowerOnDisable)) + sb.AppendLine("\tPower cycled write protection of boot areas is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePassword)) + sb.AppendLine("\tUse of password protection features is permanently disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisableWriteProtect)) + sb.AppendLine("\tUse of permanent write protection is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePermanent)) + sb.AppendLine("\tPermanent write protection is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.DisablePowerOn)) + sb.AppendLine("\tPower cycled write protection is disabled."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPermanent)) + sb.AppendLine("\tPermanent write protection will be applied to selected group."); + + if(csd.UserAreaWriteProtectionRegister.HasFlag(UserAreaWriteProtectionRegister.ApplyPowerOn)) + sb.AppendLine("\tPower cycled write protection will be applied to selected group."); + + 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(); + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Supported)) + { + sb.AppendLine("\tDevice supports partitioning features"); + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Enhanced)) + sb.AppendLine("\tDevice can have enhanced technological features in partitions and user data area"); + + if(csd.PartitioningSupport.HasFlag(PartitioningSupport.Extended)) + sb.AppendLine("\tDevice can have extended partitions attribute."); + } + + 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; + } + + switch(csd.SectorSizeEmulation) + { + 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(); + + break; + } + + switch(csd.SectorSize) + { + 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.CommandQueueModeEnable & 0x01) == 0x01) + sb.AppendLine("\tDevice has enabled command queuing"); + + return sb.ToString(); } + + public static string PrettifyExtendedCSD(byte[] response) => PrettifyExtendedCSD(DecodeExtendedCSD(response)); } \ No newline at end of file diff --git a/MMC/OCR.cs b/MMC/OCR.cs index e95989a..3bcb773 100644 --- a/MMC/OCR.cs +++ b/MMC/OCR.cs @@ -35,148 +35,147 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.MMC +namespace Aaru.Decoders.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class OCR { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public class OCR + 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 ThreeZero; + public bool TwoEight; + 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 TwoZero; +} + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Decoders +{ + public static OCR DecodeOCR(uint response) { - 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 ThreeZero; - public bool TwoEight; - 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 TwoZero; + response = Swapping.Swap(response); + + return 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 + }; } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Decoders + public static OCR DecodeOCR(byte[] response) => + response?.Length != 4 ? null : DecodeOCR(BitConverter.ToUInt32(response, 0)); + + public static string PrettifyOCR(OCR ocr) { - public static OCR DecodeOCR(uint response) - { - response = Swapping.Swap(response); + if(ocr == null) + return null; - return 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 - }; + var sb = new StringBuilder(); + sb.AppendLine("MultiMediaCard Operation Conditions Register:"); + + 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; } - public static OCR DecodeOCR(byte[] response) => - response?.Length != 4 ? null : DecodeOCR(BitConverter.ToUInt32(response, 0)); + if(ocr.ThreeFive) + sb.AppendLine("\tDevice can work with supply 3.5~3.6V"); - public static string PrettifyOCR(OCR ocr) - { - if(ocr == null) - return null; + if(ocr.ThreeFour) + sb.AppendLine("\tDevice can work with supply 3.4~3.5V"); - var sb = new StringBuilder(); - sb.AppendLine("MultiMediaCard Operation Conditions Register:"); + if(ocr.ThreeThree) + sb.AppendLine("\tDevice can work with supply 3.3~3.4V"); - if(!ocr.PowerUp) - sb.AppendLine("\tDevice is powering up"); + if(ocr.ThreeTwo) + sb.AppendLine("\tDevice can work with supply 3.2~3.3V"); - switch(ocr.AccessMode) - { - case 0: - sb.AppendLine("\tDevice is byte addressed"); + if(ocr.ThreeOne) + sb.AppendLine("\tDevice can work with supply 3.1~3.2V"); - break; - case 2: - sb.AppendLine("\tDevice is sector addressed"); + if(ocr.TwoNine) + sb.AppendLine("\tDevice can work with supply 2.9~3.0V"); - break; - default: - sb.AppendFormat("\tUnknown device access mode {0}", ocr.AccessMode).AppendLine(); + if(ocr.TwoEight) + sb.AppendLine("\tDevice can work with supply 2.8~2.9V"); - break; - } + if(ocr.TwoSeven) + sb.AppendLine("\tDevice can work with supply 2.7~2.8V"); - if(ocr.ThreeFive) - sb.AppendLine("\tDevice can work with supply 3.5~3.6V"); + if(ocr.TwoSix) + sb.AppendLine("\tDevice can work with supply 2.6~2.7V"); - if(ocr.ThreeFour) - sb.AppendLine("\tDevice can work with supply 3.4~3.5V"); + if(ocr.TwoFive) + sb.AppendLine("\tDevice can work with supply 2.5~2.6V"); - if(ocr.ThreeThree) - sb.AppendLine("\tDevice can work with supply 3.3~3.4V"); + if(ocr.TwoFour) + sb.AppendLine("\tDevice can work with supply 2.4~2.5V"); - if(ocr.ThreeTwo) - sb.AppendLine("\tDevice can work with supply 3.2~3.3V"); + if(ocr.TwoThree) + sb.AppendLine("\tDevice can work with supply 2.3~2.4V"); - if(ocr.ThreeOne) - sb.AppendLine("\tDevice can work with supply 3.1~3.2V"); + if(ocr.TwoTwo) + sb.AppendLine("\tDevice can work with supply 2.2~2.3V"); - if(ocr.TwoNine) - sb.AppendLine("\tDevice can work with supply 2.9~3.0V"); + if(ocr.TwoOne) + sb.AppendLine("\tDevice can work with supply 2.1~2.2V"); - if(ocr.TwoEight) - sb.AppendLine("\tDevice can work with supply 2.8~2.9V"); + if(ocr.TwoZero) + sb.AppendLine("\tDevice can work with supply 2.0~2.1V"); - if(ocr.TwoSeven) - sb.AppendLine("\tDevice can work with supply 2.7~2.8V"); + if(ocr.OneSix) + sb.AppendLine("\tDevice can work with supply 1.65~1.95V"); - 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(); - } - - public static string PrettifyOCR(byte[] response) => PrettifyOCR(DecodeOCR(response)); - - public static string PrettifyOCR(uint response) => PrettifyOCR(DecodeOCR(response)); + return sb.ToString(); } + + public static string PrettifyOCR(byte[] response) => PrettifyOCR(DecodeOCR(response)); + + public static string PrettifyOCR(uint response) => PrettifyOCR(DecodeOCR(response)); } \ No newline at end of file diff --git a/MMC/VendorString.cs b/MMC/VendorString.cs index 219a45a..049a825 100644 --- a/MMC/VendorString.cs +++ b/MMC/VendorString.cs @@ -30,20 +30,19 @@ // Copyright © 2011-2022 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Decoders.MMC +namespace Aaru.Decoders.MMC; + +/// Decodes MultiMediaCard vendors +public static class VendorString { - /// Decodes MultiMediaCard vendors - public static class VendorString + /// Converts the byte value of a MultiMediaCard vendor ID to the manufacturer's name string + /// MMC vendor ID + /// Manufacturer + public static string Prettify(byte mmcVendorId) => mmcVendorId switch { - /// Converts the byte value of a MultiMediaCard vendor ID to the manufacturer's name string - /// MMC vendor ID - /// Manufacturer - public static string Prettify(byte mmcVendorId) => mmcVendorId switch - { - 0x07 => "Nokia", - 0x15 => "Samsung", - 0x2C => "extreMEmory", - _ => $"Unknown manufacturer ID 0x{mmcVendorId:X2}" - }; - } + 0x07 => "Nokia", + 0x15 => "Samsung", + 0x2C => "extreMEmory", + _ => $"Unknown manufacturer ID 0x{mmcVendorId:X2}" + }; } \ No newline at end of file diff --git a/PCMCIA/CIS.cs b/PCMCIA/CIS.cs index 91949db..adb58e3 100644 --- a/PCMCIA/CIS.cs +++ b/PCMCIA/CIS.cs @@ -37,282 +37,281 @@ using System.Linq; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.PCMCIA +namespace Aaru.Decoders.PCMCIA; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class CIS { - [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? + public static Tuple[] GetTuples(byte[] data) { - // TODO: Handle links? Or are they removed in lower layers of the operating system drivers? - public static Tuple[] GetTuples(byte[] data) - { - List tuples = new List(); - int position = 0; + List tuples = new List(); + int position = 0; - while(position < data.Length) + while(position < data.Length) + { + var tuple = new Tuple { - var tuple = new Tuple - { - Code = (TupleCodes)data[position] - }; - - if(tuple.Code == TupleCodes.CISTPL_NULL) - continue; - - if(tuple.Code == TupleCodes.CISTPL_END) - break; - - tuple.Link = data[position + 1]; - - 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); - - tuples.Add(tuple); - position += tuple.Link + 2; - } - - return tuples.ToArray(); - } - - public static DeviceGeometryTuple DecodeDeviceGeometryTuple(Tuple tuple) - { - if(tuple == null) - 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; - - var tuple = new DeviceGeometryTuple(); - List geometries = new List(); - - for(int position = 2; position < data.Length; position += 6) - { - 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] - }; - - geometries.Add(geometry); - } - - tuple.Code = (TupleCodes)data[0]; - tuple.Link = data[1]; - tuple.Geometries = geometries.ToArray(); - - return tuple; - } - - public static string PrettifyDeviceGeometryTuple(DeviceGeometryTuple tuple) - { - if(tuple == null) - return null; - - if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO && - tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A) - return null; - - 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(); - } - - return sb.ToString(); - } - - public static string PrettifyDeviceGeometryTuple(Tuple tuple) => - PrettifyDeviceGeometryTuple(DecodeDeviceGeometryTuple(tuple)); - - public static string PrettifyDeviceGeometryTuple(byte[] data) => - PrettifyDeviceGeometryTuple(DecodeDeviceGeometryTuple(data)); - - public static ManufacturerIdentificationTuple DecodeManufacturerIdentificationTuple(Tuple tuple) - { - 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.Length < 6) - return null; - - return new ManufacturerIdentificationTuple - { - 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; - - 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(); - - return sb.ToString(); - } - - public static string PrettifyManufacturerIdentificationTuple(Tuple tuple) => - PrettifyManufacturerIdentificationTuple(DecodeManufacturerIdentificationTuple(tuple)); - - public static string PrettifyManufacturerIdentificationTuple(byte[] data) => - PrettifyManufacturerIdentificationTuple(DecodeManufacturerIdentificationTuple(data)); - - public static Level1VersionTuple DecodeLevel1VersionTuple(Tuple tuple) - { - 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.Length < 4) - return null; - - List buffer = new List(); - List strings = null; - bool firstString = false; - bool secondString = false; - - var tuple = new Level1VersionTuple - { - Code = (TupleCodes)data[0], - Link = data[1], - MajorVersion = data[2], - MinorVersion = data[3] + Code = (TupleCodes)data[position] }; - for(int position = 4; position < data.Length; position++) - { - if(data[position] == 0xFF) - break; + if(tuple.Code == TupleCodes.CISTPL_NULL) + continue; - buffer.Add(data[position]); + if(tuple.Code == TupleCodes.CISTPL_END) + break; - if(data[position] != 0x00) - continue; + tuple.Link = data[position + 1]; - if(!firstString) - { - tuple.Manufacturer = StringHandlers.CToString(buffer.ToArray()); - buffer = new List(); - firstString = true; + if(position + 2 + tuple.Link > data.Length) + break; - continue; - } + tuple.Data = new byte[tuple.Link + 2]; + Array.Copy(data, position, tuple.Data, 0, tuple.Link + 2); - // TODO: Check this - if(!secondString) - { - tuple.Product = StringHandlers.CToString(buffer.ToArray()); - buffer = new List(); - firstString = true; - - continue; - } - - if(strings == null) - strings = new List(); - - strings.Add(StringHandlers.CToString(buffer.ToArray())); - buffer = new List(); - } - - if(strings != null) - tuple.AdditionalInformation = strings.ToArray(); - - return tuple; + tuples.Add(tuple); + position += tuple.Link + 2; } - public static string PrettifyLevel1VersionTuple(Level1VersionTuple tuple) - { - if(tuple?.Code != TupleCodes.CISTPL_VERS_1) - return null; - - 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.Product)) - sb.AppendLine("\tNo product name string."); - else - sb.AppendFormat("\tProduct name: {0}", tuple.Product).AppendLine(); - - 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(); - } - - return sb.ToString(); - } - - public static string PrettifyLevel1VersionTuple(Tuple tuple) => - PrettifyLevel1VersionTuple(DecodeLevel1VersionTuple(tuple)); - - public static string PrettifyLevel1VersionTuple(byte[] data) => - PrettifyLevel1VersionTuple(DecodeLevel1VersionTuple(data)); + return tuples.ToArray(); } + + public static DeviceGeometryTuple DecodeDeviceGeometryTuple(Tuple tuple) + { + if(tuple == null) + 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; + + var tuple = new DeviceGeometryTuple(); + List geometries = new List(); + + for(int position = 2; position < data.Length; position += 6) + { + 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] + }; + + geometries.Add(geometry); + } + + tuple.Code = (TupleCodes)data[0]; + tuple.Link = data[1]; + tuple.Geometries = geometries.ToArray(); + + return tuple; + } + + public static string PrettifyDeviceGeometryTuple(DeviceGeometryTuple tuple) + { + if(tuple == null) + return null; + + if(tuple.Code != TupleCodes.CISTPL_DEVICEGEO && + tuple.Code != TupleCodes.CISTPL_DEVICEGEO_A) + return null; + + 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(); + } + + return sb.ToString(); + } + + public static string PrettifyDeviceGeometryTuple(Tuple tuple) => + PrettifyDeviceGeometryTuple(DecodeDeviceGeometryTuple(tuple)); + + public static string PrettifyDeviceGeometryTuple(byte[] data) => + PrettifyDeviceGeometryTuple(DecodeDeviceGeometryTuple(data)); + + public static ManufacturerIdentificationTuple DecodeManufacturerIdentificationTuple(Tuple tuple) + { + 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.Length < 6) + return null; + + return new ManufacturerIdentificationTuple + { + 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; + + 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(); + + return sb.ToString(); + } + + public static string PrettifyManufacturerIdentificationTuple(Tuple tuple) => + PrettifyManufacturerIdentificationTuple(DecodeManufacturerIdentificationTuple(tuple)); + + public static string PrettifyManufacturerIdentificationTuple(byte[] data) => + PrettifyManufacturerIdentificationTuple(DecodeManufacturerIdentificationTuple(data)); + + public static Level1VersionTuple DecodeLevel1VersionTuple(Tuple tuple) + { + 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.Length < 4) + return null; + + List buffer = new List(); + List strings = null; + bool firstString = false; + bool secondString = false; + + 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; + + buffer.Add(data[position]); + + if(data[position] != 0x00) + continue; + + if(!firstString) + { + tuple.Manufacturer = StringHandlers.CToString(buffer.ToArray()); + buffer = new List(); + firstString = true; + + continue; + } + + // TODO: Check this + if(!secondString) + { + tuple.Product = StringHandlers.CToString(buffer.ToArray()); + buffer = new List(); + firstString = true; + + continue; + } + + if(strings == null) + strings = new List(); + + strings.Add(StringHandlers.CToString(buffer.ToArray())); + buffer = new List(); + } + + if(strings != null) + tuple.AdditionalInformation = strings.ToArray(); + + return tuple; + } + + public static string PrettifyLevel1VersionTuple(Level1VersionTuple tuple) + { + if(tuple?.Code != TupleCodes.CISTPL_VERS_1) + return null; + + 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.Product)) + sb.AppendLine("\tNo product name string."); + else + sb.AppendFormat("\tProduct name: {0}", tuple.Product).AppendLine(); + + 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(); + } + + return sb.ToString(); + } + + public static string PrettifyLevel1VersionTuple(Tuple tuple) => + PrettifyLevel1VersionTuple(DecodeLevel1VersionTuple(tuple)); + + public static string PrettifyLevel1VersionTuple(byte[] data) => + PrettifyLevel1VersionTuple(DecodeLevel1VersionTuple(data)); } \ No newline at end of file diff --git a/PCMCIA/Enums.cs b/PCMCIA/Enums.cs index c1f0d4f..c0975d9 100644 --- a/PCMCIA/Enums.cs +++ b/PCMCIA/Enums.cs @@ -32,143 +32,142 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.PCMCIA +namespace Aaru.Decoders.PCMCIA; + +/// Tuple codes. +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum TupleCodes : byte { - /// Tuple codes. - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum TupleCodes : byte - { - /// Checksum control - CISTPL_CHECKSUM = 0x10, - /// End-of-chain - CISTPL_END = 0xFF, - /// Indirect access PC Card memory - CISTPL_INDIRECT = 0x03, - /// Link-target-control - CISTPL_LINKTARGET = 0x13, - /// Longlink to attribute memory - CISTPL_LONGLINK_A = 0x11, - /// Longlink to common memory - CISTPL_LONGLINK_C = 0x12, - /// Longlink to next chain on a Cardbus PC Card - CISTPL_LONGLINK_CB = 0x02, - /// Longlink to function specific chains - CISTPL_LONGLINK_MFC = 0x06, - /// No-link to common memory - CISTPL_NO_LINK = 0x14, - /// Null tuple - CISTPL_NULL = 0x00, - /// Alternate language string - CISTPL_ALTSTR = 0x16, - /// Common memory device information - CISTPL_DEVICE = 0x01, - /// Attribute memory device information - CISTPL_DEVICE_A = 0x17, - /// Other operating conditions information for attribute memory - CISTPL_DEVICE_OA = 0x1D, - /// Other operating conditions information for common memory - CISTPL_DEVICE_OC = 0x1C, - /// Device geometry information for common memory - CISTPL_DEVICEGEO = 0x1E, - /// Device geometry information for attribute memory - CISTPL_DEVICEGEO_A = 0x1F, - /// Extended common memory device information - CISTPL_EXTDEVIC = 0x09, - /// Function extensions - CISTPL_FUNCE = 0x22, - /// Function class identification - CISTPL_FUNCID = 0x21, - /// JEDEC programming information for attribute memory - CISTPL_JEDEC_A = 0x19, - /// JEDEC programming information for common memory - CISTPL_JEDEC_C = 0x18, - /// Manufacturer identification string - CISTPL_MANFID = 0x20, - /// Level 1 version/product information - CISTPL_VERS_1 = 0x15, - /// BAR for a CardBus PC Card - CISTPL_BAR = 0x07, - /// Configuration-table-entry - CISTPL_CFTABLE_ENTRY = 0x1B, - /// Configuration-table-entry for a CardBus PC Card - CISTPL_CFTABLE_ENTRY_CB = 0x05, - /// Configuration tuple for a 16-bit PC Card - CISTPL_CONFIG = 0x1A, - /// Configuration tuple for a CardBus PC Card - CISTPL_CONFIG_CB = 0x04, - /// Function state save/restore definition - CISTPL_PWR_MGMNT = 0x08, - /// Battery replacement date - CISTPL_BATTERY = 0x45, - /// Card initialization date - CISTPL_DATE = 0x44, - /// Level 2 version/product information - CISTPL_VERS_2 = 0x40, - /// Byte ordering for disk-like partitions - CISTPL_BYTEORDER = 0x43, - /// Data recording format for common memory - CISTPL_FORMAT = 0x41, - /// Data recording format for attribute memory - CISTPL_FORMAT_A = 0x47, - /// Partition geometry - CISTPL_GEOMETRY = 0x42, - /// Software interleaving - CISTPL_SWIL = 0x23, - /// Partition organization - CISTPL_ORG = 0x46, - /// Special purpose - CISTPL_SPCL = 0x90 - } + /// Checksum control + CISTPL_CHECKSUM = 0x10, + /// End-of-chain + CISTPL_END = 0xFF, + /// Indirect access PC Card memory + CISTPL_INDIRECT = 0x03, + /// Link-target-control + CISTPL_LINKTARGET = 0x13, + /// Longlink to attribute memory + CISTPL_LONGLINK_A = 0x11, + /// Longlink to common memory + CISTPL_LONGLINK_C = 0x12, + /// Longlink to next chain on a Cardbus PC Card + CISTPL_LONGLINK_CB = 0x02, + /// Longlink to function specific chains + CISTPL_LONGLINK_MFC = 0x06, + /// No-link to common memory + CISTPL_NO_LINK = 0x14, + /// Null tuple + CISTPL_NULL = 0x00, + /// Alternate language string + CISTPL_ALTSTR = 0x16, + /// Common memory device information + CISTPL_DEVICE = 0x01, + /// Attribute memory device information + CISTPL_DEVICE_A = 0x17, + /// Other operating conditions information for attribute memory + CISTPL_DEVICE_OA = 0x1D, + /// Other operating conditions information for common memory + CISTPL_DEVICE_OC = 0x1C, + /// Device geometry information for common memory + CISTPL_DEVICEGEO = 0x1E, + /// Device geometry information for attribute memory + CISTPL_DEVICEGEO_A = 0x1F, + /// Extended common memory device information + CISTPL_EXTDEVIC = 0x09, + /// Function extensions + CISTPL_FUNCE = 0x22, + /// Function class identification + CISTPL_FUNCID = 0x21, + /// JEDEC programming information for attribute memory + CISTPL_JEDEC_A = 0x19, + /// JEDEC programming information for common memory + CISTPL_JEDEC_C = 0x18, + /// Manufacturer identification string + CISTPL_MANFID = 0x20, + /// Level 1 version/product information + CISTPL_VERS_1 = 0x15, + /// BAR for a CardBus PC Card + CISTPL_BAR = 0x07, + /// Configuration-table-entry + CISTPL_CFTABLE_ENTRY = 0x1B, + /// Configuration-table-entry for a CardBus PC Card + CISTPL_CFTABLE_ENTRY_CB = 0x05, + /// Configuration tuple for a 16-bit PC Card + CISTPL_CONFIG = 0x1A, + /// Configuration tuple for a CardBus PC Card + CISTPL_CONFIG_CB = 0x04, + /// Function state save/restore definition + CISTPL_PWR_MGMNT = 0x08, + /// Battery replacement date + CISTPL_BATTERY = 0x45, + /// Card initialization date + CISTPL_DATE = 0x44, + /// Level 2 version/product information + CISTPL_VERS_2 = 0x40, + /// Byte ordering for disk-like partitions + CISTPL_BYTEORDER = 0x43, + /// Data recording format for common memory + CISTPL_FORMAT = 0x41, + /// Data recording format for attribute memory + CISTPL_FORMAT_A = 0x47, + /// Partition geometry + CISTPL_GEOMETRY = 0x42, + /// Software interleaving + CISTPL_SWIL = 0x23, + /// Partition organization + CISTPL_ORG = 0x46, + /// Special purpose + CISTPL_SPCL = 0x90 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DeviceTypeCodes : byte - { - /// No device, used to designate a hole - DTYPE_NULL = 0, - /// Masked ROM - DTYPE_ROM = 1, - /// One-type-programmable ROM - DTYPE_OTPROM = 2, - /// UV-Erasable Programmable ROM - DTYPE_EPROM = 3, - /// Electronically-Erasable Programmable ROM - DTYPE_EEPROM = 4, - /// Flash memory - DTYPE_FLASH = 5, - /// Static RAM - DTYPE_SRAM = 6, - /// Dynamic RAM - DTYPE_DRAM = 7, - /// Function-specific memory address range - DTYPE_FUNCSPEC = 13, - /// Extended type follows - DTYPE_EXTEND = 14 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DeviceTypeCodes : byte +{ + /// No device, used to designate a hole + DTYPE_NULL = 0, + /// Masked ROM + DTYPE_ROM = 1, + /// One-type-programmable ROM + DTYPE_OTPROM = 2, + /// UV-Erasable Programmable ROM + DTYPE_EPROM = 3, + /// Electronically-Erasable Programmable ROM + DTYPE_EEPROM = 4, + /// Flash memory + DTYPE_FLASH = 5, + /// Static RAM + DTYPE_SRAM = 6, + /// Dynamic RAM + DTYPE_DRAM = 7, + /// Function-specific memory address range + DTYPE_FUNCSPEC = 13, + /// Extended type follows + DTYPE_EXTEND = 14 +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DeviceSpeedCodes : byte - { - /// No device - DSPEED_NULL = 0, - /// 250 ns - DSPEED_250NS = 1, - /// 200 ns - DSPEED_200NS = 2, - /// 150 ns - DSPEED_150NS = 3, - /// 100 ns - DSPEED_100NS = 4, - /// Extended speed follows - DSPEED_EXT = 7 - } +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DeviceSpeedCodes : byte +{ + /// No device + DSPEED_NULL = 0, + /// 250 ns + DSPEED_250NS = 1, + /// 200 ns + DSPEED_200NS = 2, + /// 150 ns + DSPEED_150NS = 3, + /// 100 ns + DSPEED_100NS = 4, + /// Extended speed follows + 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 - } +[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 } \ No newline at end of file diff --git a/PCMCIA/Types.cs b/PCMCIA/Types.cs index 9e3a950..5b46919 100644 --- a/PCMCIA/Types.cs +++ b/PCMCIA/Types.cs @@ -32,350 +32,349 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.PCMCIA +namespace Aaru.Decoders.PCMCIA; + +/// Basic classure of a PCMCIA tuple +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class Tuple { - /// Basic classure of a PCMCIA tuple - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class Tuple - { - public TupleCodes Code; - public byte[] Data; - public byte Link; - } + public TupleCodes Code; + public byte[] Data; + public byte Link; +} - /// Checksum tuple - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class ChecksumTuple - { - /// Modulo-256 sum of region - public byte Checksum; - /// - /// - /// - public TupleCodes Code; - /// Length of region to be checksummed - public ushort Length; - /// Link to next tuple - public byte Link; - /// Offset to region to be checksummed - public short Offset; - } +/// Checksum tuple +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class ChecksumTuple +{ + /// Modulo-256 sum of region + public byte Checksum; + /// + /// + /// + public TupleCodes Code; + /// Length of region to be checksummed + public ushort Length; + /// Link to next tuple + public byte Link; + /// Offset to region to be checksummed + public short Offset; +} - /// Indirect Access PC Card Memory - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class IndirectTuple - { - /// - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - } +/// Indirect Access PC Card Memory +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class IndirectTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; +} - /// Link target tuple - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class LinkTargetTuple - { - /// - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - /// 'C''I''S' in ASCII - public byte[] Tag; - } +/// Link target tuple +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class LinkTargetTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// 'C''I''S' in ASCII + public byte[] Tag; +} - /// 16-bit PC Card Long Link Tuple - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class LongLinkTuple - { - /// Target address - public uint Address; - /// - /// or or - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - } +/// 16-bit PC Card Long Link Tuple +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class LongLinkTuple +{ + /// Target address + public uint Address; + /// + /// or or + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), - SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] - public class ConfigurationAddress - { - /// Target address - public uint Address; - /// Target address space, 0 = attribute, 1 = common - public byte TargetAddressSpace; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), + SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] +public class ConfigurationAddress +{ + /// Target address + public uint Address; + /// Target address space, 0 = attribute, 1 = common + public byte TargetAddressSpace; +} - /// Multiple function link tuple - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class MultipleFunctionLinkTuple - { - /// Link to more configuration registers - public ConfigurationAddress[] Addresses; - /// - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - /// How many functions follow - public byte NumberFunctions; - } +/// Multiple function link tuple +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class MultipleFunctionLinkTuple +{ + /// Link to more configuration registers + public ConfigurationAddress[] Addresses; + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// How many functions follow + public byte NumberFunctions; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class NoLinkTuple - { - /// - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class NoLinkTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class AlternateStringTuple - { - /// - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - /// - /// Array of strings. On memory they're preceded by an ISO Escape Code indicating codepage. Here they're stored as - /// Unicode, so no need for it. - /// - public string[] Strings; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class AlternateStringTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// + /// Array of strings. On memory they're preceded by an ISO Escape Code indicating codepage. Here they're stored as + /// Unicode, so no need for it. + /// + public string[] Strings; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), - SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] - public class ExtendedDeviceSpeed - { - /// Speed exponent - public byte Exponent; - /// Another extended follows - public bool Extended; - /// Speed mantisa - public byte Mantissa; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), + SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] +public class ExtendedDeviceSpeed +{ + /// Speed exponent + public byte Exponent; + /// Another extended follows + public bool Extended; + /// Speed mantisa + public byte Mantissa; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public struct DeviceInfo - { - /// Device type code - public DeviceTypeCodes Type; - /// Write protected - public bool WPS; - /// Speed code - public DeviceSpeedCodes Speed; - /// Extended speeds - public ExtendedDeviceSpeed[] ExtendedSpeeds; - /// Extended types - public byte[] ExtendedTypes; - /// Size in units - 1 - public byte Units; - /// Code to define units unit - public byte SizeCode; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public struct DeviceInfo +{ + /// Device type code + public DeviceTypeCodes Type; + /// Write protected + public bool WPS; + /// Speed code + public DeviceSpeedCodes Speed; + /// Extended speeds + public ExtendedDeviceSpeed[] ExtendedSpeeds; + /// Extended types + public byte[] ExtendedTypes; + /// Size in units - 1 + public byte Units; + /// Code to define units unit + public byte SizeCode; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class DeviceTuple - { - /// or - public TupleCodes Code; - /// Array of device information bytes - public DeviceInfo[] Infos; - /// Link to next tuple - public byte Link; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class DeviceTuple +{ + /// or + public TupleCodes Code; + /// Array of device information bytes + public DeviceInfo[] Infos; + /// Link to next tuple + public byte Link; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public struct OtherConditionInfo - { - /// True if another other condition info follows - public bool Extended; - /// Vcc used - public byte VccUsed; - /// Supports WAIT# signal - public bool MWAIT; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public struct OtherConditionInfo +{ + /// True if another other condition info follows + public bool Extended; + /// Vcc used + public byte VccUsed; + /// Supports WAIT# signal + public bool MWAIT; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class OtherConditionTuple - { - /// or - public TupleCodes Code; - /// Array of device information bytes - public DeviceInfo[] Infos; - /// Link to next tuple - public byte Link; - /// Array of other condition information bytes - public OtherConditionInfo[] OtherConditionInfos; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class OtherConditionTuple +{ + /// or + public TupleCodes Code; + /// Array of device information bytes + public DeviceInfo[] Infos; + /// Link to next tuple + public byte Link; + /// Array of other condition information bytes + public OtherConditionInfo[] OtherConditionInfos; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public struct DeviceGeometry - { - /// 1 << n-1 bytes, 2 = 16-bit PC Card, 3 = CardBus PC Card - public byte CardInterface; - /// - /// Erase block size in 1 << n-1 increments of wide accesses. If n == 4, and - /// == 16, erase block size = 32 * 4 = 128 bytes - /// - public byte EraseBlockSize; - /// - /// Read block size in 1 << n-1 increments of wide accesses. If n == 4, and - /// == 16, read block size = 32 * 4 = 128 bytes - /// - public byte ReadBlockSize; - /// - /// Write block size in 1 << n-1 increments of wide accesses. If n == 4, and - /// == 16, write block size = 32 * 4 = 128 bytes - /// - public byte WriteBlockSize; - /// - /// Device partitioning in granularity of 1 << n-1 erase blocks If n == 4, and erase block is 128 bytes, - /// partitions must be aligned to 32 erase block, or 4096 bytes - /// - public byte Partitions; - /// Card employs a multiple of 1 << n-1 times interleaving the entire memory arrays - public byte Interleaving; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public struct DeviceGeometry +{ + /// 1 << n-1 bytes, 2 = 16-bit PC Card, 3 = CardBus PC Card + public byte CardInterface; + /// + /// Erase block size in 1 << n-1 increments of wide accesses. If n == 4, and + /// == 16, erase block size = 32 * 4 = 128 bytes + /// + public byte EraseBlockSize; + /// + /// Read block size in 1 << n-1 increments of wide accesses. If n == 4, and + /// == 16, read block size = 32 * 4 = 128 bytes + /// + public byte ReadBlockSize; + /// + /// Write block size in 1 << n-1 increments of wide accesses. If n == 4, and + /// == 16, write block size = 32 * 4 = 128 bytes + /// + public byte WriteBlockSize; + /// + /// Device partitioning in granularity of 1 << n-1 erase blocks If n == 4, and erase block is 128 bytes, + /// partitions must be aligned to 32 erase block, or 4096 bytes + /// + public byte Partitions; + /// Card employs a multiple of 1 << n-1 times interleaving the entire memory arrays + public byte Interleaving; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public class DeviceGeometryTuple - { - /// or - public TupleCodes Code; - /// Array of device geometries - public DeviceGeometry[] Geometries; - /// Link to next tuple - public byte Link; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class DeviceGeometryTuple +{ + /// or + public TupleCodes Code; + /// Array of device geometries + public DeviceGeometry[] Geometries; + /// Link to next tuple + public byte Link; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class FunctionIdentificationTuple - { - /// - /// - /// - public TupleCodes Code; - /// Function code - public FunctionCodes Function; - /// Link to next tuple - public byte Link; - /// Device wants to be part of power-on-self-test - public bool POST; - /// Device contains boot ROM - public bool ROM; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class FunctionIdentificationTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Function code + public FunctionCodes Function; + /// Link to next tuple + public byte Link; + /// Device wants to be part of power-on-self-test + public bool POST; + /// Device contains boot ROM + public bool ROM; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public class ManufacturerIdentificationTuple - { - /// Card ID - public ushort CardID; - /// - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - /// Manufacturer ID - public ushort ManufacturerID; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class ManufacturerIdentificationTuple +{ + /// Card ID + public ushort CardID; + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// Manufacturer ID + public ushort ManufacturerID; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public class Level1VersionTuple - { - /// Additional information strings - public string[] AdditionalInformation; - /// - /// - /// - public TupleCodes Code; - /// Link to next tuple - public byte Link; - /// Major version of standard compliance - public byte MajorVersion; - /// Manufacturer string - public string Manufacturer; - /// Minor version of standard compliance - public byte MinorVersion; - /// Product string - public string Product; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class Level1VersionTuple +{ + /// Additional information strings + public string[] AdditionalInformation; + /// + /// + /// + public TupleCodes Code; + /// Link to next tuple + public byte Link; + /// Major version of standard compliance + public byte MajorVersion; + /// Manufacturer string + public string Manufacturer; + /// Minor version of standard compliance + public byte MinorVersion; + /// Product string + public string Product; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class Level2VersionTuple - { - /// Address of first data byte - public ushort Address; - /// Number of copies of CIS present - public byte CISCopies; - /// - /// - /// - public TupleCodes Code; - /// Level of compliance - public byte Compliance; - /// Informational message about the card - public string Information; - /// Link to next tuple - public byte Link; - /// Vendor of software that formatted the card - public string OEM; - /// Version of this classure - public byte StructureVersion; - /// Vendor-specific byte - public byte VendorSpecific1; - /// Vendor-specific byte - public byte VendorSpecific2; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class Level2VersionTuple +{ + /// Address of first data byte + public ushort Address; + /// Number of copies of CIS present + public byte CISCopies; + /// + /// + /// + public TupleCodes Code; + /// Level of compliance + public byte Compliance; + /// Informational message about the card + public string Information; + /// Link to next tuple + public byte Link; + /// Vendor of software that formatted the card + public string OEM; + /// Version of this classure + public byte StructureVersion; + /// Vendor-specific byte + public byte VendorSpecific1; + /// Vendor-specific byte + public byte VendorSpecific2; +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class GeometryTuple - { - /// - /// - /// - public TupleCodes Code; - /// Cylinders - public ushort Cylinders; - /// Link to next tuple - public byte Link; - /// Sectors per track - public byte SectorsPerTrack; - /// Tracks per cylinder - public byte TracksPerCylinder; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class GeometryTuple +{ + /// + /// + /// + public TupleCodes Code; + /// Cylinders + public ushort Cylinders; + /// Link to next tuple + public byte Link; + /// Sectors per track + public byte SectorsPerTrack; + /// Tracks per cylinder + public byte TracksPerCylinder; } \ No newline at end of file diff --git a/PCMCIA/VendorCode.cs b/PCMCIA/VendorCode.cs index 1b44006..01992b4 100644 --- a/PCMCIA/VendorCode.cs +++ b/PCMCIA/VendorCode.cs @@ -32,332 +32,331 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.PCMCIA -{ - [SuppressMessage("ReSharper", "MemberCanBeInternal")] - public static class VendorCode - { - public static string Prettify(ushort id) - { - 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"; - #endregion JEDEC +namespace Aaru.Decoders.PCMCIA; - 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}"; - } +[SuppressMessage("ReSharper", "MemberCanBeInternal")] +public static class VendorCode +{ + public static string Prettify(ushort id) + { + 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"; + #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}"; } } } \ No newline at end of file diff --git a/SCSI/DiscStructureCapabilities.cs b/SCSI/DiscStructureCapabilities.cs index d9d8616..87c8d39 100644 --- a/SCSI/DiscStructureCapabilities.cs +++ b/SCSI/DiscStructureCapabilities.cs @@ -33,47 +33,46 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DiscStructureCapabilities { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class DiscStructureCapabilities + public static Capability[] Decode(byte[] response) { - public static Capability[] Decode(byte[] response) + ushort len = (ushort)((response[0] << 8) + response[1]); + + if(len + 2 != response.Length) + return null; + + List caps = new List(); + + uint offset = 4; + + while(offset < response.Length) { - ushort len = (ushort)((response[0] << 8) + response[1]); - - if(len + 2 != response.Length) - return null; - - List caps = new List(); - - uint offset = 4; - - while(offset < response.Length) + var 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(); + caps.Add(cap); + offset += 4; } - public struct Capability - { - /// READ/SEND DISC STRUCTURE format code - public byte FormatCode; - /// Supported in SEND DISC STRUCTURE - public bool SDS; - /// Supported in READ DISC STRUCTURE - public bool RDS; - } + return caps.ToArray(); + } + + public struct Capability + { + /// READ/SEND DISC STRUCTURE format code + public byte FormatCode; + /// Supported in SEND DISC STRUCTURE + public bool SDS; + /// Supported in READ DISC STRUCTURE + public bool RDS; } } \ No newline at end of file diff --git a/SCSI/EVPD.cs b/SCSI/EVPD.cs index 4fb06f7..13d92b7 100644 --- a/SCSI/EVPD.cs +++ b/SCSI/EVPD.cs @@ -40,1544 +40,2152 @@ using Aaru.CommonTypes.Structs.Devices.ATA; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global"), + SuppressMessage("ReSharper", "UnassignedField.Global")] +public static class EVPD { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global"), - SuppressMessage("ReSharper", "UnassignedField.Global")] - public static class EVPD + /// Decodes VPD page 0x00: Supported VPD pages + /// A byte array containing all supported VPD pages. + /// Page 0x00. + public static byte[] DecodePage00(byte[] page) { - /// Decodes VPD page 0x00: Supported VPD pages - /// A byte array containing all supported VPD pages. - /// Page 0x00. - public static byte[] DecodePage00(byte[] page) + if(page?[1] != 0) + return null; + + if(page.Length != page[3] + 4) + return null; + + byte[] decoded = new byte[page.Length - 4]; + + Array.Copy(page, 4, decoded, 0, page.Length - 4); + + return decoded; + } + + /// Decides VPD pages 0x01 to 0x7F: ASCII Information + /// An ASCII string with the contents of the page. + /// Page 0x01-0x7F. + public static string DecodeASCIIPage(byte[] page) + { + if(page == null) + return null; + + if(page[1] == 0 || + page[1] > 0x7F) + return null; + + if(page.Length != page[3] + 4) + return null; + + byte[] ascii = new byte[page[4]]; + + Array.Copy(page, 5, ascii, 0, page[4]); + + return StringHandlers.CToString(ascii); + } + + /// Decodes VPD page 0x80: Unit Serial Number + /// The unit serial number. + /// Page 0x80. + public static string DecodePage80(byte[] page) + { + if(page?[1] != 0x80) + return null; + + if(page.Length != page[3] + 4) + return null; + + byte[] ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + for(int i = 0; i < ascii.Length - 1; i++) + if(ascii[i] < 0x20) + return null; + + return StringHandlers.CToString(ascii); + } + + /// Decodes VPD page 0x82: ASCII implemented operating definition + /// ASCII implemented operating definition. + /// Page 0x82. + public static string DecodePage82(byte[] page) + { + if(page?[1] != 0x82) + return null; + + if(page.Length != page[3] + 4) + return null; + + byte[] ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + return StringHandlers.CToString(ascii); + } + + #region EVPD Page 0xB1: Manufacturer-assigned Serial Number page + public static string DecodePageB1(byte[] page) + { + if(page?[1] != 0xB1) + return null; + + if(page.Length != page[3] + 4) + return null; + + byte[] ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + return StringHandlers.CToString(ascii).Trim(); + } + #endregion EVPD Page 0xB1: Manufacturer-assigned Serial Number page + + #region EVPD Page 0xB2: TapeAlert Supported Flags page + public static ulong DecodePageB2(byte[] page) + { + if(page?[1] != 0xB2) + return 0; + + if(page.Length != 12) + return 0; + + byte[] bitmap = new byte[8]; + + Array.Copy(page, 4, bitmap, 0, 8); + + return BitConverter.ToUInt64(bitmap.Reverse().ToArray(), 0); + } + #endregion EVPD Page 0xB2: TapeAlert Supported Flags page + + #region EVPD Page 0xB3: Automation Device Serial Number page + public static string DecodePageB3(byte[] page) + { + if(page?[1] != 0xB3) + return null; + + if(page.Length != page[3] + 4) + return null; + + byte[] ascii = new byte[page.Length - 4]; + + Array.Copy(page, 4, ascii, 0, page.Length - 4); + + return StringHandlers.CToString(ascii).Trim(); + } + #endregion EVPD Page 0xB3: Automation Device Serial Number page + + #region EVPD Page 0xB4: Data Transfer Device Element Address page + public static string DecodePageB4(byte[] page) + { + if(page?[1] != 0xB3) + return null; + + if(page.Length != page[3] + 4) + return null; + + byte[] element = new byte[page.Length - 4]; + var sb = new StringBuilder(); + + foreach(byte b in element) + sb.AppendFormat("{0:X2}", b); + + return sb.ToString(); + } + #endregion EVPD Page 0xB4: Data Transfer Device Element Address page + + #region EVPD Page 0x81: Implemented operating definition page + /// Implemented operating definition page Page code 0x81 + public struct Page_81 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Current operating definition + public ScsiDefinitions Current; + /// Default operating definition + public ScsiDefinitions Default; + /// Support operating definition list + public ScsiDefinitions[] Supported; + } + + public static Page_81? DecodePage_81(byte[] pageResponse) + { + if(pageResponse?[1] != 0x81) + return null; + + if(pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 6) + return null; + + var decoded = new Page_81 { - if(page?[1] != 0) - return null; + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + Current = (ScsiDefinitions)(pageResponse[4] & 0x7F), + Default = (ScsiDefinitions)(pageResponse[5] & 0x7F) + }; - if(page.Length != page[3] + 4) - return null; + int position = 6; + List definitions = new List(); - byte[] decoded = new byte[page.Length - 4]; - - Array.Copy(page, 4, decoded, 0, page.Length - 4); - - return decoded; + while(position < pageResponse.Length) + { + var definition = (ScsiDefinitions)(pageResponse[position] & 0x7F); + position++; + definitions.Add(definition); } - /// Decides VPD pages 0x01 to 0x7F: ASCII Information - /// An ASCII string with the contents of the page. - /// Page 0x01-0x7F. - public static string DecodeASCIIPage(byte[] page) + decoded.Supported = definitions.ToArray(); + + return decoded; + } + + public static string PrettifyPage_81(byte[] pageResponse) => PrettifyPage_81(DecodePage_81(pageResponse)); + + public static string DefinitionToString(ScsiDefinitions definition) + { + switch(definition) { - if(page == null) - return null; - - if(page[1] == 0 || - page[1] > 0x7F) - return null; - - if(page.Length != page[3] + 4) - return null; - - byte[] ascii = new byte[page[4]]; - - Array.Copy(page, 5, ascii, 0, page[4]); - - return StringHandlers.CToString(ascii); + case ScsiDefinitions.Current: return ""; + case ScsiDefinitions.CCS: return "CCS"; + case ScsiDefinitions.SCSI1: return "SCSI-1"; + case ScsiDefinitions.SCSI2: return "SCSI-2"; + case ScsiDefinitions.SCSI3: return "SCSI-3"; + default: return $"Unknown definition code {(byte)definition}"; } + } - /// Decodes VPD page 0x80: Unit Serial Number - /// The unit serial number. - /// Page 0x80. - public static string DecodePage80(byte[] page) + public static string PrettifyPage_81(Page_81? modePage) + { + if(!modePage.HasValue) + return null; + + Page_81 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Implemented operating definitions:"); + + sb.AppendFormat("\tDefault operating definition: {0}", DefinitionToString(page.Current)).AppendLine(); + sb.AppendFormat("\tCurrent operating definition: {0}", DefinitionToString(page.Current)).AppendLine(); + + if(page.Supported.Length == 0) { - if(page?[1] != 0x80) - return null; - - if(page.Length != page[3] + 4) - return null; - - byte[] ascii = new byte[page.Length - 4]; - - Array.Copy(page, 4, ascii, 0, page.Length - 4); - - for(int i = 0; i < ascii.Length - 1; i++) - if(ascii[i] < 0x20) - return null; - - return StringHandlers.CToString(ascii); - } - - /// Decodes VPD page 0x82: ASCII implemented operating definition - /// ASCII implemented operating definition. - /// Page 0x82. - public static string DecodePage82(byte[] page) - { - if(page?[1] != 0x82) - return null; - - if(page.Length != page[3] + 4) - return null; - - byte[] ascii = new byte[page.Length - 4]; - - Array.Copy(page, 4, ascii, 0, page.Length - 4); - - return StringHandlers.CToString(ascii); - } - - #region EVPD Page 0xB1: Manufacturer-assigned Serial Number page - public static string DecodePageB1(byte[] page) - { - if(page?[1] != 0xB1) - return null; - - if(page.Length != page[3] + 4) - return null; - - byte[] ascii = new byte[page.Length - 4]; - - Array.Copy(page, 4, ascii, 0, page.Length - 4); - - return StringHandlers.CToString(ascii).Trim(); - } - #endregion EVPD Page 0xB1: Manufacturer-assigned Serial Number page - - #region EVPD Page 0xB2: TapeAlert Supported Flags page - public static ulong DecodePageB2(byte[] page) - { - if(page?[1] != 0xB2) - return 0; - - if(page.Length != 12) - return 0; - - byte[] bitmap = new byte[8]; - - Array.Copy(page, 4, bitmap, 0, 8); - - return BitConverter.ToUInt64(bitmap.Reverse().ToArray(), 0); - } - #endregion EVPD Page 0xB2: TapeAlert Supported Flags page - - #region EVPD Page 0xB3: Automation Device Serial Number page - public static string DecodePageB3(byte[] page) - { - if(page?[1] != 0xB3) - return null; - - if(page.Length != page[3] + 4) - return null; - - byte[] ascii = new byte[page.Length - 4]; - - Array.Copy(page, 4, ascii, 0, page.Length - 4); - - return StringHandlers.CToString(ascii).Trim(); - } - #endregion EVPD Page 0xB3: Automation Device Serial Number page - - #region EVPD Page 0xB4: Data Transfer Device Element Address page - public static string DecodePageB4(byte[] page) - { - if(page?[1] != 0xB3) - return null; - - if(page.Length != page[3] + 4) - return null; - - byte[] element = new byte[page.Length - 4]; - var sb = new StringBuilder(); - - foreach(byte b in element) - sb.AppendFormat("{0:X2}", b); + sb.AppendLine("\tThere are no supported definitions"); return sb.ToString(); } - #endregion EVPD Page 0xB4: Data Transfer Device Element Address page - #region EVPD Page 0x81: Implemented operating definition page - /// Implemented operating definition page Page code 0x81 - public struct Page_81 + sb.AppendLine("\tSupported operating definitions:"); + + foreach(ScsiDefinitions definition in page.Supported) + sb.AppendFormat("\t\t{0}", DefinitionToString(definition)).AppendLine(); + + return sb.ToString(); + } + #endregion EVPD Page 0x81: Implemented operating definition page + + #region EVPD Page 0x83: Device identification page + public enum IdentificationAssociation : byte + { + /// Identifier field is associated with the addressed logical unit + LogicalUnit = 0, + /// Identifier field is associated with the target port + TargetPort = 1, + /// Identifier field is associated with the target device that contains the LUN + TargetDevice = 2 + } + + public enum IdentificationCodeSet : byte + { + /// Identifier is binary + Binary = 1, + /// Identifier is pure ASCII + ASCII = 2, + /// Identifier is in UTF-8 + UTF8 = 3 + } + + public enum IdentificationTypes : byte + { + /// No assignment authority was used and there is no guarantee the identifier is unique + NoAuthority = 0, + /// Concatenates vendor and product identifier from INQUIRY plus unit serial number from page 80h + Inquiry = 1, + /// Identifier is a 64-bit IEEE EUI-64, or extended + EUI = 2, + /// Identifier is compatible with 64-bit FC-PH Name_Identifier + NAA = 3, + /// Identifier to relative port in device + Relative = 4, + /// Identifier to group of target ports in device + TargetPortGroup = 5, + /// Identifier to group of target LUNs in device + LogicalUnitGroup = 6, + /// MD5 of device identification values + MD5 = 7, + /// SCSI name string + SCSI = 8, + /// Protocol specific port identifier + ProtocolSpecific = 9 + } + + public struct IdentificatonDescriptor + { + /// Protocol identifier + public ProtocolIdentifiers ProtocolIdentifier; + /// Defines how the identifier is stored + public IdentificationCodeSet CodeSet; + /// Set if protocol identifier is valid + public bool PIV; + /// Identifies which decide the identifier associates with + public IdentificationAssociation Association; + /// Defines the type of the identifier + public IdentificationTypes Type; + /// Length of the identifier + public byte Length; + /// Identifier as a string if applicable + public string ASCII; + /// Binary identifier + public byte[] Binary; + } + + /// Device identification page Page code 0x83 + public struct Page_83 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// The descriptors. + public IdentificatonDescriptor[] Descriptors; + } + + public static Page_83? DecodePage_83(byte[] pageResponse) + { + if(pageResponse?[1] != 0x83) + return null; + + if(pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 6) + return null; + + var decoded = new Page_83 { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - /// Current operating definition - public ScsiDefinitions Current; - /// Default operating definition - public ScsiDefinitions Default; - /// Support operating definition list - public ScsiDefinitions[] Supported; - } + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4) + }; - public static Page_81? DecodePage_81(byte[] pageResponse) + int position = 4; + List descriptors = new List(); + + while(position < pageResponse.Length) { - if(pageResponse?[1] != 0x81) - return null; - - if(pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 6) - return null; - - var decoded = new Page_81 + var descriptor = new IdentificatonDescriptor { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - Current = (ScsiDefinitions)(pageResponse[4] & 0x7F), - Default = (ScsiDefinitions)(pageResponse[5] & 0x7F) + ProtocolIdentifier = (ProtocolIdentifiers)((pageResponse[position] & 0xF0) >> 4), + CodeSet = (IdentificationCodeSet)(pageResponse[position] & 0x0F), + PIV = (pageResponse[position + 1] & 0x80) == 0x80, + Association = (IdentificationAssociation)((pageResponse[position + 1] & 0x30) >> 4), + Type = (IdentificationTypes)(pageResponse[position + 1] & 0x0F), + Length = pageResponse[position + 3] }; - int position = 6; - List definitions = new List(); + descriptor.Binary = new byte[descriptor.Length]; - while(position < pageResponse.Length) + if(descriptor.Length + position + 4 >= pageResponse.Length) + descriptor.Length = (byte)(pageResponse.Length - position - 4); + + Array.Copy(pageResponse, position + 4, descriptor.Binary, 0, descriptor.Length); + + switch(descriptor.CodeSet) { - var definition = (ScsiDefinitions)(pageResponse[position] & 0x7F); - position++; - definitions.Add(definition); + case IdentificationCodeSet.ASCII: + descriptor.ASCII = StringHandlers.CToString(descriptor.Binary); + + break; + case IdentificationCodeSet.UTF8: + descriptor.ASCII = Encoding.UTF8.GetString(descriptor.Binary); + + break; + default: + descriptor.ASCII = ""; + + break; } - decoded.Supported = definitions.ToArray(); - - return decoded; + position += 4 + descriptor.Length; + descriptors.Add(descriptor); } - public static string PrettifyPage_81(byte[] pageResponse) => PrettifyPage_81(DecodePage_81(pageResponse)); + decoded.Descriptors = descriptors.ToArray(); - public static string DefinitionToString(ScsiDefinitions definition) + return decoded; + } + + public static string PrettifyPage_83(byte[] pageResponse) => PrettifyPage_83(DecodePage_83(pageResponse)); + + public static string PrettifyPage_83(Page_83? modePage) + { + if(!modePage.HasValue) + return null; + + Page_83 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Device identification:"); + + if(page.Descriptors.Length == 0) { - switch(definition) - { - case ScsiDefinitions.Current: return ""; - case ScsiDefinitions.CCS: return "CCS"; - case ScsiDefinitions.SCSI1: return "SCSI-1"; - case ScsiDefinitions.SCSI2: return "SCSI-2"; - case ScsiDefinitions.SCSI3: return "SCSI-3"; - default: return $"Unknown definition code {(byte)definition}"; - } - } - - public static string PrettifyPage_81(Page_81? modePage) - { - if(!modePage.HasValue) - return null; - - Page_81 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Implemented operating definitions:"); - - sb.AppendFormat("\tDefault operating definition: {0}", DefinitionToString(page.Current)).AppendLine(); - sb.AppendFormat("\tCurrent operating definition: {0}", DefinitionToString(page.Current)).AppendLine(); - - if(page.Supported.Length == 0) - { - sb.AppendLine("\tThere are no supported definitions"); - - return sb.ToString(); - } - - sb.AppendLine("\tSupported operating definitions:"); - - foreach(ScsiDefinitions definition in page.Supported) - sb.AppendFormat("\t\t{0}", DefinitionToString(definition)).AppendLine(); + sb.AppendLine("\tThere are no identifiers"); return sb.ToString(); } - #endregion EVPD Page 0x81: Implemented operating definition page - #region EVPD Page 0x83: Device identification page - public enum IdentificationAssociation : byte + foreach(IdentificatonDescriptor descriptor in page.Descriptors) { - /// Identifier field is associated with the addressed logical unit - LogicalUnit = 0, - /// Identifier field is associated with the target port - TargetPort = 1, - /// Identifier field is associated with the target device that contains the LUN - TargetDevice = 2 - } - - public enum IdentificationCodeSet : byte - { - /// Identifier is binary - Binary = 1, - /// Identifier is pure ASCII - ASCII = 2, - /// Identifier is in UTF-8 - UTF8 = 3 - } - - public enum IdentificationTypes : byte - { - /// No assignment authority was used and there is no guarantee the identifier is unique - NoAuthority = 0, - /// Concatenates vendor and product identifier from INQUIRY plus unit serial number from page 80h - Inquiry = 1, - /// Identifier is a 64-bit IEEE EUI-64, or extended - EUI = 2, - /// Identifier is compatible with 64-bit FC-PH Name_Identifier - NAA = 3, - /// Identifier to relative port in device - Relative = 4, - /// Identifier to group of target ports in device - TargetPortGroup = 5, - /// Identifier to group of target LUNs in device - LogicalUnitGroup = 6, - /// MD5 of device identification values - MD5 = 7, - /// SCSI name string - SCSI = 8, - /// Protocol specific port identifier - ProtocolSpecific = 9 - } - - public struct IdentificatonDescriptor - { - /// Protocol identifier - public ProtocolIdentifiers ProtocolIdentifier; - /// Defines how the identifier is stored - public IdentificationCodeSet CodeSet; - /// Set if protocol identifier is valid - public bool PIV; - /// Identifies which decide the identifier associates with - public IdentificationAssociation Association; - /// Defines the type of the identifier - public IdentificationTypes Type; - /// Length of the identifier - public byte Length; - /// Identifier as a string if applicable - public string ASCII; - /// Binary identifier - public byte[] Binary; - } - - /// Device identification page Page code 0x83 - public struct Page_83 - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - /// The descriptors. - public IdentificatonDescriptor[] Descriptors; - } - - public static Page_83? DecodePage_83(byte[] pageResponse) - { - if(pageResponse?[1] != 0x83) - return null; - - if(pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 6) - return null; - - var decoded = new Page_83 + switch(descriptor.Association) { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4) - }; + case IdentificationAssociation.LogicalUnit: + sb.AppendLine("\tIdentifier belongs to addressed logical unit"); - int position = 4; - List descriptors = new List(); + break; + case IdentificationAssociation.TargetPort: + sb.AppendLine("\tIdentifier belongs to target port"); - while(position < pageResponse.Length) + break; + case IdentificationAssociation.TargetDevice: + sb.AppendLine("\tIdentifier belongs to target device that contains the addressed logical unit"); + + break; + default: + sb.AppendFormat("\tIndentifier has unknown association with code {0}", + (byte)descriptor.Association).AppendLine(); + + break; + } + + if(descriptor.PIV) { - var descriptor = new IdentificatonDescriptor + string protocol; + + switch(descriptor.ProtocolIdentifier) { - ProtocolIdentifier = (ProtocolIdentifiers)((pageResponse[position] & 0xF0) >> 4), - CodeSet = (IdentificationCodeSet)(pageResponse[position] & 0x0F), - PIV = (pageResponse[position + 1] & 0x80) == 0x80, - Association = (IdentificationAssociation)((pageResponse[position + 1] & 0x30) >> 4), - Type = (IdentificationTypes)(pageResponse[position + 1] & 0x0F), - Length = pageResponse[position + 3] - }; - - descriptor.Binary = new byte[descriptor.Length]; - - if(descriptor.Length + position + 4 >= pageResponse.Length) - descriptor.Length = (byte)(pageResponse.Length - position - 4); - - Array.Copy(pageResponse, position + 4, descriptor.Binary, 0, descriptor.Length); - - switch(descriptor.CodeSet) - { - case IdentificationCodeSet.ASCII: - descriptor.ASCII = StringHandlers.CToString(descriptor.Binary); + case ProtocolIdentifiers.ADT: + protocol = "Automation/Drive Interface Transport"; break; - case IdentificationCodeSet.UTF8: - descriptor.ASCII = Encoding.UTF8.GetString(descriptor.Binary); + case ProtocolIdentifiers.ATA: + protocol = "AT Attachment Interface (ATA/ATAPI)"; + + break; + case ProtocolIdentifiers.FibreChannel: + protocol = "Fibre Channel"; + + break; + case ProtocolIdentifiers.Firewire: + protocol = "IEEE 1394"; + + break; + case ProtocolIdentifiers.iSCSI: + protocol = "Internet SCSI"; + + break; + case ProtocolIdentifiers.NoProtocol: + protocol = "no specific"; + + break; + case ProtocolIdentifiers.PCIe: + protocol = "PCI Express"; + + break; + case ProtocolIdentifiers.RDMAP: + protocol = "SCSI Remote Direct Memory Access"; + + break; + case ProtocolIdentifiers.SAS: + protocol = "Serial Attachment SCSI"; + + break; + case ProtocolIdentifiers.SCSI: + protocol = "Parallel SCSI"; + + break; + case ProtocolIdentifiers.SCSIe: + protocol = "SCSI over PCI Express"; + + break; + case ProtocolIdentifiers.SSA: + protocol = "SSA"; + + break; + case ProtocolIdentifiers.UAS: + protocol = "USB Attached SCSI"; break; default: - descriptor.ASCII = ""; + protocol = $"unknown code {(byte)descriptor.ProtocolIdentifier}"; break; } - position += 4 + descriptor.Length; - descriptors.Add(descriptor); + sb.AppendFormat("\tDescriptor referes to {0} protocol", protocol).AppendLine(); } - decoded.Descriptors = descriptors.ToArray(); - - return decoded; - } - - public static string PrettifyPage_83(byte[] pageResponse) => PrettifyPage_83(DecodePage_83(pageResponse)); - - public static string PrettifyPage_83(Page_83? modePage) - { - if(!modePage.HasValue) - return null; - - Page_83 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Device identification:"); - - if(page.Descriptors.Length == 0) + switch(descriptor.Type) { - sb.AppendLine("\tThere are no identifiers"); - - return sb.ToString(); - } - - foreach(IdentificatonDescriptor descriptor in page.Descriptors) - { - switch(descriptor.Association) - { - case IdentificationAssociation.LogicalUnit: - sb.AppendLine("\tIdentifier belongs to addressed logical unit"); - - break; - case IdentificationAssociation.TargetPort: - sb.AppendLine("\tIdentifier belongs to target port"); - - break; - case IdentificationAssociation.TargetDevice: - sb.AppendLine("\tIdentifier belongs to target device that contains the addressed logical unit"); - - break; - default: - sb.AppendFormat("\tIndentifier has unknown association with code {0}", - (byte)descriptor.Association).AppendLine(); - - break; - } - - if(descriptor.PIV) - { - string protocol; - - switch(descriptor.ProtocolIdentifier) + case IdentificationTypes.NoAuthority: + switch(descriptor.CodeSet) { - case ProtocolIdentifiers.ADT: - protocol = "Automation/Drive Interface Transport"; + case IdentificationCodeSet.ASCII: + case IdentificationCodeSet.UTF8: + sb.AppendFormat("\tVendor descriptor contains: {0}", descriptor.ASCII).AppendLine(); break; - case ProtocolIdentifiers.ATA: - protocol = "AT Attachment Interface (ATA/ATAPI)"; - - break; - case ProtocolIdentifiers.FibreChannel: - protocol = "Fibre Channel"; - - break; - case ProtocolIdentifiers.Firewire: - protocol = "IEEE 1394"; - - break; - case ProtocolIdentifiers.iSCSI: - protocol = "Internet SCSI"; - - break; - case ProtocolIdentifiers.NoProtocol: - protocol = "no specific"; - - break; - case ProtocolIdentifiers.PCIe: - protocol = "PCI Express"; - - break; - case ProtocolIdentifiers.RDMAP: - protocol = "SCSI Remote Direct Memory Access"; - - break; - case ProtocolIdentifiers.SAS: - protocol = "Serial Attachment SCSI"; - - break; - case ProtocolIdentifiers.SCSI: - protocol = "Parallel SCSI"; - - break; - case ProtocolIdentifiers.SCSIe: - protocol = "SCSI over PCI Express"; - - break; - case ProtocolIdentifiers.SSA: - protocol = "SSA"; - - break; - case ProtocolIdentifiers.UAS: - protocol = "USB Attached SCSI"; + case IdentificationCodeSet.Binary: + sb.AppendFormat("\tVendor descriptor contains binary data (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)).AppendLine(); break; default: - protocol = $"unknown code {(byte)descriptor.ProtocolIdentifier}"; + sb.AppendFormat("\tVendor descriptor contains unknown kind {1} of data (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.CodeSet).AppendLine(); break; } - sb.AppendFormat("\tDescriptor referes to {0} protocol", protocol).AppendLine(); - } + break; + case IdentificationTypes.Inquiry: + switch(descriptor.CodeSet) + { + case IdentificationCodeSet.ASCII: + case IdentificationCodeSet.UTF8: + sb.AppendFormat("\tInquiry descriptor contains: {0}", descriptor.ASCII).AppendLine(); - switch(descriptor.Type) - { - case IdentificationTypes.NoAuthority: - switch(descriptor.CodeSet) - { - case IdentificationCodeSet.ASCII: - case IdentificationCodeSet.UTF8: - sb.AppendFormat("\tVendor descriptor contains: {0}", descriptor.ASCII).AppendLine(); - - break; - case IdentificationCodeSet.Binary: - sb.AppendFormat("\tVendor descriptor contains binary data (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)).AppendLine(); - - break; - default: - sb.AppendFormat("\tVendor descriptor contains unknown kind {1} of data (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), - (byte)descriptor.CodeSet).AppendLine(); - - break; - } - - break; - case IdentificationTypes.Inquiry: - switch(descriptor.CodeSet) - { - case IdentificationCodeSet.ASCII: - case IdentificationCodeSet.UTF8: - sb.AppendFormat("\tInquiry descriptor contains: {0}", descriptor.ASCII).AppendLine(); - - break; - case IdentificationCodeSet.Binary: - sb.AppendFormat("\tInquiry descriptor contains binary data (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)).AppendLine(); - - break; - default: - sb.AppendFormat("\tInquiry descriptor contains unknown kind {1} of data (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), - (byte)descriptor.CodeSet).AppendLine(); - - break; - } - - break; - case IdentificationTypes.EUI: - if(descriptor.CodeSet == IdentificationCodeSet.ASCII || - descriptor.CodeSet == IdentificationCodeSet.UTF8) - sb.AppendFormat("\tIEEE EUI-64: {0}", descriptor.ASCII).AppendLine(); - else - { - sb.AppendFormat("\tIEEE EUI-64: {0:X2}", descriptor.Binary[0]); - - for(int i = 1; i < descriptor.Binary.Length; i++) - sb.AppendFormat(":{0:X2}", descriptor.Binary[i]); - - sb.AppendLine(); - } - - break; - case IdentificationTypes.NAA: - if(descriptor.CodeSet == IdentificationCodeSet.ASCII || - descriptor.CodeSet == IdentificationCodeSet.UTF8) - sb.AppendFormat("\tNAA: {0}", descriptor.ASCII).AppendLine(); - else - { - sb.AppendFormat("\tNAA: {0:X2}", descriptor.Binary[0]); - - for(int i = 1; i < descriptor.Binary.Length; i++) - sb.AppendFormat(":{0:X2}", descriptor.Binary[i]); - - sb.AppendLine(); - } - - break; - case IdentificationTypes.Relative: - if(descriptor.CodeSet == IdentificationCodeSet.ASCII || - descriptor.CodeSet == IdentificationCodeSet.UTF8) - sb.AppendFormat("\tRelative target port identifier: {0}", descriptor.ASCII).AppendLine(); - else - sb.AppendFormat("\tRelative target port identifier: {0}", - (descriptor.Binary[2] << 8) + descriptor.Binary[3]).AppendLine(); - - break; - case IdentificationTypes.TargetPortGroup: - if(descriptor.CodeSet == IdentificationCodeSet.ASCII || - descriptor.CodeSet == IdentificationCodeSet.UTF8) - sb.AppendFormat("\tTarget group identifier: {0}", descriptor.ASCII).AppendLine(); - else - sb.AppendFormat("\tTarget group identifier: {0}", - (descriptor.Binary[2] << 8) + descriptor.Binary[3]).AppendLine(); - - break; - case IdentificationTypes.LogicalUnitGroup: - if(descriptor.CodeSet == IdentificationCodeSet.ASCII || - descriptor.CodeSet == IdentificationCodeSet.UTF8) - sb.AppendFormat("\tLogical unit group identifier: {0}", descriptor.ASCII).AppendLine(); - else - sb.AppendFormat("\tLogical unit group identifier: {0}", - (descriptor.Binary[2] << 8) + descriptor.Binary[3]).AppendLine(); - - break; - case IdentificationTypes.MD5: - if(descriptor.CodeSet == IdentificationCodeSet.ASCII || - descriptor.CodeSet == IdentificationCodeSet.UTF8) - sb.AppendFormat("\tMD5 logical unit identifier: {0}", descriptor.ASCII).AppendLine(); - else - { - sb.AppendFormat("\tMD5 logical unit identifier: {0:x2}", descriptor.Binary[0]); - - for(int i = 1; i < descriptor.Binary.Length; i++) - sb.AppendFormat("{0:x2}", descriptor.Binary[i]); - - sb.AppendLine(); - } - - break; - case IdentificationTypes.SCSI: - if(descriptor.CodeSet == IdentificationCodeSet.ASCII || - descriptor.CodeSet == IdentificationCodeSet.UTF8) - sb.AppendFormat("\tSCSI name string identifier: {0}", descriptor.ASCII).AppendLine(); - else - sb.AppendFormat("\tSCSI name string identifier (hex): {0}", + break; + case IdentificationCodeSet.Binary: + sb.AppendFormat("\tInquiry descriptor contains binary data (hex): {0}", PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)).AppendLine(); - break; - case IdentificationTypes.ProtocolSpecific: - { - if(descriptor.PIV) - switch(descriptor.ProtocolIdentifier) - { - case ProtocolIdentifiers.ADT: - sb. - AppendFormat("\tProtocol (Automation/Drive Interface Transport) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); + break; + default: + sb.AppendFormat("\tInquiry descriptor contains unknown kind {1} of data (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.CodeSet).AppendLine(); - break; - case ProtocolIdentifiers.ATA: - sb. - AppendFormat("\tProtocol (ATA/ATAPI) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.FibreChannel: - sb. - AppendFormat("\tProtocol (Fibre Channel) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.Firewire: - sb. - AppendFormat("\tProtocol (IEEE 1394) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.iSCSI: - sb. - AppendFormat("\tProtocol (Internet SCSI) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.NoProtocol: - sb. - AppendFormat("\tProtocol (unknown) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.PCIe: - sb. - AppendFormat("\tProtocol (PCI Express) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.RDMAP: - sb. - AppendFormat("\tProtocol (SCSI Remote Direct Memory Access) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.SAS: - sb. - AppendFormat("\tProtocol (Serial Attachment SCSI) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.SCSI: - sb. - AppendFormat("\tProtocol (Parallel SCSI) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.SSA: - sb. - AppendFormat("\tProtocol (SSA) specific descriptor with unknown format (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - case ProtocolIdentifiers.SCSIe: - sb.AppendFormat("\tProtocol (SCSIe) specific descriptor: Routing ID is {0}", - (descriptor.Binary[0] << 8) + descriptor.Binary[1]).AppendLine(); - - break; - case ProtocolIdentifiers.UAS: - sb. - AppendFormat("\tProtocol (UAS) specific descriptor: USB address {0} interface {1}", - descriptor.Binary[0] & 0x7F, descriptor.Binary[2]).AppendLine(); - - break; - default: - sb. - AppendFormat("\tProtocol (unknown code {0}) specific descriptor with unknown format (hex): {1}", - (byte)descriptor.ProtocolIdentifier, - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). - AppendLine(); - - break; - } + break; } - break; - default: - switch(descriptor.CodeSet) + break; + case IdentificationTypes.EUI: + if(descriptor.CodeSet == IdentificationCodeSet.ASCII || + descriptor.CodeSet == IdentificationCodeSet.UTF8) + sb.AppendFormat("\tIEEE EUI-64: {0}", descriptor.ASCII).AppendLine(); + else + { + sb.AppendFormat("\tIEEE EUI-64: {0:X2}", descriptor.Binary[0]); + + for(int i = 1; i < descriptor.Binary.Length; i++) + sb.AppendFormat(":{0:X2}", descriptor.Binary[i]); + + sb.AppendLine(); + } + + break; + case IdentificationTypes.NAA: + if(descriptor.CodeSet == IdentificationCodeSet.ASCII || + descriptor.CodeSet == IdentificationCodeSet.UTF8) + sb.AppendFormat("\tNAA: {0}", descriptor.ASCII).AppendLine(); + else + { + sb.AppendFormat("\tNAA: {0:X2}", descriptor.Binary[0]); + + for(int i = 1; i < descriptor.Binary.Length; i++) + sb.AppendFormat(":{0:X2}", descriptor.Binary[i]); + + sb.AppendLine(); + } + + break; + case IdentificationTypes.Relative: + if(descriptor.CodeSet == IdentificationCodeSet.ASCII || + descriptor.CodeSet == IdentificationCodeSet.UTF8) + sb.AppendFormat("\tRelative target port identifier: {0}", descriptor.ASCII).AppendLine(); + else + sb.AppendFormat("\tRelative target port identifier: {0}", + (descriptor.Binary[2] << 8) + descriptor.Binary[3]).AppendLine(); + + break; + case IdentificationTypes.TargetPortGroup: + if(descriptor.CodeSet == IdentificationCodeSet.ASCII || + descriptor.CodeSet == IdentificationCodeSet.UTF8) + sb.AppendFormat("\tTarget group identifier: {0}", descriptor.ASCII).AppendLine(); + else + sb.AppendFormat("\tTarget group identifier: {0}", + (descriptor.Binary[2] << 8) + descriptor.Binary[3]).AppendLine(); + + break; + case IdentificationTypes.LogicalUnitGroup: + if(descriptor.CodeSet == IdentificationCodeSet.ASCII || + descriptor.CodeSet == IdentificationCodeSet.UTF8) + sb.AppendFormat("\tLogical unit group identifier: {0}", descriptor.ASCII).AppendLine(); + else + sb.AppendFormat("\tLogical unit group identifier: {0}", + (descriptor.Binary[2] << 8) + descriptor.Binary[3]).AppendLine(); + + break; + case IdentificationTypes.MD5: + if(descriptor.CodeSet == IdentificationCodeSet.ASCII || + descriptor.CodeSet == IdentificationCodeSet.UTF8) + sb.AppendFormat("\tMD5 logical unit identifier: {0}", descriptor.ASCII).AppendLine(); + else + { + sb.AppendFormat("\tMD5 logical unit identifier: {0:x2}", descriptor.Binary[0]); + + for(int i = 1; i < descriptor.Binary.Length; i++) + sb.AppendFormat("{0:x2}", descriptor.Binary[i]); + + sb.AppendLine(); + } + + break; + case IdentificationTypes.SCSI: + if(descriptor.CodeSet == IdentificationCodeSet.ASCII || + descriptor.CodeSet == IdentificationCodeSet.UTF8) + sb.AppendFormat("\tSCSI name string identifier: {0}", descriptor.ASCII).AppendLine(); + else + sb.AppendFormat("\tSCSI name string identifier (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)).AppendLine(); + + break; + case IdentificationTypes.ProtocolSpecific: + { + if(descriptor.PIV) + switch(descriptor.ProtocolIdentifier) { - case IdentificationCodeSet.ASCII: - case IdentificationCodeSet.UTF8: - sb.AppendFormat("\tUnknown descriptor type {1} contains: {0}", descriptor.ASCII, - (byte)descriptor.Type).AppendLine(); + case ProtocolIdentifiers.ADT: + sb. + AppendFormat("\tProtocol (Automation/Drive Interface Transport) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); break; - case IdentificationCodeSet.Binary: - sb.AppendFormat("\tUnknown descriptor type {1} contains binary data (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), - (byte)descriptor.Type).AppendLine(); + case ProtocolIdentifiers.ATA: + sb. + AppendFormat("\tProtocol (ATA/ATAPI) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.FibreChannel: + sb. + AppendFormat("\tProtocol (Fibre Channel) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.Firewire: + sb. + AppendFormat("\tProtocol (IEEE 1394) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.iSCSI: + sb. + AppendFormat("\tProtocol (Internet SCSI) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.NoProtocol: + sb. + AppendFormat("\tProtocol (unknown) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.PCIe: + sb. + AppendFormat("\tProtocol (PCI Express) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.RDMAP: + sb. + AppendFormat("\tProtocol (SCSI Remote Direct Memory Access) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.SAS: + sb. + AppendFormat("\tProtocol (Serial Attachment SCSI) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.SCSI: + sb. + AppendFormat("\tProtocol (Parallel SCSI) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.SSA: + sb. + AppendFormat("\tProtocol (SSA) specific descriptor with unknown format (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); + + break; + case ProtocolIdentifiers.SCSIe: + sb.AppendFormat("\tProtocol (SCSIe) specific descriptor: Routing ID is {0}", + (descriptor.Binary[0] << 8) + descriptor.Binary[1]).AppendLine(); + + break; + case ProtocolIdentifiers.UAS: + sb. + AppendFormat("\tProtocol (UAS) specific descriptor: USB address {0} interface {1}", + descriptor.Binary[0] & 0x7F, descriptor.Binary[2]).AppendLine(); break; default: sb. - AppendFormat("Inquiry descriptor type {2} contains unknown kind {1} of data (hex): {0}", - PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), - (byte)descriptor.CodeSet, (byte)descriptor.Type).AppendLine(); + AppendFormat("\tProtocol (unknown code {0}) specific descriptor with unknown format (hex): {1}", + (byte)descriptor.ProtocolIdentifier, + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40)). + AppendLine(); break; } - - break; - } - } - - return sb.ToString(); - } - #endregion EVPD Page 0x83: Device identification page - - #region EVPD Page 0x84: Software Interface Identification page - public struct SoftwareIdentifier - { - /// EUI-48 identifier - public byte[] Identifier; - } - - /// Software Interface Identification page Page code 0x84 - public struct Page_84 - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - /// The descriptors. - public SoftwareIdentifier[] Identifiers; - } - - public static Page_84? DecodePage_84(byte[] pageResponse) - { - if(pageResponse?[1] != 0x84) - return null; - - if(pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 10) - return null; - - var decoded = new Page_84 - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4) - }; - - int position = 4; - List identifiers = new List(); - - while(position < pageResponse.Length) - { - var identifier = new SoftwareIdentifier - { - Identifier = new byte[6] - }; - - Array.Copy(pageResponse, position, identifier.Identifier, 0, 6); - identifiers.Add(identifier); - position += 6; - } - - decoded.Identifiers = identifiers.ToArray(); - - return decoded; - } - - public static string PrettifyPage_84(byte[] pageResponse) => PrettifyPage_84(DecodePage_84(pageResponse)); - - public static string PrettifyPage_84(Page_84? modePage) - { - if(!modePage.HasValue) - return null; - - Page_84 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Software Interface Identifiers:"); - - if(page.Identifiers.Length == 0) - { - sb.AppendLine("\tThere are no identifiers"); - - return sb.ToString(); - } - - foreach(SoftwareIdentifier identifier in page.Identifiers) - { - sb.AppendFormat("\t{0:X2}", identifier.Identifier[0]); - - for(int i = 1; i < identifier.Identifier.Length; i++) - sb.AppendFormat(":{0:X2}", identifier.Identifier[i]); - - sb.AppendLine(); - } - - return sb.ToString(); - } - #endregion EVPD Page 0x84: Software Interface Identification page - - #region EVPD Page 0x85: Management Network Addresses page - public enum NetworkServiceTypes : byte - { - Unspecified = 0, StorageConf = 1, Diagnostics = 2, - Status = 3, Logging = 4, CodeDownload = 5, - CopyService = 6, Administrative = 7 - } - - public struct NetworkDescriptor - { - /// Identifies which device the identifier associates with - public IdentificationAssociation Association; - /// Defines the type of the identifier - public NetworkServiceTypes Type; - /// Length of the identifier - public ushort Length; - /// Binary identifier - public byte[] Address; - } - - /// Device identification page Page code 0x85 - public struct Page_85 - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public ushort PageLength; - /// The descriptors. - public NetworkDescriptor[] Descriptors; - } - - public static Page_85? DecodePage_85(byte[] pageResponse) - { - if(pageResponse?[1] != 0x85) - return null; - - if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 4) - return null; - - var decoded = new Page_85 - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4) - }; - - int position = 4; - List descriptors = new List(); - - while(position < pageResponse.Length) - { - var descriptor = new NetworkDescriptor - { - Association = (IdentificationAssociation)((pageResponse[position] & 0x60) >> 5), - Type = (NetworkServiceTypes)(pageResponse[position] & 0x1F), - Length = (ushort)((pageResponse[position + 2] << 8) + pageResponse[position + 3]) - }; - - descriptor.Address = new byte[descriptor.Length]; - Array.Copy(pageResponse, position + 4, descriptor.Address, 0, descriptor.Length); - - position += 4 + descriptor.Length; - descriptors.Add(descriptor); - } - - decoded.Descriptors = descriptors.ToArray(); - - return decoded; - } - - public static string PrettifyPage_85(byte[] pageResponse) => PrettifyPage_85(DecodePage_85(pageResponse)); - - public static string PrettifyPage_85(Page_85? modePage) - { - if(!modePage.HasValue) - return null; - - Page_85 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Management Network Addresses:"); - - if(page.Descriptors.Length == 0) - { - sb.AppendLine("\tThere are no addresses"); - - return sb.ToString(); - } - - foreach(NetworkDescriptor descriptor in page.Descriptors) - { - switch(descriptor.Association) - { - case IdentificationAssociation.LogicalUnit: - sb.AppendLine("\tIdentifier belongs to addressed logical unit"); - - break; - case IdentificationAssociation.TargetPort: - sb.AppendLine("\tIdentifier belongs to target port"); - - break; - case IdentificationAssociation.TargetDevice: - sb.AppendLine("\tIdentifier belongs to target device that contains the addressed logical unit"); - - break; - default: - sb.AppendFormat("\tIndentifier has unknown association with code {0}", - (byte)descriptor.Association).AppendLine(); - - break; } - switch(descriptor.Type) - { - case NetworkServiceTypes.CodeDownload: - sb.AppendFormat("Address for code download: {0}", StringHandlers.CToString(descriptor.Address)). - AppendLine(); - - break; - case NetworkServiceTypes.Diagnostics: - sb.AppendFormat("Address for diagnostics: {0}", StringHandlers.CToString(descriptor.Address)). - AppendLine(); - - break; - case NetworkServiceTypes.Logging: - sb.AppendFormat("Address for logging: {0}", StringHandlers.CToString(descriptor.Address)). - AppendLine(); - - break; - case NetworkServiceTypes.Status: - sb.AppendFormat("Address for status: {0}", StringHandlers.CToString(descriptor.Address)). - AppendLine(); - - break; - case NetworkServiceTypes.StorageConf: - sb.AppendFormat("Address for storage configuration service: {0}", - StringHandlers.CToString(descriptor.Address)).AppendLine(); - - break; - case NetworkServiceTypes.Unspecified: - sb.AppendFormat("Unspecified address: {0}", StringHandlers.CToString(descriptor.Address)). - AppendLine(); - - break; - case NetworkServiceTypes.CopyService: - sb.AppendFormat("Address for copy service: {0}", StringHandlers.CToString(descriptor.Address)). - AppendLine(); - - break; - case NetworkServiceTypes.Administrative: - sb.AppendFormat("Address for administrative configuration service: {0}", - StringHandlers.CToString(descriptor.Address)).AppendLine(); - - break; - default: - sb.AppendFormat("Address of unknown type {1}: {0}", - StringHandlers.CToString(descriptor.Address), (byte)descriptor.Type). - AppendLine(); - - break; - } - } - - return sb.ToString(); - } - #endregion EVPD Page 0x85: Management Network Addresses page - - #region EVPD Page 0x86: Extended INQUIRY data page - /// Device identification page Page code 0x86 - public struct Page_86 - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - /// Indicates how a device server activates microcode - public byte ActivateMicrocode; - /// Protection types supported by device - public byte SPT; - /// Checks logical block guard field - public bool GRD_CHK; - /// Checks logical block application tag - public bool APP_CHK; - /// Checks logical block reference - public bool REF_CHK; - /// Supports unit attention condition sense key specific data - public bool UASK_SUP; - /// Supports grouping - public bool GROUP_SUP; - /// Supports priority - public bool PRIOR_SUP; - /// Supports head of queue - public bool HEADSUP; - /// Supports ordered - public bool ORDSUP; - /// Supports simple - public bool SIMPSUP; - /// Supports marking a block as uncorrectable - public bool WU_SUP; - /// Supports disabling correction on WRITE LONG - public bool CRD_SUP; - /// Supports a non-volatile cache - public bool NV_SUP; - /// Supports a volatile cache - public bool V_SUP; - /// Disable protection information checks - public bool NO_PI_CHK; - /// Protection information interval supported - public bool P_I_I_SUP; - /// Clears all LUNs unit attention when clearing one - public bool LUICLR; - /// Referrals support - public bool R_SUP; - /// History snapshots release effects - public bool HSSRELEF; - /// Capability based command security - public bool CBCS; - /// Indicates how it handles microcode updating with multiple nexuxes - public byte Nexus; - /// Time to complete extended self-test - public ushort ExtendedTestMinutes; - /// Power on activation support - public bool POA_SUP; - /// Hard reset actication - public bool HRA_SUP; - /// Vendor specific activation - public bool VSA_SUP; - /// Maximum length in bytes of sense data - public byte MaximumSenseLength; - } - - public static Page_86? DecodePage_86(byte[] pageResponse) - { - if(pageResponse?[1] != 0x86) - return null; - - if(pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 64) - return null; - - return new Page_86 - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - ActivateMicrocode = (byte)((pageResponse[4] & 0xC0) >> 6), - SPT = (byte)((pageResponse[4] & 0x38) >> 3), - GRD_CHK = (pageResponse[4] & 0x04) == 0x04, - APP_CHK = (pageResponse[4] & 0x02) == 0x02, - REF_CHK = (pageResponse[4] & 0x01) == 0x01, - UASK_SUP = (pageResponse[5] & 0x20) == 0x20, - GROUP_SUP = (pageResponse[5] & 0x10) == 0x10, - PRIOR_SUP = (pageResponse[5] & 0x08) == 0x08, - HEADSUP = (pageResponse[5] & 0x04) == 0x04, - ORDSUP = (pageResponse[5] & 0x02) == 0x02, - SIMPSUP = (pageResponse[5] & 0x01) == 0x01, - WU_SUP = (pageResponse[6] & 0x08) == 0x08, - CRD_SUP = (pageResponse[6] & 0x04) == 0x04, - NV_SUP = (pageResponse[6] & 0x02) == 0x02, - V_SUP = (pageResponse[6] & 0x01) == 0x01, - NO_PI_CHK = (pageResponse[7] & 0x20) == 0x20, - P_I_I_SUP = (pageResponse[7] & 0x10) == 0x10, - LUICLR = (pageResponse[7] & 0x01) == 0x01, - R_SUP = (pageResponse[8] & 0x10) == 0x10, - HSSRELEF = (pageResponse[8] & 0x02) == 0x02, - CBCS = (pageResponse[8] & 0x01) == 0x01, - Nexus = (byte)(pageResponse[9] & 0x0F), - ExtendedTestMinutes = (ushort)((pageResponse[10] << 8) + pageResponse[11]), - POA_SUP = (pageResponse[12] & 0x80) == 0x80, - HRA_SUP = (pageResponse[12] & 0x40) == 0x40, - VSA_SUP = (pageResponse[12] & 0x20) == 0x20, - MaximumSenseLength = pageResponse[13] - }; - } - - public static string PrettifyPage_86(byte[] pageResponse) => PrettifyPage_86(DecodePage_86(pageResponse)); - - public static string PrettifyPage_86(Page_86? modePage) - { - if(!modePage.HasValue) - return null; - - Page_86 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Extended INQUIRY Data:"); - - switch(page.PeripheralDeviceType) - { - case PeripheralDeviceTypes.DirectAccess: - case PeripheralDeviceTypes.SCSIZonedBlockDevice: - switch(page.SPT) + break; + default: + switch(descriptor.CodeSet) { - case 0: - sb.AppendLine("Logical unit supports type 1 protection"); + case IdentificationCodeSet.ASCII: + case IdentificationCodeSet.UTF8: + sb.AppendFormat("\tUnknown descriptor type {1} contains: {0}", descriptor.ASCII, + (byte)descriptor.Type).AppendLine(); break; - case 1: - sb.AppendLine("Logical unit supports types 1 and 2 protection"); - - break; - case 2: - sb.AppendLine("Logical unit supports type 2 protection"); - - break; - case 3: - sb.AppendLine("Logical unit supports types 1 and 3 protection"); - - break; - case 4: - sb.AppendLine("Logical unit supports type 3 protection"); - - break; - case 5: - sb.AppendLine("Logical unit supports types 2 and 3 protection"); - - break; - case 7: - sb.AppendLine("Logical unit supports types 1, 2 and 3 protection"); + case IdentificationCodeSet.Binary: + sb.AppendFormat("\tUnknown descriptor type {1} contains binary data (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.Type).AppendLine(); break; default: - sb.AppendFormat("Logical unit supports unknown protection defined by code {0}", page.SPT). - AppendLine(); + sb. + AppendFormat("Inquiry descriptor type {2} contains unknown kind {1} of data (hex): {0}", + PrintHex.ByteArrayToHexArrayString(descriptor.Binary, 40), + (byte)descriptor.CodeSet, (byte)descriptor.Type).AppendLine(); break; } break; - case PeripheralDeviceTypes.SequentialAccess when page.SPT == 1: - sb.AppendLine("Logical unit supports logical block protection"); + } + } + + return sb.ToString(); + } + #endregion EVPD Page 0x83: Device identification page + + #region EVPD Page 0x84: Software Interface Identification page + public struct SoftwareIdentifier + { + /// EUI-48 identifier + public byte[] Identifier; + } + + /// Software Interface Identification page Page code 0x84 + public struct Page_84 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// The descriptors. + public SoftwareIdentifier[] Identifiers; + } + + public static Page_84? DecodePage_84(byte[] pageResponse) + { + if(pageResponse?[1] != 0x84) + return null; + + if(pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 10) + return null; + + var decoded = new Page_84 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4) + }; + + int position = 4; + List identifiers = new List(); + + while(position < pageResponse.Length) + { + var identifier = new SoftwareIdentifier + { + Identifier = new byte[6] + }; + + Array.Copy(pageResponse, position, identifier.Identifier, 0, 6); + identifiers.Add(identifier); + position += 6; + } + + decoded.Identifiers = identifiers.ToArray(); + + return decoded; + } + + public static string PrettifyPage_84(byte[] pageResponse) => PrettifyPage_84(DecodePage_84(pageResponse)); + + public static string PrettifyPage_84(Page_84? modePage) + { + if(!modePage.HasValue) + return null; + + Page_84 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Software Interface Identifiers:"); + + if(page.Identifiers.Length == 0) + { + sb.AppendLine("\tThere are no identifiers"); + + return sb.ToString(); + } + + foreach(SoftwareIdentifier identifier in page.Identifiers) + { + sb.AppendFormat("\t{0:X2}", identifier.Identifier[0]); + + for(int i = 1; i < identifier.Identifier.Length; i++) + sb.AppendFormat(":{0:X2}", identifier.Identifier[i]); + + sb.AppendLine(); + } + + return sb.ToString(); + } + #endregion EVPD Page 0x84: Software Interface Identification page + + #region EVPD Page 0x85: Management Network Addresses page + public enum NetworkServiceTypes : byte + { + Unspecified = 0, StorageConf = 1, Diagnostics = 2, + Status = 3, Logging = 4, CodeDownload = 5, + CopyService = 6, Administrative = 7 + } + + public struct NetworkDescriptor + { + /// Identifies which device the identifier associates with + public IdentificationAssociation Association; + /// Defines the type of the identifier + public NetworkServiceTypes Type; + /// Length of the identifier + public ushort Length; + /// Binary identifier + public byte[] Address; + } + + /// Device identification page Page code 0x85 + public struct Page_85 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public ushort PageLength; + /// The descriptors. + public NetworkDescriptor[] Descriptors; + } + + public static Page_85? DecodePage_85(byte[] pageResponse) + { + if(pageResponse?[1] != 0x85) + return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 4) + return null; + + var decoded = new Page_85 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4) + }; + + int position = 4; + List descriptors = new List(); + + while(position < pageResponse.Length) + { + var descriptor = new NetworkDescriptor + { + Association = (IdentificationAssociation)((pageResponse[position] & 0x60) >> 5), + Type = (NetworkServiceTypes)(pageResponse[position] & 0x1F), + Length = (ushort)((pageResponse[position + 2] << 8) + pageResponse[position + 3]) + }; + + descriptor.Address = new byte[descriptor.Length]; + Array.Copy(pageResponse, position + 4, descriptor.Address, 0, descriptor.Length); + + position += 4 + descriptor.Length; + descriptors.Add(descriptor); + } + + decoded.Descriptors = descriptors.ToArray(); + + return decoded; + } + + public static string PrettifyPage_85(byte[] pageResponse) => PrettifyPage_85(DecodePage_85(pageResponse)); + + public static string PrettifyPage_85(Page_85? modePage) + { + if(!modePage.HasValue) + return null; + + Page_85 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Management Network Addresses:"); + + if(page.Descriptors.Length == 0) + { + sb.AppendLine("\tThere are no addresses"); + + return sb.ToString(); + } + + foreach(NetworkDescriptor descriptor in page.Descriptors) + { + switch(descriptor.Association) + { + case IdentificationAssociation.LogicalUnit: + sb.AppendLine("\tIdentifier belongs to addressed logical unit"); + + break; + case IdentificationAssociation.TargetPort: + sb.AppendLine("\tIdentifier belongs to target port"); + + break; + case IdentificationAssociation.TargetDevice: + sb.AppendLine("\tIdentifier belongs to target device that contains the addressed logical unit"); + + break; + default: + sb.AppendFormat("\tIndentifier has unknown association with code {0}", + (byte)descriptor.Association).AppendLine(); break; } - if(page.GRD_CHK) - sb.AppendLine("Device checks the logical block guard"); - - if(page.APP_CHK) - sb.AppendLine("Device checks the logical block application tag"); - - if(page.REF_CHK) - sb.AppendLine("Device checks the logical block reference tag"); - - if(page.UASK_SUP) - sb.AppendLine("Device supports unit attention condition sense key specific data"); - - if(page.GROUP_SUP) - sb.AppendLine("Device supports grouping"); - - if(page.PRIOR_SUP) - sb.AppendLine("Device supports priority"); - - if(page.HEADSUP) - sb.AppendLine("Device supports head of queue"); - - if(page.ORDSUP) - sb.AppendLine("Device supports the ORDERED task attribute"); - - if(page.SIMPSUP) - sb.AppendLine("Device supports the SIMPLE task attribute"); - - if(page.WU_SUP) - sb.AppendLine("Device supports marking a block as uncorrectable with WRITE LONG"); - - if(page.CRD_SUP) - sb.AppendLine("Device supports disabling correction with WRITE LONG"); - - if(page.NV_SUP) - sb.AppendLine("Device has a non-volatile cache"); - - if(page.V_SUP) - sb.AppendLine("Device has a volatile cache"); - - if(page.NO_PI_CHK) - sb.AppendLine("Device has disabled protection information checks"); - - if(page.P_I_I_SUP) - sb.AppendLine("Device supports protection information intervals"); - - if(page.LUICLR) - sb.AppendLine("Device clears any unit attention condition in all LUNs after reporting for any LUN"); - - if(page.R_SUP) - sb.AppendLine("Device supports referrals"); - - if(page.HSSRELEF) - sb.AppendLine("Devoce implements alternate reset handling"); - - if(page.CBCS) - sb.AppendLine("Device supports capability-based command security"); - - if(page.POA_SUP) - sb.AppendLine("Device supports power-on activation for new microcode"); - - if(page.HRA_SUP) - sb.AppendLine("Device supports hard reset activation for new microcode"); - - if(page.VSA_SUP) - sb.AppendLine("Device supports vendor specific activation for new microcode"); - - if(page.ExtendedTestMinutes > 0) - sb.AppendFormat("Extended self-test takes {0} to complete", - TimeSpan.FromMinutes(page.ExtendedTestMinutes)).AppendLine(); - - if(page.MaximumSenseLength > 0) - sb.AppendFormat("Device supports a maximum of {0} bytes for sense data", page.MaximumSenseLength). - AppendLine(); - - return sb.ToString(); - } - #endregion EVPD Page 0x86: Extended INQUIRY data page - - #region EVPD Page 0x89: ATA Information page - /// ATA Information page Page code 0x89 - public struct Page_89 - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public ushort PageLength; - /// Contains the SAT vendor identification - public byte[] VendorIdentification; - /// Contains the SAT product identification - public byte[] ProductIdentification; - /// Contains the SAT revision level - public byte[] ProductRevisionLevel; - /// Contains the ATA device signature - public byte[] Signature; - /// Contains the command code used to identify the device - public byte CommandCode; - /// Contains the response to ATA IDENTIFY (PACKET) DEVICE - public byte[] IdentifyData; - } - - public static Page_89? DecodePage_89(byte[] pageResponse) - { - if(pageResponse?[1] != 0x89) - return null; - - if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 572) - return null; - - var decoded = new Page_89 + switch(descriptor.Type) { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4), - VendorIdentification = new byte[8], - ProductIdentification = new byte[16], - ProductRevisionLevel = new byte[4], - Signature = new byte[20], - IdentifyData = new byte[512] - }; + case NetworkServiceTypes.CodeDownload: + sb.AppendFormat("Address for code download: {0}", StringHandlers.CToString(descriptor.Address)). + AppendLine(); - Array.Copy(pageResponse, 8, decoded.VendorIdentification, 0, 8); - Array.Copy(pageResponse, 16, decoded.ProductIdentification, 0, 16); - Array.Copy(pageResponse, 32, decoded.ProductRevisionLevel, 0, 4); - Array.Copy(pageResponse, 36, decoded.Signature, 0, 20); - decoded.CommandCode = pageResponse[56]; - Array.Copy(pageResponse, 60, decoded.IdentifyData, 0, 512); + break; + case NetworkServiceTypes.Diagnostics: + sb.AppendFormat("Address for diagnostics: {0}", StringHandlers.CToString(descriptor.Address)). + AppendLine(); - return decoded; + break; + case NetworkServiceTypes.Logging: + sb.AppendFormat("Address for logging: {0}", StringHandlers.CToString(descriptor.Address)). + AppendLine(); + + break; + case NetworkServiceTypes.Status: + sb.AppendFormat("Address for status: {0}", StringHandlers.CToString(descriptor.Address)). + AppendLine(); + + break; + case NetworkServiceTypes.StorageConf: + sb.AppendFormat("Address for storage configuration service: {0}", + StringHandlers.CToString(descriptor.Address)).AppendLine(); + + break; + case NetworkServiceTypes.Unspecified: + sb.AppendFormat("Unspecified address: {0}", StringHandlers.CToString(descriptor.Address)). + AppendLine(); + + break; + case NetworkServiceTypes.CopyService: + sb.AppendFormat("Address for copy service: {0}", StringHandlers.CToString(descriptor.Address)). + AppendLine(); + + break; + case NetworkServiceTypes.Administrative: + sb.AppendFormat("Address for administrative configuration service: {0}", + StringHandlers.CToString(descriptor.Address)).AppendLine(); + + break; + default: + sb.AppendFormat("Address of unknown type {1}: {0}", + StringHandlers.CToString(descriptor.Address), (byte)descriptor.Type). + AppendLine(); + + break; + } } - public static string PrettifyPage_89(byte[] pageResponse) => PrettifyPage_89(DecodePage_89(pageResponse)); + return sb.ToString(); + } + #endregion EVPD Page 0x85: Management Network Addresses page - // TODO: Decode ATA signature? - public static string PrettifyPage_89(Page_89? modePage) + #region EVPD Page 0x86: Extended INQUIRY data page + /// Device identification page Page code 0x86 + public struct Page_86 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Indicates how a device server activates microcode + public byte ActivateMicrocode; + /// Protection types supported by device + public byte SPT; + /// Checks logical block guard field + public bool GRD_CHK; + /// Checks logical block application tag + public bool APP_CHK; + /// Checks logical block reference + public bool REF_CHK; + /// Supports unit attention condition sense key specific data + public bool UASK_SUP; + /// Supports grouping + public bool GROUP_SUP; + /// Supports priority + public bool PRIOR_SUP; + /// Supports head of queue + public bool HEADSUP; + /// Supports ordered + public bool ORDSUP; + /// Supports simple + public bool SIMPSUP; + /// Supports marking a block as uncorrectable + public bool WU_SUP; + /// Supports disabling correction on WRITE LONG + public bool CRD_SUP; + /// Supports a non-volatile cache + public bool NV_SUP; + /// Supports a volatile cache + public bool V_SUP; + /// Disable protection information checks + public bool NO_PI_CHK; + /// Protection information interval supported + public bool P_I_I_SUP; + /// Clears all LUNs unit attention when clearing one + public bool LUICLR; + /// Referrals support + public bool R_SUP; + /// History snapshots release effects + public bool HSSRELEF; + /// Capability based command security + public bool CBCS; + /// Indicates how it handles microcode updating with multiple nexuxes + public byte Nexus; + /// Time to complete extended self-test + public ushort ExtendedTestMinutes; + /// Power on activation support + public bool POA_SUP; + /// Hard reset actication + public bool HRA_SUP; + /// Vendor specific activation + public bool VSA_SUP; + /// Maximum length in bytes of sense data + public byte MaximumSenseLength; + } + + public static Page_86? DecodePage_86(byte[] pageResponse) + { + if(pageResponse?[1] != 0x86) + return null; + + if(pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 64) + return null; + + return new Page_86 { - if(!modePage.HasValue) - return null; + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + ActivateMicrocode = (byte)((pageResponse[4] & 0xC0) >> 6), + SPT = (byte)((pageResponse[4] & 0x38) >> 3), + GRD_CHK = (pageResponse[4] & 0x04) == 0x04, + APP_CHK = (pageResponse[4] & 0x02) == 0x02, + REF_CHK = (pageResponse[4] & 0x01) == 0x01, + UASK_SUP = (pageResponse[5] & 0x20) == 0x20, + GROUP_SUP = (pageResponse[5] & 0x10) == 0x10, + PRIOR_SUP = (pageResponse[5] & 0x08) == 0x08, + HEADSUP = (pageResponse[5] & 0x04) == 0x04, + ORDSUP = (pageResponse[5] & 0x02) == 0x02, + SIMPSUP = (pageResponse[5] & 0x01) == 0x01, + WU_SUP = (pageResponse[6] & 0x08) == 0x08, + CRD_SUP = (pageResponse[6] & 0x04) == 0x04, + NV_SUP = (pageResponse[6] & 0x02) == 0x02, + V_SUP = (pageResponse[6] & 0x01) == 0x01, + NO_PI_CHK = (pageResponse[7] & 0x20) == 0x20, + P_I_I_SUP = (pageResponse[7] & 0x10) == 0x10, + LUICLR = (pageResponse[7] & 0x01) == 0x01, + R_SUP = (pageResponse[8] & 0x10) == 0x10, + HSSRELEF = (pageResponse[8] & 0x02) == 0x02, + CBCS = (pageResponse[8] & 0x01) == 0x01, + Nexus = (byte)(pageResponse[9] & 0x0F), + ExtendedTestMinutes = (ushort)((pageResponse[10] << 8) + pageResponse[11]), + POA_SUP = (pageResponse[12] & 0x80) == 0x80, + HRA_SUP = (pageResponse[12] & 0x40) == 0x40, + VSA_SUP = (pageResponse[12] & 0x20) == 0x20, + MaximumSenseLength = pageResponse[13] + }; + } - Page_89 page = modePage.Value; - var sb = new StringBuilder(); + public static string PrettifyPage_86(byte[] pageResponse) => PrettifyPage_86(DecodePage_86(pageResponse)); - sb.AppendLine("SCSI to ATA Translation Layer Data:"); + public static string PrettifyPage_86(Page_86? modePage) + { + if(!modePage.HasValue) + return null; - sb.AppendFormat("\tTranslation layer vendor: {0}", - VendorString.Prettify(StringHandlers.CToString(page.VendorIdentification).Trim())). + Page_86 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Extended INQUIRY Data:"); + + switch(page.PeripheralDeviceType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.SCSIZonedBlockDevice: + switch(page.SPT) + { + case 0: + sb.AppendLine("Logical unit supports type 1 protection"); + + break; + case 1: + sb.AppendLine("Logical unit supports types 1 and 2 protection"); + + break; + case 2: + sb.AppendLine("Logical unit supports type 2 protection"); + + break; + case 3: + sb.AppendLine("Logical unit supports types 1 and 3 protection"); + + break; + case 4: + sb.AppendLine("Logical unit supports type 3 protection"); + + break; + case 5: + sb.AppendLine("Logical unit supports types 2 and 3 protection"); + + break; + case 7: + sb.AppendLine("Logical unit supports types 1, 2 and 3 protection"); + + break; + default: + sb.AppendFormat("Logical unit supports unknown protection defined by code {0}", page.SPT). + AppendLine(); + + break; + } + + break; + case PeripheralDeviceTypes.SequentialAccess when page.SPT == 1: + sb.AppendLine("Logical unit supports logical block protection"); + + break; + } + + if(page.GRD_CHK) + sb.AppendLine("Device checks the logical block guard"); + + if(page.APP_CHK) + sb.AppendLine("Device checks the logical block application tag"); + + if(page.REF_CHK) + sb.AppendLine("Device checks the logical block reference tag"); + + if(page.UASK_SUP) + sb.AppendLine("Device supports unit attention condition sense key specific data"); + + if(page.GROUP_SUP) + sb.AppendLine("Device supports grouping"); + + if(page.PRIOR_SUP) + sb.AppendLine("Device supports priority"); + + if(page.HEADSUP) + sb.AppendLine("Device supports head of queue"); + + if(page.ORDSUP) + sb.AppendLine("Device supports the ORDERED task attribute"); + + if(page.SIMPSUP) + sb.AppendLine("Device supports the SIMPLE task attribute"); + + if(page.WU_SUP) + sb.AppendLine("Device supports marking a block as uncorrectable with WRITE LONG"); + + if(page.CRD_SUP) + sb.AppendLine("Device supports disabling correction with WRITE LONG"); + + if(page.NV_SUP) + sb.AppendLine("Device has a non-volatile cache"); + + if(page.V_SUP) + sb.AppendLine("Device has a volatile cache"); + + if(page.NO_PI_CHK) + sb.AppendLine("Device has disabled protection information checks"); + + if(page.P_I_I_SUP) + sb.AppendLine("Device supports protection information intervals"); + + if(page.LUICLR) + sb.AppendLine("Device clears any unit attention condition in all LUNs after reporting for any LUN"); + + if(page.R_SUP) + sb.AppendLine("Device supports referrals"); + + if(page.HSSRELEF) + sb.AppendLine("Devoce implements alternate reset handling"); + + if(page.CBCS) + sb.AppendLine("Device supports capability-based command security"); + + if(page.POA_SUP) + sb.AppendLine("Device supports power-on activation for new microcode"); + + if(page.HRA_SUP) + sb.AppendLine("Device supports hard reset activation for new microcode"); + + if(page.VSA_SUP) + sb.AppendLine("Device supports vendor specific activation for new microcode"); + + if(page.ExtendedTestMinutes > 0) + sb.AppendFormat("Extended self-test takes {0} to complete", + TimeSpan.FromMinutes(page.ExtendedTestMinutes)).AppendLine(); + + if(page.MaximumSenseLength > 0) + sb.AppendFormat("Device supports a maximum of {0} bytes for sense data", page.MaximumSenseLength). AppendLine(); - sb.AppendFormat("\tTranslation layer name: {0}", - StringHandlers.CToString(page.ProductIdentification).Trim()).AppendLine(); + return sb.ToString(); + } + #endregion EVPD Page 0x86: Extended INQUIRY data page - sb.AppendFormat("\tTranslation layer release level: {0}", - StringHandlers.CToString(page.ProductRevisionLevel).Trim()).AppendLine(); + #region EVPD Page 0x89: ATA Information page + /// ATA Information page Page code 0x89 + public struct Page_89 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public ushort PageLength; + /// Contains the SAT vendor identification + public byte[] VendorIdentification; + /// Contains the SAT product identification + public byte[] ProductIdentification; + /// Contains the SAT revision level + public byte[] ProductRevisionLevel; + /// Contains the ATA device signature + public byte[] Signature; + /// Contains the command code used to identify the device + public byte CommandCode; + /// Contains the response to ATA IDENTIFY (PACKET) DEVICE + public byte[] IdentifyData; + } - switch(page.CommandCode) + public static Page_89? DecodePage_89(byte[] pageResponse) + { + if(pageResponse?[1] != 0x89) + return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 572) + return null; + + var decoded = new Page_89 + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4), + VendorIdentification = new byte[8], + ProductIdentification = new byte[16], + ProductRevisionLevel = new byte[4], + Signature = new byte[20], + IdentifyData = new byte[512] + }; + + Array.Copy(pageResponse, 8, decoded.VendorIdentification, 0, 8); + Array.Copy(pageResponse, 16, decoded.ProductIdentification, 0, 16); + Array.Copy(pageResponse, 32, decoded.ProductRevisionLevel, 0, 4); + Array.Copy(pageResponse, 36, decoded.Signature, 0, 20); + decoded.CommandCode = pageResponse[56]; + Array.Copy(pageResponse, 60, decoded.IdentifyData, 0, 512); + + return decoded; + } + + public static string PrettifyPage_89(byte[] pageResponse) => PrettifyPage_89(DecodePage_89(pageResponse)); + + // TODO: Decode ATA signature? + public static string PrettifyPage_89(Page_89? modePage) + { + if(!modePage.HasValue) + return null; + + Page_89 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI to ATA Translation Layer Data:"); + + sb.AppendFormat("\tTranslation layer vendor: {0}", + VendorString.Prettify(StringHandlers.CToString(page.VendorIdentification).Trim())). + AppendLine(); + + sb.AppendFormat("\tTranslation layer name: {0}", + StringHandlers.CToString(page.ProductIdentification).Trim()).AppendLine(); + + sb.AppendFormat("\tTranslation layer release level: {0}", + StringHandlers.CToString(page.ProductRevisionLevel).Trim()).AppendLine(); + + switch(page.CommandCode) + { + case 0xEC: + sb.AppendLine("\tDevice responded to ATA IDENTIFY DEVICE command."); + + break; + case 0xA1: + sb.AppendLine("\tDevice responded to ATA IDENTIFY PACKET DEVICE command."); + + break; + default: + sb.AppendFormat("\tDevice responded to ATA command {0:X2}h", page.CommandCode).AppendLine(); + + break; + } + + switch(page.Signature[0]) + { + case 0x00: + sb.AppendLine("\tDevice uses Parallel ATA."); + + break; + case 0x34: + sb.AppendLine("\tDevice uses Serial ATA."); + + break; + default: + sb.AppendFormat("\tDevice uses unknown transport with code {0}", page.Signature[0]).AppendLine(); + + break; + } + + Identify.IdentifyDevice? id = Identify.Decode(page.IdentifyData); + + if(id != null) + { + sb.AppendLine("\tATA IDENTIFY information follows:"); + sb.AppendFormat("{0}", ATA.Identify.Prettify(id)).AppendLine(); + } + else + sb.AppendLine("\tCould not decode ATA IDENTIFY information"); + + return sb.ToString(); + } + #endregion EVPD Page 0x89: ATA Information page + + #region EVPD Page 0xC0 (Quantum): Firmware Build Information page + /// Firmware Build Information page Page code 0xC0 (Quantum) + public struct Page_C0_Quantum + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Servo firmware checksum + public ushort ServoFirmwareChecksum; + /// Servo EEPROM checksum + public ushort ServoEEPROMChecksum; + /// Read/Write firmware checksum + public uint ReadWriteFirmwareChecksum; + /// Read/Write firmware build data + public byte[] ReadWriteFirmwareBuildData; + } + + public static Page_C0_Quantum? DecodePage_C0_Quantum(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC0) + return null; + + if(pageResponse[3] != 20) + return null; + + if(pageResponse.Length != 36) + return null; + + var decoded = new Page_C0_Quantum + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + ServoFirmwareChecksum = (ushort)((pageResponse[4] << 8) + pageResponse[5]), + ServoEEPROMChecksum = (ushort)((pageResponse[6] << 8) + pageResponse[7]), + ReadWriteFirmwareChecksum = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + + (pageResponse[10] << 8) + pageResponse[11]), + ReadWriteFirmwareBuildData = new byte[24] + }; + + Array.Copy(pageResponse, 12, decoded.ReadWriteFirmwareBuildData, 0, 24); + + return decoded; + } + + public static string PrettifyPage_C0_Quantum(byte[] pageResponse) => + PrettifyPage_C0_Quantum(DecodePage_C0_Quantum(pageResponse)); + + public static string PrettifyPage_C0_Quantum(Page_C0_Quantum? modePage) + { + if(!modePage.HasValue) + return null; + + Page_C0_Quantum page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Quantum Firmware Build Information page:"); + + sb.AppendFormat("\tServo firmware checksum: 0x{0:X4}", page.ServoFirmwareChecksum).AppendLine(); + sb.AppendFormat("\tEEPROM firmware checksum: 0x{0:X4}", page.ServoEEPROMChecksum).AppendLine(); + sb.AppendFormat("\tRead/write firmware checksum: 0x{0:X8}", page.ReadWriteFirmwareChecksum).AppendLine(); + + sb.AppendFormat("\tRead/write firmware build date: {0}", + StringHandlers.CToString(page.ReadWriteFirmwareBuildData)).AppendLine(); + + return sb.ToString(); + } + #endregion EVPD Page 0xC0 (Quantum): Firmware Build Information page + + #region EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages + /// Drive component revision level pages Page codes 0xC0, 0xC1 (Certance) + public struct Page_C0_C1_Certance + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] Component; + public byte[] Version; + public byte[] Date; + public byte[] Variant; + } + + public static Page_C0_C1_Certance? DecodePage_C0_C1_Certance(byte[] pageResponse) + { + if(pageResponse == null) + return null; + + if(pageResponse[1] != 0xC0 && + pageResponse[1] != 0xC1) + return null; + + if(pageResponse[3] != 92) + return null; + + if(pageResponse.Length != 96) + return null; + + var decoded = new Page_C0_C1_Certance + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + Component = new byte[26], + Version = new byte[19], + Date = new byte[24], + Variant = new byte[23] + }; + + Array.Copy(pageResponse, 4, decoded.Component, 0, 26); + Array.Copy(pageResponse, 30, decoded.Version, 0, 19); + Array.Copy(pageResponse, 49, decoded.Date, 0, 24); + Array.Copy(pageResponse, 73, decoded.Variant, 0, 23); + + return decoded; + } + + public static string PrettifyPage_C0_C1_Certance(byte[] pageResponse) => + PrettifyPage_C0_C1_Certance(DecodePage_C0_C1_Certance(pageResponse)); + + public static string PrettifyPage_C0_C1_Certance(Page_C0_C1_Certance? modePage) + { + if(!modePage.HasValue) + return null; + + Page_C0_C1_Certance page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Certance Drive Component Revision Levels page:"); + + sb.AppendFormat("\tComponent: {0}", StringHandlers.CToString(page.Component)).AppendLine(); + sb.AppendFormat("\tVersion: {0}", StringHandlers.CToString(page.Version)).AppendLine(); + sb.AppendFormat("\tDate: {0}", StringHandlers.CToString(page.Date)).AppendLine(); + sb.AppendFormat("\tVariant: {0}", StringHandlers.CToString(page.Variant)).AppendLine(); + + return sb.ToString(); + } + #endregion EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages + + #region EVPD Pages 0xC2, 0xC3, 0xC4, 0xC5, 0xC6 (Certance): Drive component serial number pages + /// Drive component serial number pages Page codes 0xC2, 0xC3, 0xC4, 0xC5, 0xC6 (Certance) + public struct Page_C2_C3_C4_C5_C6_Certance + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] SerialNumber; + } + + public static Page_C2_C3_C4_C5_C6_Certance? DecodePage_C2_C3_C4_C5_C6_Certance(byte[] pageResponse) + { + if(pageResponse == null) + return null; + + if(pageResponse[1] != 0xC2 && + pageResponse[1] != 0xC3 && + pageResponse[1] != 0xC4 && + pageResponse[1] != 0xC5 && + pageResponse[1] != 0xC6) + return null; + + if(pageResponse[3] != 12) + return null; + + if(pageResponse.Length != 16) + return null; + + var decoded = new Page_C2_C3_C4_C5_C6_Certance + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + SerialNumber = new byte[12] + }; + + Array.Copy(pageResponse, 4, decoded.SerialNumber, 0, 12); + + return decoded; + } + + public static string PrettifyPage_C2_C3_C4_C5_C6_Certance(byte[] pageResponse) => + PrettifyPage_C2_C3_C4_C5_C6_Certance(DecodePage_C2_C3_C4_C5_C6_Certance(pageResponse)); + + public static string PrettifyPage_C2_C3_C4_C5_C6_Certance(Page_C2_C3_C4_C5_C6_Certance? modePage) + { + if(!modePage.HasValue) + return null; + + Page_C2_C3_C4_C5_C6_Certance page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Certance Drive Component Serial Number page:"); + + switch(page.PageCode) + { + case 0xC2: + sb.AppendFormat("\tHead Assembly Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). + AppendLine(); + + break; + case 0xC3: + sb.AppendFormat("\tReel Motor 1 Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). + AppendLine(); + + break; + case 0xC4: + sb.AppendFormat("\tReel Motor 2 Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). + AppendLine(); + + break; + case 0xC5: + sb.AppendFormat("\tBoard Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). + AppendLine(); + + break; + case 0xC6: + sb.AppendFormat("\tBase Mechanical Serial Number: {0}", + StringHandlers.CToString(page.SerialNumber)).AppendLine(); + + break; + } + + return sb.ToString(); + } + #endregion EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages + + #region EVPD Page 0xDF (Certance): Drive status pages + /// Drive status pages Page codes 0xDF (Certance) + public struct Page_DF_Certance + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + /// Command forwarding + public byte CmdFwd; + /// Alerts + public bool Alerts; + /// Removable prevention + public bool NoRemov; + /// Unit reservation + public bool UnitRsvd; + /// Needs cleaning + public bool Clean; + /// Tape threaded + public bool Threaded; + /// Commands await forwarding + public bool Lun1Cmd; + /// Autoload mode + public byte AutoloadMode; + /// Cartridge type + public byte CartridgeType; + /// Cartridge format + public byte CartridgeFormat; + /// Cartridge capacity in 10e9 bytes + public ushort CartridgeCapacity; + /// Port A transport type + public byte PortATransportType; + /// Port A SCSI ID + public byte PortASelectionID; + /// Total number of head-tape contact time + public uint OperatingHours; + /// ID that reserved the device + public ulong InitiatorID; + /// Cartridge serial number + public byte[] CartridgeSerialNumber; + } + + public static Page_DF_Certance? DecodePage_DF_Certance(byte[] pageResponse) + { + if(pageResponse?[1] != 0xDF) + return null; + + if(pageResponse[3] != 60) + return null; + + if(pageResponse.Length != 64) + return null; + + var decoded = new Page_DF_Certance + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + CmdFwd = (byte)((pageResponse[5] & 0xC0) >> 5), + Alerts = (pageResponse[5] & 0x20) == 0x20, + NoRemov = (pageResponse[5] & 0x08) == 0x08, + UnitRsvd = (pageResponse[5] & 0x04) == 0x04, + Clean = (pageResponse[5] & 0x01) == 0x01, + Threaded = (pageResponse[6] & 0x10) == 0x10, + Lun1Cmd = (pageResponse[6] & 0x08) == 0x08, + AutoloadMode = (byte)(pageResponse[6] & 0x07), + CartridgeType = pageResponse[8], + CartridgeFormat = pageResponse[9], + CartridgeCapacity = (ushort)((pageResponse[10] << 8) + pageResponse[11] + 4), + PortATransportType = pageResponse[12], + PortASelectionID = pageResponse[15], + OperatingHours = (uint)((pageResponse[20] << 24) + (pageResponse[21] << 16) + (pageResponse[22] << 8) + + pageResponse[23]), + CartridgeSerialNumber = new byte[32] + }; + + byte[] buf = new byte[8]; + Array.Copy(pageResponse, 24, buf, 0, 8); + decoded.InitiatorID = BitConverter.ToUInt64(buf.Reverse().ToArray(), 0); + Array.Copy(pageResponse, 32, decoded.CartridgeSerialNumber, 0, 32); + + return decoded; + } + + public static string PrettifyPage_DF_Certance(byte[] pageResponse) => + PrettifyPage_DF_Certance(DecodePage_DF_Certance(pageResponse)); + + public static string PrettifyPage_DF_Certance(Page_DF_Certance? modePage) + { + if(!modePage.HasValue) + return null; + + Page_DF_Certance page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Certance drive status page:"); + + 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; + } + + if(page.Alerts) + sb.AppendLine("\tAlerts are enabled"); + + if(page.NoRemov) + sb.AppendLine("\tCartridge removable is prevented"); + + if(page.UnitRsvd) + sb.AppendFormat("\tUnit is reserved by initiator ID {0:X16}", page.InitiatorID).AppendLine(); + + if(page.Clean) + sb.AppendLine("\tDevice needs cleaning cartridge"); + + if(page.Threaded) + sb.AppendLine("\tCartridge tape is threaded"); + + if(page.Lun1Cmd) + sb.AppendLine("\tThere are commands pending to be forwarded"); + + switch(page.AutoloadMode) + { + case 0: + sb.AppendLine("\tCartridge will be loaded and threaded on insertion"); + + break; + case 1: + sb.AppendLine("\tCartridge will be loaded but not threaded on insertion"); + + break; + case 2: + sb.AppendLine("\tCartridge will not be loaded"); + + break; + default: + sb.AppendFormat("\tUnknown autoloading mode code {0}", page.AutoloadMode).AppendLine(); + + break; + } + + switch(page.PortATransportType) + { + 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.PortASelectionID).AppendLine(); + + sb.AppendFormat("\tDrive has been operating {0}", TimeSpan.FromHours(page.OperatingHours)).AppendLine(); + + if(page.CartridgeType > 0) + { + switch(page.CartridgeFormat) { - case 0xEC: - sb.AppendLine("\tDevice responded to ATA IDENTIFY DEVICE command."); - - break; - case 0xA1: - sb.AppendLine("\tDevice responded to ATA IDENTIFY PACKET DEVICE command."); + case 0: + sb.AppendLine("\tInserted cartridge is LTO"); break; default: - sb.AppendFormat("\tDevice responded to ATA command {0:X2}h", page.CommandCode).AppendLine(); + sb.AppendFormat("\tUnknown cartridge format code {0}", page.CartridgeType).AppendLine(); break; } - switch(page.Signature[0]) + switch(page.CartridgeType) { - case 0x00: - sb.AppendLine("\tDevice uses Parallel ATA."); + case 0: + sb.AppendLine("\tThere is no cartridge inserted"); break; - case 0x34: - sb.AppendLine("\tDevice uses Serial ATA."); + case 1: + sb.AppendLine("\tCleaning cartridge inserted"); + + break; + case 2: + sb.AppendLine("\tUnknown data cartridge inserted"); + + break; + case 3: + sb.AppendLine("\tFirmware cartridge inserted"); + + break; + case 4: + sb.AppendLine("\tLTO Ultrium 1 Type A cartridge inserted"); + + break; + case 5: + sb.AppendLine("\tLTO Ultrium 1 Type B cartridge inserted"); + + break; + case 6: + sb.AppendLine("\tLTO Ultrium 1 Type C cartridge inserted"); + + break; + case 7: + sb.AppendLine("\tLTO Ultrium 1 Type D cartridge inserted"); + + break; + case 8: + sb.AppendLine("\tLTO Ultrium 2 cartridge inserted"); break; default: - sb.AppendFormat("\tDevice uses unknown transport with code {0}", page.Signature[0]).AppendLine(); + sb.AppendFormat("\tUnknown cartridge type code {0}", page.CartridgeType).AppendLine(); break; } - Identify.IdentifyDevice? id = Identify.Decode(page.IdentifyData); + sb.AppendFormat("\tCartridge has an uncompressed capabity of {0} gigabytes", page.CartridgeCapacity). + AppendLine(); - if(id != null) - { - sb.AppendLine("\tATA IDENTIFY information follows:"); - sb.AppendFormat("{0}", ATA.Identify.Prettify(id)).AppendLine(); - } - else - sb.AppendLine("\tCould not decode ATA IDENTIFY information"); - - return sb.ToString(); + sb.AppendFormat("\tCartridge serial number: {0}", + StringHandlers.SpacePaddedToString(page.CartridgeSerialNumber)).AppendLine(); } - #endregion EVPD Page 0x89: ATA Information page + else + sb.AppendLine("\tThere is no cartridge inserted"); - #region EVPD Page 0xC0 (Quantum): Firmware Build Information page - /// Firmware Build Information page Page code 0xC0 (Quantum) - public struct Page_C0_Quantum + return sb.ToString(); + } + #endregion EVPD Page 0xDF (Certance): Drive status pages + + #region EVPD Page 0xC0 (IBM): Drive Component Revision Levels page + /// Drive Component Revision Levels page Page code 0xC0 (IBM) + public struct Page_C0_IBM + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] CodeName; + public byte[] Date; + } + + public static Page_C0_IBM? DecodePage_C0_IBM(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC0) + return null; + + if(pageResponse[3] != 39) + return null; + + if(pageResponse.Length != 43) + return null; + + var decoded = new Page_C0_IBM { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - /// Servo firmware checksum - public ushort ServoFirmwareChecksum; - /// Servo EEPROM checksum - public ushort ServoEEPROMChecksum; - /// Read/Write firmware checksum - public uint ReadWriteFirmwareChecksum; - /// Read/Write firmware build data - public byte[] ReadWriteFirmwareBuildData; - } + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + CodeName = new byte[12], + Date = new byte[8] + }; - public static Page_C0_Quantum? DecodePage_C0_Quantum(byte[] pageResponse) + Array.Copy(pageResponse, 4, decoded.CodeName, 0, 12); + Array.Copy(pageResponse, 23, decoded.Date, 0, 8); + + return decoded; + } + + public static string PrettifyPage_C0_IBM(byte[] pageResponse) => + PrettifyPage_C0_IBM(DecodePage_C0_IBM(pageResponse)); + + public static string PrettifyPage_C0_IBM(Page_C0_IBM? modePage) + { + if(!modePage.HasValue) + return null; + + Page_C0_IBM page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("IBM Drive Component Revision Levels page:"); + + sb.AppendFormat("\tCode name: {0}", StringHandlers.CToString(page.CodeName)).AppendLine(); + sb.AppendFormat("\tDate: {0}", StringHandlers.CToString(page.Date)).AppendLine(); + + return sb.ToString(); + } + #endregion EVPD Page 0xC0 (IBM): Drive Component Revision Levels page + + #region EVPD Page 0xC1 (IBM): Drive Serial Numbers page + /// Drive Serial Numbers page Page code 0xC1 (IBM) + public struct Page_C1_IBM + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] ManufacturingSerial; + public byte[] ReportedSerial; + } + + public static Page_C1_IBM? DecodePage_C1_IBM(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC1) + return null; + + if(pageResponse[3] != 24) + return null; + + if(pageResponse.Length != 28) + return null; + + var decoded = new Page_C1_IBM { - if(pageResponse?[1] != 0xC0) - return null; + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + ManufacturingSerial = new byte[12], + ReportedSerial = new byte[12] + }; - if(pageResponse[3] != 20) - return null; + Array.Copy(pageResponse, 4, decoded.ManufacturingSerial, 0, 12); + Array.Copy(pageResponse, 16, decoded.ReportedSerial, 0, 12); - if(pageResponse.Length != 36) - return null; + return decoded; + } - var decoded = new Page_C0_Quantum - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - ServoFirmwareChecksum = (ushort)((pageResponse[4] << 8) + pageResponse[5]), - ServoEEPROMChecksum = (ushort)((pageResponse[6] << 8) + pageResponse[7]), - ReadWriteFirmwareChecksum = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + - (pageResponse[10] << 8) + pageResponse[11]), - ReadWriteFirmwareBuildData = new byte[24] - }; + public static string PrettifyPage_C1_IBM(byte[] pageResponse) => + PrettifyPage_C1_IBM(DecodePage_C1_IBM(pageResponse)); - Array.Copy(pageResponse, 12, decoded.ReadWriteFirmwareBuildData, 0, 24); + public static string PrettifyPage_C1_IBM(Page_C1_IBM? modePage) + { + if(!modePage.HasValue) + return null; - return decoded; - } + Page_C1_IBM page = modePage.Value; + var sb = new StringBuilder(); - public static string PrettifyPage_C0_Quantum(byte[] pageResponse) => - PrettifyPage_C0_Quantum(DecodePage_C0_Quantum(pageResponse)); + sb.AppendLine("IBM Drive Serial Numbers page:"); - public static string PrettifyPage_C0_Quantum(Page_C0_Quantum? modePage) + sb.AppendFormat("\tManufacturing serial number: {0}", StringHandlers.CToString(page.ManufacturingSerial)). + AppendLine(); + + sb.AppendFormat("\tReported serial number: {0}", StringHandlers.CToString(page.ReportedSerial)). + AppendLine(); + + return sb.ToString(); + } + #endregion EVPD Page 0xC1 (IBM): Drive Serial Numbers page + + #region EVPD Page 0xB0: Sequential-access device capabilities page + /// Sequential-access device capabilities page Page code 0xB0 + public struct Page_B0 + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public ushort PageLength; + public bool TSMC; + public bool WORM; + } + + public static Page_B0? DecodePage_B0(byte[] pageResponse) + { + if(pageResponse?[1] != 0xB0) + return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 5) + return null; + + var decoded = new Page_B0 { - if(!modePage.HasValue) - return null; + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4), + TSMC = (pageResponse[4] & 0x02) == 0x02, + WORM = (pageResponse[4] & 0x01) == 0x01 + }; - Page_C0_Quantum page = modePage.Value; - var sb = new StringBuilder(); + return decoded; + } - sb.AppendLine("Quantum Firmware Build Information page:"); + public static string PrettifyPage_B0(byte[] pageResponse) => PrettifyPage_B0(DecodePage_B0(pageResponse)); - sb.AppendFormat("\tServo firmware checksum: 0x{0:X4}", page.ServoFirmwareChecksum).AppendLine(); - sb.AppendFormat("\tEEPROM firmware checksum: 0x{0:X4}", page.ServoEEPROMChecksum).AppendLine(); - sb.AppendFormat("\tRead/write firmware checksum: 0x{0:X8}", page.ReadWriteFirmwareChecksum).AppendLine(); + public static string PrettifyPage_B0(Page_B0? modePage) + { + if(!modePage.HasValue) + return null; - sb.AppendFormat("\tRead/write firmware build date: {0}", - StringHandlers.CToString(page.ReadWriteFirmwareBuildData)).AppendLine(); + Page_B0 page = modePage.Value; + var sb = new StringBuilder(); - return sb.ToString(); - } - #endregion EVPD Page 0xC0 (Quantum): Firmware Build Information page + sb.AppendLine("SCSI Sequential-access Device Capabilities:"); - #region EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages - /// Drive component revision level pages Page codes 0xC0, 0xC1 (Certance) - public struct Page_C0_C1_Certance + if(page.WORM) + sb.AppendLine("\tDevice supports WORM media"); + + if(page.TSMC) + sb.AppendLine("\tDevice supports Tape Stream Mirroring"); + + return sb.ToString(); + } + #endregion EVPD Page 0xB0: Sequential-access device capabilities page + + #region EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages + /// Drive component revision level pages Page codes 0xC0 to 0xC5 (HP) + public struct Page_C0_to_C5_HP + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] Component; + public byte[] Version; + public byte[] Date; + public byte[] Variant; + public byte[] Copyright; + } + + public static Page_C0_to_C5_HP? DecodePage_C0_to_C5_HP(byte[] pageResponse) + { + if(pageResponse == null) + return null; + + if(pageResponse[1] != 0xC0 && + pageResponse[1] != 0xC1 && + pageResponse[1] != 0xC2 && + pageResponse[1] != 0xC3 && + pageResponse[1] != 0xC4 && + pageResponse[1] != 0xC5) + return null; + + if(pageResponse.Length < 4) + return null; + + var decoded = new Page_C0_to_C5_HP { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - public byte[] Component; - public byte[] Version; - public byte[] Date; - public byte[] Variant; - } + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + PageCode = pageResponse[1] + }; - public static Page_C0_C1_Certance? DecodePage_C0_C1_Certance(byte[] pageResponse) + if(pageResponse[3] == 92 && + pageResponse.Length >= 96) { - if(pageResponse == null) - return null; - - if(pageResponse[1] != 0xC0 && - pageResponse[1] != 0xC1) - return null; - - if(pageResponse[3] != 92) - return null; - - if(pageResponse.Length != 96) - return null; - - var decoded = new Page_C0_C1_Certance - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - Component = new byte[26], - Version = new byte[19], - Date = new byte[24], - Variant = new byte[23] - }; + decoded.Component = new byte[26]; + decoded.Version = new byte[19]; + decoded.Date = new byte[24]; + decoded.Variant = new byte[23]; Array.Copy(pageResponse, 4, decoded.Component, 0, 26); Array.Copy(pageResponse, 30, decoded.Version, 0, 19); @@ -1587,790 +2195,181 @@ namespace Aaru.Decoders.SCSI return decoded; } - public static string PrettifyPage_C0_C1_Certance(byte[] pageResponse) => - PrettifyPage_C0_C1_Certance(DecodePage_C0_C1_Certance(pageResponse)); + if(pageResponse[4] != pageResponse[3] - 1) + return null; - public static string PrettifyPage_C0_C1_Certance(Page_C0_C1_Certance? modePage) - { - if(!modePage.HasValue) - return null; + List array = new List(); - Page_C0_C1_Certance page = modePage.Value; - var sb = new StringBuilder(); + const string fwRegExStr = + @"Firmware Rev\s+=\s+(?\d+\.\d+)\s+Build date\s+=\s+(?(\w|\d|\s*.)*)\s*$"; - sb.AppendLine("Certance Drive Component Revision Levels page:"); + const string fwcRegExStr = @"FW_CONF\s+=\s+(?0x[0-9A-Fa-f]{8})\s*$"; + const string servoRegExStr = @"Servo\s+Rev\s+=\s+(?\d+\.\d+)\s*$"; + var fwRegEx = new Regex(fwRegExStr); + var fwcRegEx = new Regex(fwcRegExStr); + var servoRegEx = new Regex(servoRegExStr); - sb.AppendFormat("\tComponent: {0}", StringHandlers.CToString(page.Component)).AppendLine(); - sb.AppendFormat("\tVersion: {0}", StringHandlers.CToString(page.Version)).AppendLine(); - sb.AppendFormat("\tDate: {0}", StringHandlers.CToString(page.Date)).AppendLine(); - sb.AppendFormat("\tVariant: {0}", StringHandlers.CToString(page.Variant)).AppendLine(); - - return sb.ToString(); - } - #endregion EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages - - #region EVPD Pages 0xC2, 0xC3, 0xC4, 0xC5, 0xC6 (Certance): Drive component serial number pages - /// Drive component serial number pages Page codes 0xC2, 0xC3, 0xC4, 0xC5, 0xC6 (Certance) - public struct Page_C2_C3_C4_C5_C6_Certance - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - public byte[] SerialNumber; - } - - public static Page_C2_C3_C4_C5_C6_Certance? DecodePage_C2_C3_C4_C5_C6_Certance(byte[] pageResponse) - { - if(pageResponse == null) - return null; - - if(pageResponse[1] != 0xC2 && - pageResponse[1] != 0xC3 && - pageResponse[1] != 0xC4 && - pageResponse[1] != 0xC5 && - pageResponse[1] != 0xC6) - return null; - - if(pageResponse[3] != 12) - return null; - - if(pageResponse.Length != 16) - return null; - - var decoded = new Page_C2_C3_C4_C5_C6_Certance + for(int pos = 5; pos < pageResponse.Length; pos++) + if(pageResponse[pos] == 0x00) { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - SerialNumber = new byte[12] - }; + string str = StringHandlers.CToString(array.ToArray()); + Match fwMatch = fwRegEx.Match(str); + Match fwcMatch = fwcRegEx.Match(str); + Match servoMatch = servoRegEx.Match(str); - Array.Copy(pageResponse, 4, decoded.SerialNumber, 0, 12); - - return decoded; - } - - public static string PrettifyPage_C2_C3_C4_C5_C6_Certance(byte[] pageResponse) => - PrettifyPage_C2_C3_C4_C5_C6_Certance(DecodePage_C2_C3_C4_C5_C6_Certance(pageResponse)); - - public static string PrettifyPage_C2_C3_C4_C5_C6_Certance(Page_C2_C3_C4_C5_C6_Certance? modePage) - { - if(!modePage.HasValue) - return null; - - Page_C2_C3_C4_C5_C6_Certance page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Certance Drive Component Serial Number page:"); - - switch(page.PageCode) - { - case 0xC2: - sb.AppendFormat("\tHead Assembly Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). - AppendLine(); - - break; - case 0xC3: - sb.AppendFormat("\tReel Motor 1 Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). - AppendLine(); - - break; - case 0xC4: - sb.AppendFormat("\tReel Motor 2 Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). - AppendLine(); - - break; - case 0xC5: - sb.AppendFormat("\tBoard Serial Number: {0}", StringHandlers.CToString(page.SerialNumber)). - AppendLine(); - - break; - case 0xC6: - sb.AppendFormat("\tBase Mechanical Serial Number: {0}", - StringHandlers.CToString(page.SerialNumber)).AppendLine(); - - break; - } - - return sb.ToString(); - } - #endregion EVPD Pages 0xC0, 0xC1 (Certance): Drive component revision level pages - - #region EVPD Page 0xDF (Certance): Drive status pages - /// Drive status pages Page codes 0xDF (Certance) - public struct Page_DF_Certance - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - /// Command forwarding - public byte CmdFwd; - /// Alerts - public bool Alerts; - /// Removable prevention - public bool NoRemov; - /// Unit reservation - public bool UnitRsvd; - /// Needs cleaning - public bool Clean; - /// Tape threaded - public bool Threaded; - /// Commands await forwarding - public bool Lun1Cmd; - /// Autoload mode - public byte AutoloadMode; - /// Cartridge type - public byte CartridgeType; - /// Cartridge format - public byte CartridgeFormat; - /// Cartridge capacity in 10e9 bytes - public ushort CartridgeCapacity; - /// Port A transport type - public byte PortATransportType; - /// Port A SCSI ID - public byte PortASelectionID; - /// Total number of head-tape contact time - public uint OperatingHours; - /// ID that reserved the device - public ulong InitiatorID; - /// Cartridge serial number - public byte[] CartridgeSerialNumber; - } - - public static Page_DF_Certance? DecodePage_DF_Certance(byte[] pageResponse) - { - if(pageResponse?[1] != 0xDF) - return null; - - if(pageResponse[3] != 60) - return null; - - if(pageResponse.Length != 64) - return null; - - var decoded = new Page_DF_Certance - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - CmdFwd = (byte)((pageResponse[5] & 0xC0) >> 5), - Alerts = (pageResponse[5] & 0x20) == 0x20, - NoRemov = (pageResponse[5] & 0x08) == 0x08, - UnitRsvd = (pageResponse[5] & 0x04) == 0x04, - Clean = (pageResponse[5] & 0x01) == 0x01, - Threaded = (pageResponse[6] & 0x10) == 0x10, - Lun1Cmd = (pageResponse[6] & 0x08) == 0x08, - AutoloadMode = (byte)(pageResponse[6] & 0x07), - CartridgeType = pageResponse[8], - CartridgeFormat = pageResponse[9], - CartridgeCapacity = (ushort)((pageResponse[10] << 8) + pageResponse[11] + 4), - PortATransportType = pageResponse[12], - PortASelectionID = pageResponse[15], - OperatingHours = (uint)((pageResponse[20] << 24) + (pageResponse[21] << 16) + (pageResponse[22] << 8) + - pageResponse[23]), - CartridgeSerialNumber = new byte[32] - }; - - byte[] buf = new byte[8]; - Array.Copy(pageResponse, 24, buf, 0, 8); - decoded.InitiatorID = BitConverter.ToUInt64(buf.Reverse().ToArray(), 0); - Array.Copy(pageResponse, 32, decoded.CartridgeSerialNumber, 0, 32); - - return decoded; - } - - public static string PrettifyPage_DF_Certance(byte[] pageResponse) => - PrettifyPage_DF_Certance(DecodePage_DF_Certance(pageResponse)); - - public static string PrettifyPage_DF_Certance(Page_DF_Certance? modePage) - { - if(!modePage.HasValue) - return null; - - Page_DF_Certance page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Certance drive status page:"); - - 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; - } - - if(page.Alerts) - sb.AppendLine("\tAlerts are enabled"); - - if(page.NoRemov) - sb.AppendLine("\tCartridge removable is prevented"); - - if(page.UnitRsvd) - sb.AppendFormat("\tUnit is reserved by initiator ID {0:X16}", page.InitiatorID).AppendLine(); - - if(page.Clean) - sb.AppendLine("\tDevice needs cleaning cartridge"); - - if(page.Threaded) - sb.AppendLine("\tCartridge tape is threaded"); - - if(page.Lun1Cmd) - sb.AppendLine("\tThere are commands pending to be forwarded"); - - switch(page.AutoloadMode) - { - case 0: - sb.AppendLine("\tCartridge will be loaded and threaded on insertion"); - - break; - case 1: - sb.AppendLine("\tCartridge will be loaded but not threaded on insertion"); - - break; - case 2: - sb.AppendLine("\tCartridge will not be loaded"); - - break; - default: - sb.AppendFormat("\tUnknown autoloading mode code {0}", page.AutoloadMode).AppendLine(); - - break; - } - - switch(page.PortATransportType) - { - 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.PortASelectionID).AppendLine(); - - sb.AppendFormat("\tDrive has been operating {0}", TimeSpan.FromHours(page.OperatingHours)).AppendLine(); - - if(page.CartridgeType > 0) - { - switch(page.CartridgeFormat) + if(str.ToLowerInvariant().StartsWith("copyright", StringComparison.Ordinal)) + decoded.Copyright = Encoding.ASCII.GetBytes(str); + else if(fwMatch.Success) { - case 0: - sb.AppendLine("\tInserted cartridge is LTO"); - - break; - default: - sb.AppendFormat("\tUnknown cartridge format code {0}", page.CartridgeType).AppendLine(); - - break; + decoded.Component = Encoding.ASCII.GetBytes("Firmware"); + decoded.Version = Encoding.ASCII.GetBytes(fwMatch.Groups["fw"].Value); + decoded.Date = Encoding.ASCII.GetBytes(fwMatch.Groups["date"].Value); + } + else if(fwcMatch.Success) + decoded.Variant = Encoding.ASCII.GetBytes(fwMatch.Groups["value"].Value); + else if(servoMatch.Success) + { + decoded.Component = Encoding.ASCII.GetBytes("Servo"); + decoded.Version = Encoding.ASCII.GetBytes(servoMatch.Groups["version"].Value); } - switch(page.CartridgeType) - { - case 0: - sb.AppendLine("\tThere is no cartridge inserted"); - - break; - case 1: - sb.AppendLine("\tCleaning cartridge inserted"); - - break; - case 2: - sb.AppendLine("\tUnknown data cartridge inserted"); - - break; - case 3: - sb.AppendLine("\tFirmware cartridge inserted"); - - break; - case 4: - sb.AppendLine("\tLTO Ultrium 1 Type A cartridge inserted"); - - break; - case 5: - sb.AppendLine("\tLTO Ultrium 1 Type B cartridge inserted"); - - break; - case 6: - sb.AppendLine("\tLTO Ultrium 1 Type C cartridge inserted"); - - break; - case 7: - sb.AppendLine("\tLTO Ultrium 1 Type D cartridge inserted"); - - break; - case 8: - sb.AppendLine("\tLTO Ultrium 2 cartridge inserted"); - - break; - default: - sb.AppendFormat("\tUnknown cartridge type code {0}", page.CartridgeType).AppendLine(); - - break; - } - - sb.AppendFormat("\tCartridge has an uncompressed capabity of {0} gigabytes", page.CartridgeCapacity). - AppendLine(); - - sb.AppendFormat("\tCartridge serial number: {0}", - StringHandlers.SpacePaddedToString(page.CartridgeSerialNumber)).AppendLine(); + array = new List(); } else - sb.AppendLine("\tThere is no cartridge inserted"); + array.Add(pageResponse[pos]); - return sb.ToString(); - } - #endregion EVPD Page 0xDF (Certance): Drive status pages + return decoded; + } - #region EVPD Page 0xC0 (IBM): Drive Component Revision Levels page - /// Drive Component Revision Levels page Page code 0xC0 (IBM) - public struct Page_C0_IBM + public static string PrettifyPage_C0_to_C5_HP(byte[] pageResponse) => + PrettifyPage_C0_to_C5_HP(DecodePage_C0_to_C5_HP(pageResponse)); + + public static string PrettifyPage_C0_to_C5_HP(Page_C0_to_C5_HP? modePage) + { + if(!modePage.HasValue) + return null; + + Page_C0_to_C5_HP page = modePage.Value; + var sb = new StringBuilder(); + + switch(page.PageCode) { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - public byte[] CodeName; - public byte[] Date; + case 0xC0: + sb.AppendLine("HP Drive Firmware Revision Levels page:"); + + break; + case 0xC1: + sb.AppendLine("HP Drive Hardware Revision Levels page:"); + + break; + case 0xC2: + sb.AppendLine("HP Drive PCA Revision Levels page:"); + + break; + case 0xC3: + sb.AppendLine("HP Drive Mechanism Revision Levels page:"); + + break; + case 0xC4: + sb.AppendLine("HP Drive Head Assembly Revision Levels page:"); + + break; + case 0xC5: + sb.AppendLine("HP Drive ACI Revision Levels page:"); + + break; } - public static Page_C0_IBM? DecodePage_C0_IBM(byte[] pageResponse) - { - if(pageResponse?[1] != 0xC0) - return null; + if(page.Component != null && + page.Component.Length > 0) + sb.AppendFormat("\tComponent: {0}", StringHandlers.CToString(page.Component)).AppendLine(); - if(pageResponse[3] != 39) - return null; + if(page.Version != null && + page.Version.Length > 0) + sb.AppendFormat("\tVersion: {0}", StringHandlers.CToString(page.Version)).AppendLine(); - if(pageResponse.Length != 43) - return null; - - var decoded = new Page_C0_IBM - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - CodeName = new byte[12], - Date = new byte[8] - }; - - Array.Copy(pageResponse, 4, decoded.CodeName, 0, 12); - Array.Copy(pageResponse, 23, decoded.Date, 0, 8); - - return decoded; - } - - public static string PrettifyPage_C0_IBM(byte[] pageResponse) => - PrettifyPage_C0_IBM(DecodePage_C0_IBM(pageResponse)); - - public static string PrettifyPage_C0_IBM(Page_C0_IBM? modePage) - { - if(!modePage.HasValue) - return null; - - Page_C0_IBM page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("IBM Drive Component Revision Levels page:"); - - sb.AppendFormat("\tCode name: {0}", StringHandlers.CToString(page.CodeName)).AppendLine(); + if(page.Date != null && + page.Date.Length > 0) sb.AppendFormat("\tDate: {0}", StringHandlers.CToString(page.Date)).AppendLine(); - return sb.ToString(); - } - #endregion EVPD Page 0xC0 (IBM): Drive Component Revision Levels page + if(page.Variant != null && + page.Variant.Length > 0) + sb.AppendFormat("\tVariant: {0}", StringHandlers.CToString(page.Variant)).AppendLine(); - #region EVPD Page 0xC1 (IBM): Drive Serial Numbers page - /// Drive Serial Numbers page Page code 0xC1 (IBM) - public struct Page_C1_IBM - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - public byte[] ManufacturingSerial; - public byte[] ReportedSerial; - } + if(page.Copyright != null && + page.Copyright.Length > 0) + sb.AppendFormat("\tCopyright: {0}", StringHandlers.CToString(page.Copyright)).AppendLine(); - public static Page_C1_IBM? DecodePage_C1_IBM(byte[] pageResponse) - { - if(pageResponse?[1] != 0xC1) - return null; - - if(pageResponse[3] != 24) - return null; - - if(pageResponse.Length != 28) - return null; - - var decoded = new Page_C1_IBM - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - ManufacturingSerial = new byte[12], - ReportedSerial = new byte[12] - }; - - Array.Copy(pageResponse, 4, decoded.ManufacturingSerial, 0, 12); - Array.Copy(pageResponse, 16, decoded.ReportedSerial, 0, 12); - - return decoded; - } - - public static string PrettifyPage_C1_IBM(byte[] pageResponse) => - PrettifyPage_C1_IBM(DecodePage_C1_IBM(pageResponse)); - - public static string PrettifyPage_C1_IBM(Page_C1_IBM? modePage) - { - if(!modePage.HasValue) - return null; - - Page_C1_IBM page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("IBM Drive Serial Numbers page:"); - - sb.AppendFormat("\tManufacturing serial number: {0}", StringHandlers.CToString(page.ManufacturingSerial)). - AppendLine(); - - sb.AppendFormat("\tReported serial number: {0}", StringHandlers.CToString(page.ReportedSerial)). - AppendLine(); - - return sb.ToString(); - } - #endregion EVPD Page 0xC1 (IBM): Drive Serial Numbers page - - #region EVPD Page 0xB0: Sequential-access device capabilities page - /// Sequential-access device capabilities page Page code 0xB0 - public struct Page_B0 - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public ushort PageLength; - public bool TSMC; - public bool WORM; - } - - public static Page_B0? DecodePage_B0(byte[] pageResponse) - { - if(pageResponse?[1] != 0xB0) - return null; - - if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 5) - return null; - - var decoded = new Page_B0 - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (ushort)((pageResponse[2] << 8) + pageResponse[3] + 4), - TSMC = (pageResponse[4] & 0x02) == 0x02, - WORM = (pageResponse[4] & 0x01) == 0x01 - }; - - return decoded; - } - - public static string PrettifyPage_B0(byte[] pageResponse) => PrettifyPage_B0(DecodePage_B0(pageResponse)); - - public static string PrettifyPage_B0(Page_B0? modePage) - { - if(!modePage.HasValue) - return null; - - Page_B0 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Sequential-access Device Capabilities:"); - - if(page.WORM) - sb.AppendLine("\tDevice supports WORM media"); - - if(page.TSMC) - sb.AppendLine("\tDevice supports Tape Stream Mirroring"); - - return sb.ToString(); - } - #endregion EVPD Page 0xB0: Sequential-access device capabilities page - - #region EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages - /// Drive component revision level pages Page codes 0xC0 to 0xC5 (HP) - public struct Page_C0_to_C5_HP - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - public byte[] Component; - public byte[] Version; - public byte[] Date; - public byte[] Variant; - public byte[] Copyright; - } - - public static Page_C0_to_C5_HP? DecodePage_C0_to_C5_HP(byte[] pageResponse) - { - if(pageResponse == null) - return null; - - if(pageResponse[1] != 0xC0 && - pageResponse[1] != 0xC1 && - pageResponse[1] != 0xC2 && - pageResponse[1] != 0xC3 && - pageResponse[1] != 0xC4 && - pageResponse[1] != 0xC5) - return null; - - if(pageResponse.Length < 4) - return null; - - var decoded = new Page_C0_to_C5_HP - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - PageCode = pageResponse[1] - }; - - if(pageResponse[3] == 92 && - pageResponse.Length >= 96) - { - decoded.Component = new byte[26]; - decoded.Version = new byte[19]; - decoded.Date = new byte[24]; - decoded.Variant = new byte[23]; - - Array.Copy(pageResponse, 4, decoded.Component, 0, 26); - Array.Copy(pageResponse, 30, decoded.Version, 0, 19); - Array.Copy(pageResponse, 49, decoded.Date, 0, 24); - Array.Copy(pageResponse, 73, decoded.Variant, 0, 23); - - return decoded; - } - - if(pageResponse[4] != pageResponse[3] - 1) - return null; - - List array = new List(); - - const string fwRegExStr = - @"Firmware Rev\s+=\s+(?\d+\.\d+)\s+Build date\s+=\s+(?(\w|\d|\s*.)*)\s*$"; - - const string fwcRegExStr = @"FW_CONF\s+=\s+(?0x[0-9A-Fa-f]{8})\s*$"; - const string servoRegExStr = @"Servo\s+Rev\s+=\s+(?\d+\.\d+)\s*$"; - var fwRegEx = new Regex(fwRegExStr); - var fwcRegEx = new Regex(fwcRegExStr); - var servoRegEx = new Regex(servoRegExStr); - - for(int pos = 5; pos < pageResponse.Length; pos++) - if(pageResponse[pos] == 0x00) - { - string str = StringHandlers.CToString(array.ToArray()); - Match fwMatch = fwRegEx.Match(str); - Match fwcMatch = fwcRegEx.Match(str); - Match servoMatch = servoRegEx.Match(str); - - if(str.ToLowerInvariant().StartsWith("copyright", StringComparison.Ordinal)) - decoded.Copyright = Encoding.ASCII.GetBytes(str); - else if(fwMatch.Success) - { - decoded.Component = Encoding.ASCII.GetBytes("Firmware"); - decoded.Version = Encoding.ASCII.GetBytes(fwMatch.Groups["fw"].Value); - decoded.Date = Encoding.ASCII.GetBytes(fwMatch.Groups["date"].Value); - } - else if(fwcMatch.Success) - decoded.Variant = Encoding.ASCII.GetBytes(fwMatch.Groups["value"].Value); - else if(servoMatch.Success) - { - decoded.Component = Encoding.ASCII.GetBytes("Servo"); - decoded.Version = Encoding.ASCII.GetBytes(servoMatch.Groups["version"].Value); - } - - array = new List(); - } - else - array.Add(pageResponse[pos]); - - return decoded; - } - - public static string PrettifyPage_C0_to_C5_HP(byte[] pageResponse) => - PrettifyPage_C0_to_C5_HP(DecodePage_C0_to_C5_HP(pageResponse)); - - public static string PrettifyPage_C0_to_C5_HP(Page_C0_to_C5_HP? modePage) - { - if(!modePage.HasValue) - return null; - - Page_C0_to_C5_HP page = modePage.Value; - var sb = new StringBuilder(); - - switch(page.PageCode) - { - case 0xC0: - sb.AppendLine("HP Drive Firmware Revision Levels page:"); - - break; - case 0xC1: - sb.AppendLine("HP Drive Hardware Revision Levels page:"); - - break; - case 0xC2: - sb.AppendLine("HP Drive PCA Revision Levels page:"); - - break; - case 0xC3: - sb.AppendLine("HP Drive Mechanism Revision Levels page:"); - - break; - case 0xC4: - sb.AppendLine("HP Drive Head Assembly Revision Levels page:"); - - break; - case 0xC5: - sb.AppendLine("HP Drive ACI Revision Levels page:"); - - break; - } - - if(page.Component != null && - page.Component.Length > 0) - sb.AppendFormat("\tComponent: {0}", StringHandlers.CToString(page.Component)).AppendLine(); - - if(page.Version != null && - page.Version.Length > 0) - sb.AppendFormat("\tVersion: {0}", StringHandlers.CToString(page.Version)).AppendLine(); - - if(page.Date != null && - page.Date.Length > 0) - sb.AppendFormat("\tDate: {0}", StringHandlers.CToString(page.Date)).AppendLine(); - - if(page.Variant != null && - page.Variant.Length > 0) - sb.AppendFormat("\tVariant: {0}", StringHandlers.CToString(page.Variant)).AppendLine(); - - if(page.Copyright != null && - page.Copyright.Length > 0) - sb.AppendFormat("\tCopyright: {0}", StringHandlers.CToString(page.Copyright)).AppendLine(); - - return sb.ToString(); - } - #endregion EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages - - #region EVPD Page 0xC0 (Seagate): Firmware numbers page - /// Firmware numbers page Page code 0xC0 (Seagate) - public struct Page_C0_Seagate - { - /// The peripheral qualifier. - public PeripheralQualifiers PeripheralQualifier; - /// The type of the peripheral device. - public PeripheralDeviceTypes PeripheralDeviceType; - /// The page code. - public byte PageCode; - /// The length of the page. - public byte PageLength; - public byte[] ControllerFirmware; - public byte[] BootFirmware; - public byte[] ServoFirmware; - } - - public static Page_C0_Seagate? DecodePage_C0_Seagate(byte[] pageResponse) - { - if(pageResponse?[1] != 0xC0) - return null; - - if(pageResponse[3] != 12) - return null; - - if(pageResponse.Length != 16) - return null; - - var decoded = new Page_C0_Seagate - { - PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), - PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), - PageLength = (byte)(pageResponse[3] + 4), - PageCode = pageResponse[1], - ControllerFirmware = new byte[4], - BootFirmware = new byte[4], - ServoFirmware = new byte[4] - }; - - Array.Copy(pageResponse, 4, decoded.ControllerFirmware, 0, 4); - Array.Copy(pageResponse, 8, decoded.BootFirmware, 0, 4); - Array.Copy(pageResponse, 12, decoded.ServoFirmware, 0, 4); - - return decoded; - } - - public static string PrettifyPage_C0_Seagate(byte[] pageResponse) => - PrettifyPage_C0_Seagate(DecodePage_C0_Seagate(pageResponse)); - - public static string PrettifyPage_C0_Seagate(Page_C0_Seagate? modePage) - { - if(!modePage.HasValue) - return null; - - Page_C0_Seagate page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Seagate Firmware Numbers page:"); - - sb.AppendFormat("\tController firmware version: {0}", StringHandlers.CToString(page.ControllerFirmware)). - AppendLine(); - - sb.AppendFormat("\tBoot firmware version: {0}", StringHandlers.CToString(page.BootFirmware)).AppendLine(); - sb.AppendFormat("\tServo firmware version: {0}", StringHandlers.CToString(page.ServoFirmware)).AppendLine(); - - return sb.ToString(); - } - #endregion EVPD Page 0xC0 (Seagate): Firmware numbers page + return sb.ToString(); } + #endregion EVPD Pages 0xC0 to 0xC5 (HP): Drive component revision level pages + + #region EVPD Page 0xC0 (Seagate): Firmware numbers page + /// Firmware numbers page Page code 0xC0 (Seagate) + public struct Page_C0_Seagate + { + /// The peripheral qualifier. + public PeripheralQualifiers PeripheralQualifier; + /// The type of the peripheral device. + public PeripheralDeviceTypes PeripheralDeviceType; + /// The page code. + public byte PageCode; + /// The length of the page. + public byte PageLength; + public byte[] ControllerFirmware; + public byte[] BootFirmware; + public byte[] ServoFirmware; + } + + public static Page_C0_Seagate? DecodePage_C0_Seagate(byte[] pageResponse) + { + if(pageResponse?[1] != 0xC0) + return null; + + if(pageResponse[3] != 12) + return null; + + if(pageResponse.Length != 16) + return null; + + var decoded = new Page_C0_Seagate + { + PeripheralQualifier = (PeripheralQualifiers)((pageResponse[0] & 0xE0) >> 5), + PeripheralDeviceType = (PeripheralDeviceTypes)(pageResponse[0] & 0x1F), + PageLength = (byte)(pageResponse[3] + 4), + PageCode = pageResponse[1], + ControllerFirmware = new byte[4], + BootFirmware = new byte[4], + ServoFirmware = new byte[4] + }; + + Array.Copy(pageResponse, 4, decoded.ControllerFirmware, 0, 4); + Array.Copy(pageResponse, 8, decoded.BootFirmware, 0, 4); + Array.Copy(pageResponse, 12, decoded.ServoFirmware, 0, 4); + + return decoded; + } + + public static string PrettifyPage_C0_Seagate(byte[] pageResponse) => + PrettifyPage_C0_Seagate(DecodePage_C0_Seagate(pageResponse)); + + public static string PrettifyPage_C0_Seagate(Page_C0_Seagate? modePage) + { + if(!modePage.HasValue) + return null; + + Page_C0_Seagate page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Seagate Firmware Numbers page:"); + + sb.AppendFormat("\tController firmware version: {0}", StringHandlers.CToString(page.ControllerFirmware)). + AppendLine(); + + sb.AppendFormat("\tBoot firmware version: {0}", StringHandlers.CToString(page.BootFirmware)).AppendLine(); + sb.AppendFormat("\tServo firmware version: {0}", StringHandlers.CToString(page.ServoFirmware)).AppendLine(); + + return sb.ToString(); + } + #endregion EVPD Page 0xC0 (Seagate): Firmware numbers page } \ No newline at end of file diff --git a/SCSI/Inquiry.cs b/SCSI/Inquiry.cs index 4cd40c4..d641a24 100644 --- a/SCSI/Inquiry.cs +++ b/SCSI/Inquiry.cs @@ -37,2454 +37,2453 @@ using System.Text; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +// Information from the following standards: +// T9/375-D revision 10l +// T10/995-D revision 10 +// T10/1236-D revision 20 +// T10/1416-D revision 23 +// T10/1731-D revision 16 +// T10/502 revision 05 +// RFC 7144 +// ECMA-111 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Inquiry { - // Information from the following standards: - // T9/375-D revision 10l - // T10/995-D revision 10 - // T10/1236-D revision 20 - // T10/1416-D revision 23 - // T10/1731-D revision 16 - // T10/502 revision 05 - // RFC 7144 - // ECMA-111 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Inquiry + public static string Prettify(CommonTypes.Structs.Devices.SCSI.Inquiry? SCSIInquiryResponse) { - public static string Prettify(CommonTypes.Structs.Devices.SCSI.Inquiry? SCSIInquiryResponse) + if(SCSIInquiryResponse == null) + return null; + + CommonTypes.Structs.Devices.SCSI.Inquiry response = SCSIInquiryResponse.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat("Device vendor: {0}", + VendorString.Prettify(StringHandlers.CToString(response.VendorIdentification).Trim())). + AppendLine(); + + sb.AppendFormat("Device name: {0}", StringHandlers.CToString(response.ProductIdentification).Trim()). + AppendLine(); + + sb.AppendFormat("Device release level: {0}", + StringHandlers.CToString(response.ProductRevisionLevel).Trim()).AppendLine(); + + switch((PeripheralQualifiers)response.PeripheralQualifier) { - if(SCSIInquiryResponse == null) - return null; + case PeripheralQualifiers.Supported: + sb.AppendLine("Device is connected and supported."); - CommonTypes.Structs.Devices.SCSI.Inquiry response = SCSIInquiryResponse.Value; + break; + case PeripheralQualifiers.Unconnected: + sb.AppendLine("Device is supported but not connected."); - var sb = new StringBuilder(); + break; + case PeripheralQualifiers.Reserved: + sb.AppendLine("Reserved value set in Peripheral Qualifier field."); - sb.AppendFormat("Device vendor: {0}", - VendorString.Prettify(StringHandlers.CToString(response.VendorIdentification).Trim())). - AppendLine(); + break; + case PeripheralQualifiers.Unsupported: + sb.AppendLine("Device is connected but unsupported."); - sb.AppendFormat("Device name: {0}", StringHandlers.CToString(response.ProductIdentification).Trim()). - AppendLine(); + break; + default: + sb.AppendFormat("Vendor value {0} set in Peripheral Qualifier field.", + response.PeripheralQualifier).AppendLine(); + + break; + } - sb.AppendFormat("Device release level: {0}", - StringHandlers.CToString(response.ProductRevisionLevel).Trim()).AppendLine(); + switch((PeripheralDeviceTypes)response.PeripheralDeviceType) + { + case PeripheralDeviceTypes.DirectAccess: //0x00, + sb.AppendLine("Direct-access device"); + + break; + case PeripheralDeviceTypes.SequentialAccess: //0x01, + sb.AppendLine("Sequential-access device"); + + break; + case PeripheralDeviceTypes.PrinterDevice: //0x02, + sb.AppendLine("Printer device"); + + break; + case PeripheralDeviceTypes.ProcessorDevice: //0x03, + sb.AppendLine("Processor device"); + + break; + case PeripheralDeviceTypes.WriteOnceDevice: //0x04, + sb.AppendLine("Write-once device"); + + break; + case PeripheralDeviceTypes.MultiMediaDevice: //0x05, + sb.AppendLine("CD-ROM/DVD/etc device"); + + break; + case PeripheralDeviceTypes.ScannerDevice: //0x06, + sb.AppendLine("Scanner device"); + + break; + case PeripheralDeviceTypes.OpticalDevice: //0x07, + sb.AppendLine("Optical memory device"); + + break; + case PeripheralDeviceTypes.MediumChangerDevice: //0x08, + sb.AppendLine("Medium change device"); + + break; + case PeripheralDeviceTypes.CommsDevice: //0x09, + sb.AppendLine("Communications device"); + + break; + case PeripheralDeviceTypes.PrePressDevice1: //0x0A, + sb.AppendLine("Graphics arts pre-press device (defined in ASC IT8)"); + + break; + case PeripheralDeviceTypes.PrePressDevice2: //0x0B, + sb.AppendLine("Graphics arts pre-press device (defined in ASC IT8)"); + + break; + case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, + sb.AppendLine("Array controller device"); + + break; + case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, + sb.AppendLine("Enclosure services device"); + + break; + case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, + sb.AppendLine("Simplified direct-access device"); + + break; + case PeripheralDeviceTypes.OCRWDevice: //0x0F, + sb.AppendLine("Optical card reader/writer device"); + + break; + case PeripheralDeviceTypes.BridgingExpander: //0x10, + sb.AppendLine("Bridging Expanders"); + + break; + case PeripheralDeviceTypes.ObjectDevice: //0x11, + sb.AppendLine("Object-based Storage Device"); + + break; + case PeripheralDeviceTypes.ADCDevice: //0x12, + sb.AppendLine("Automation/Drive Interface"); + + break; + case PeripheralDeviceTypes.SCSISecurityManagerDevice: //0x13, + sb.AppendLine("Security Manager Device"); - switch((PeripheralQualifiers)response.PeripheralQualifier) - { - case PeripheralQualifiers.Supported: - sb.AppendLine("Device is connected and supported."); + break; + case PeripheralDeviceTypes.SCSIZonedBlockDevice: //0x14 + sb.AppendLine("Host managed zoned block device"); - break; - case PeripheralQualifiers.Unconnected: - sb.AppendLine("Device is supported but not connected."); + break; + case PeripheralDeviceTypes.WellKnownDevice: //0x1E, + sb.AppendLine("Well known logical unit"); - break; - case PeripheralQualifiers.Reserved: - sb.AppendLine("Reserved value set in Peripheral Qualifier field."); + break; + case PeripheralDeviceTypes.UnknownDevice: //0x1F + sb.AppendLine("Unknown or no device type"); - break; - case PeripheralQualifiers.Unsupported: - sb.AppendLine("Device is connected but unsupported."); + break; + default: + sb.AppendFormat("Unknown device type field value 0x{0:X2}", response.PeripheralDeviceType). + AppendLine(); - break; - default: - sb.AppendFormat("Vendor value {0} set in Peripheral Qualifier field.", - response.PeripheralQualifier).AppendLine(); + break; + } - break; - } + switch((ANSIVersions)response.ANSIVersion) + { + case ANSIVersions.ANSINoVersion: + sb.AppendLine("Device does not claim to comply with any SCSI ANSI standard"); - switch((PeripheralDeviceTypes)response.PeripheralDeviceType) - { - case PeripheralDeviceTypes.DirectAccess: //0x00, - sb.AppendLine("Direct-access device"); + break; + case ANSIVersions.ANSI1986Version: + sb.AppendLine("Device claims to comply with ANSI X3.131:1986 (SCSI-1)"); - break; - case PeripheralDeviceTypes.SequentialAccess: //0x01, - sb.AppendLine("Sequential-access device"); + break; + case ANSIVersions.ANSI1994Version: + sb.AppendLine("Device claims to comply with ANSI X3.131:1994 (SCSI-2)"); - break; - case PeripheralDeviceTypes.PrinterDevice: //0x02, - sb.AppendLine("Printer device"); + break; + case ANSIVersions.ANSI1997Version: + sb.AppendLine("Device claims to comply with ANSI X3.301:1997 (SPC-1)"); - break; - case PeripheralDeviceTypes.ProcessorDevice: //0x03, - sb.AppendLine("Processor device"); + break; + case ANSIVersions.ANSI2001Version: + sb.AppendLine("Device claims to comply with ANSI X3.351:2001 (SPC-2)"); - break; - case PeripheralDeviceTypes.WriteOnceDevice: //0x04, - sb.AppendLine("Write-once device"); + break; + case ANSIVersions.ANSI2005Version: + sb.AppendLine("Device claims to comply with ANSI X3.408:2005 (SPC-3)"); - break; - case PeripheralDeviceTypes.MultiMediaDevice: //0x05, - sb.AppendLine("CD-ROM/DVD/etc device"); + break; + case ANSIVersions.ANSI2008Version: + sb.AppendLine("Device claims to comply with ANSI X3.408:2005 (SPC-4)"); - break; - case PeripheralDeviceTypes.ScannerDevice: //0x06, - sb.AppendLine("Scanner device"); + break; + default: + sb.AppendFormat("Device claims to comply with unknown SCSI ANSI standard value 0x{0:X2})", + response.ANSIVersion).AppendLine(); - break; - case PeripheralDeviceTypes.OpticalDevice: //0x07, - sb.AppendLine("Optical memory device"); + break; + } - break; - case PeripheralDeviceTypes.MediumChangerDevice: //0x08, - sb.AppendLine("Medium change device"); + switch((ECMAVersions)response.ECMAVersion) + { + case ECMAVersions.ECMANoVersion: + sb.AppendLine("Device does not claim to comply with any SCSI ECMA standard"); - break; - case PeripheralDeviceTypes.CommsDevice: //0x09, - sb.AppendLine("Communications device"); + break; + case ECMAVersions.ECMA111: + sb.AppendLine("Device claims to comply ECMA-111: Small Computer System Interface SCSI"); - break; - case PeripheralDeviceTypes.PrePressDevice1: //0x0A, - sb.AppendLine("Graphics arts pre-press device (defined in ASC IT8)"); + break; + default: + sb.AppendFormat("Device claims to comply with unknown SCSI ECMA standard value 0x{0:X2})", + response.ECMAVersion).AppendLine(); - break; - case PeripheralDeviceTypes.PrePressDevice2: //0x0B, - sb.AppendLine("Graphics arts pre-press device (defined in ASC IT8)"); + break; + } - break; - case PeripheralDeviceTypes.ArrayControllerDevice: //0x0C, - sb.AppendLine("Array controller device"); + switch((ISOVersions)response.ISOVersion) + { + case ISOVersions.ISONoVersion: + sb.AppendLine("Device does not claim to comply with any SCSI ISO/IEC standard"); - break; - case PeripheralDeviceTypes.EnclosureServiceDevice: //0x0D, - sb.AppendLine("Enclosure services device"); + break; + case ISOVersions.ISO1995Version: + sb.AppendLine("Device claims to comply with ISO/IEC 9316:1995"); - break; - case PeripheralDeviceTypes.SimplifiedDevice: //0x0E, - sb.AppendLine("Simplified direct-access device"); + break; + default: + sb.AppendFormat("Device claims to comply with unknown SCSI ISO/IEC standard value 0x{0:X2})", + response.ISOVersion).AppendLine(); - break; - case PeripheralDeviceTypes.OCRWDevice: //0x0F, - sb.AppendLine("Optical card reader/writer device"); + break; + } - break; - case PeripheralDeviceTypes.BridgingExpander: //0x10, - sb.AppendLine("Bridging Expanders"); + if(response.RMB) + sb.AppendLine("Device is removable"); - break; - case PeripheralDeviceTypes.ObjectDevice: //0x11, - sb.AppendLine("Object-based Storage Device"); - - break; - case PeripheralDeviceTypes.ADCDevice: //0x12, - sb.AppendLine("Automation/Drive Interface"); - - break; - case PeripheralDeviceTypes.SCSISecurityManagerDevice: //0x13, - sb.AppendLine("Security Manager Device"); + if(response.AERC) + sb.AppendLine("Device supports Asynchronous Event Reporting Capability"); - break; - case PeripheralDeviceTypes.SCSIZonedBlockDevice: //0x14 - sb.AppendLine("Host managed zoned block device"); + if(response.TrmTsk) + sb.AppendLine("Device supports TERMINATE TASK command"); - break; - case PeripheralDeviceTypes.WellKnownDevice: //0x1E, - sb.AppendLine("Well known logical unit"); + if(response.NormACA) + sb.AppendLine("Device supports setting Normal ACA"); - break; - case PeripheralDeviceTypes.UnknownDevice: //0x1F - sb.AppendLine("Unknown or no device type"); + if(response.HiSup) + sb.AppendLine("Device supports LUN hierarchical addressing"); - break; - default: - sb.AppendFormat("Unknown device type field value 0x{0:X2}", response.PeripheralDeviceType). - AppendLine(); + if(response.SCCS) + sb.AppendLine("Device contains an embedded storage array controller"); - break; - } + if(response.ACC) + sb.AppendLine("Device contains an Access Control Coordinator"); - switch((ANSIVersions)response.ANSIVersion) - { - case ANSIVersions.ANSINoVersion: - sb.AppendLine("Device does not claim to comply with any SCSI ANSI standard"); + if(response.ThreePC) + sb.AppendLine("Device supports third-party copy commands"); - break; - case ANSIVersions.ANSI1986Version: - sb.AppendLine("Device claims to comply with ANSI X3.131:1986 (SCSI-1)"); + if(response.Protect) + sb.AppendLine("Device supports protection information"); - break; - case ANSIVersions.ANSI1994Version: - sb.AppendLine("Device claims to comply with ANSI X3.131:1994 (SCSI-2)"); + if(response.BQue) + sb.AppendLine("Device supports basic queueing"); - break; - case ANSIVersions.ANSI1997Version: - sb.AppendLine("Device claims to comply with ANSI X3.301:1997 (SPC-1)"); + if(response.EncServ) + sb.AppendLine("Device contains an embedded enclosure services component"); - break; - case ANSIVersions.ANSI2001Version: - sb.AppendLine("Device claims to comply with ANSI X3.351:2001 (SPC-2)"); + if(response.MultiP) + sb.AppendLine("Multi-port device"); - break; - case ANSIVersions.ANSI2005Version: - sb.AppendLine("Device claims to comply with ANSI X3.408:2005 (SPC-3)"); + if(response.MChngr) + sb.AppendLine("Device contains or is attached to a medium changer"); - break; - case ANSIVersions.ANSI2008Version: - sb.AppendLine("Device claims to comply with ANSI X3.408:2005 (SPC-4)"); + if(response.ACKREQQ) + sb.AppendLine("Device supports request and acknowledge handshakes"); - break; - default: - sb.AppendFormat("Device claims to comply with unknown SCSI ANSI standard value 0x{0:X2})", - response.ANSIVersion).AppendLine(); + if(response.Addr32) + sb.AppendLine("Device supports 32-bit wide SCSI addresses"); - break; - } + if(response.Addr16) + sb.AppendLine("Device supports 16-bit wide SCSI addresses"); - switch((ECMAVersions)response.ECMAVersion) - { - case ECMAVersions.ECMANoVersion: - sb.AppendLine("Device does not claim to comply with any SCSI ECMA standard"); + if(response.RelAddr) + sb.AppendLine("Device supports relative addressing"); - break; - case ECMAVersions.ECMA111: - sb.AppendLine("Device claims to comply ECMA-111: Small Computer System Interface SCSI"); + if(response.WBus32) + sb.AppendLine("Device supports 32-bit wide data transfers"); - break; - default: - sb.AppendFormat("Device claims to comply with unknown SCSI ECMA standard value 0x{0:X2})", - response.ECMAVersion).AppendLine(); + if(response.WBus16) + sb.AppendLine("Device supports 16-bit wide data transfers"); - break; - } + if(response.Sync) + sb.AppendLine("Device supports synchronous data transfer"); - switch((ISOVersions)response.ISOVersion) - { - case ISOVersions.ISONoVersion: - sb.AppendLine("Device does not claim to comply with any SCSI ISO/IEC standard"); + if(response.Linked) + sb.AppendLine("Device supports linked commands"); - break; - case ISOVersions.ISO1995Version: - sb.AppendLine("Device claims to comply with ISO/IEC 9316:1995"); + if(response.TranDis) + sb.AppendLine("Device supports CONTINUE TASK and TARGET TRANSFER DISABLE commands"); - break; - default: - sb.AppendFormat("Device claims to comply with unknown SCSI ISO/IEC standard value 0x{0:X2})", - response.ISOVersion).AppendLine(); + if(response.QAS) + sb.AppendLine("Device supports Quick Arbitration and Selection"); - break; - } + if(response.CmdQue) + sb.AppendLine("Device supports TCQ queue"); - if(response.RMB) - sb.AppendLine("Device is removable"); + if(response.IUS) + sb.AppendLine("Device supports information unit transfers"); - if(response.AERC) - sb.AppendLine("Device supports Asynchronous Event Reporting Capability"); + if(response.SftRe) + sb.AppendLine("Device implements RESET as a soft reset"); + #if DEBUG + if(response.VS1) + sb.AppendLine("Vendor specific bit 5 on byte 6 of INQUIRY response is set"); + #endif - if(response.TrmTsk) - sb.AppendLine("Device supports TERMINATE TASK command"); + switch((TGPSValues)response.TPGS) + { + case TGPSValues.NotSupported: + sb.AppendLine("Device does not support asymmetrical access"); - if(response.NormACA) - sb.AppendLine("Device supports setting Normal ACA"); + break; + case TGPSValues.OnlyImplicit: + sb.AppendLine("Device only supports implicit asymmetrical access"); - if(response.HiSup) - sb.AppendLine("Device supports LUN hierarchical addressing"); + break; + case TGPSValues.OnlyExplicit: + sb.AppendLine("Device only supports explicit asymmetrical access"); - if(response.SCCS) - sb.AppendLine("Device contains an embedded storage array controller"); + break; + case TGPSValues.Both: + sb.AppendLine("Device supports implicit and explicit asymmetrical access"); - if(response.ACC) - sb.AppendLine("Device contains an Access Control Coordinator"); + break; + default: + sb.AppendFormat("Unknown value in TPGS field 0x{0:X2}", response.TPGS).AppendLine(); - if(response.ThreePC) - sb.AppendLine("Device supports third-party copy commands"); + break; + } - if(response.Protect) - sb.AppendLine("Device supports protection information"); + switch((SPIClocking)response.Clocking) + { + case SPIClocking.ST: + sb.AppendLine("Device supports only ST clocking"); - if(response.BQue) - sb.AppendLine("Device supports basic queueing"); + break; + case SPIClocking.DT: + sb.AppendLine("Device supports only DT clocking"); - if(response.EncServ) - sb.AppendLine("Device contains an embedded enclosure services component"); + break; + case SPIClocking.Reserved: + sb.AppendLine("Reserved value 0x02 found in SPI clocking field"); - if(response.MultiP) - sb.AppendLine("Multi-port device"); + break; + case SPIClocking.STandDT: + sb.AppendLine("Device supports ST and DT clocking"); - if(response.MChngr) - sb.AppendLine("Device contains or is attached to a medium changer"); + break; + default: + sb.AppendFormat("Unknown value in SPI clocking field 0x{0:X2}", response.Clocking).AppendLine(); - if(response.ACKREQQ) - sb.AppendLine("Device supports request and acknowledge handshakes"); + break; + } - if(response.Addr32) - sb.AppendLine("Device supports 32-bit wide SCSI addresses"); - - if(response.Addr16) - sb.AppendLine("Device supports 16-bit wide SCSI addresses"); - - if(response.RelAddr) - sb.AppendLine("Device supports relative addressing"); - - if(response.WBus32) - sb.AppendLine("Device supports 32-bit wide data transfers"); - - if(response.WBus16) - sb.AppendLine("Device supports 16-bit wide data transfers"); - - if(response.Sync) - sb.AppendLine("Device supports synchronous data transfer"); - - if(response.Linked) - sb.AppendLine("Device supports linked commands"); - - if(response.TranDis) - sb.AppendLine("Device supports CONTINUE TASK and TARGET TRANSFER DISABLE commands"); - - if(response.QAS) - sb.AppendLine("Device supports Quick Arbitration and Selection"); - - if(response.CmdQue) - sb.AppendLine("Device supports TCQ queue"); - - if(response.IUS) - sb.AppendLine("Device supports information unit transfers"); - - if(response.SftRe) - sb.AppendLine("Device implements RESET as a soft reset"); - #if DEBUG - if(response.VS1) - sb.AppendLine("Vendor specific bit 5 on byte 6 of INQUIRY response is set"); - #endif - - switch((TGPSValues)response.TPGS) - { - case TGPSValues.NotSupported: - sb.AppendLine("Device does not support asymmetrical access"); - - break; - case TGPSValues.OnlyImplicit: - sb.AppendLine("Device only supports implicit asymmetrical access"); - - break; - case TGPSValues.OnlyExplicit: - sb.AppendLine("Device only supports explicit asymmetrical access"); - - break; - case TGPSValues.Both: - sb.AppendLine("Device supports implicit and explicit asymmetrical access"); - - break; - default: - sb.AppendFormat("Unknown value in TPGS field 0x{0:X2}", response.TPGS).AppendLine(); - - break; - } - - switch((SPIClocking)response.Clocking) - { - case SPIClocking.ST: - sb.AppendLine("Device supports only ST clocking"); - - break; - case SPIClocking.DT: - sb.AppendLine("Device supports only DT clocking"); - - break; - case SPIClocking.Reserved: - sb.AppendLine("Reserved value 0x02 found in SPI clocking field"); - - break; - case SPIClocking.STandDT: - sb.AppendLine("Device supports ST and DT clocking"); - - break; - default: - sb.AppendFormat("Unknown value in SPI clocking field 0x{0:X2}", response.Clocking).AppendLine(); - - break; - } - - if(response.VersionDescriptors != null) - foreach(ushort VersionDescriptor in response.VersionDescriptors) - switch(VersionDescriptor) - { - case 0xFFFF: - case 0x0000: break; - case 0x0020: - sb.AppendLine("Device complies with SAM (no version claimed)"); - - break; - case 0x003B: - sb.AppendLine("Device complies with SAM T10/0994-D revision 18"); - - break; - case 0x003C: - sb.AppendLine("Device complies with SAM ANSI INCITS 270-1996"); - - break; - case 0x0040: - sb.AppendLine("Device complies with SAM-2 (no version claimed)"); - - break; - case 0x0054: - sb.AppendLine("Device complies with SAM-2 T10/1157-D revision 23"); - - break; - case 0x0055: - sb.AppendLine("Device complies with SAM-2 T10/1157-D revision 24"); - - break; - case 0x005C: - sb.AppendLine("Device complies with SAM-2 ANSI INCITS 366-2003"); - - break; - case 0x005E: - sb.AppendLine("Device complies with SAM-2 ISO/IEC 14776-412"); - - break; - case 0x0060: - sb.AppendLine("Device complies with SAM-3 (no version claimed)"); - - break; - case 0x0062: - sb.AppendLine("Device complies with SAM-3 T10/1561-D revision 7"); - - break; - case 0x0075: - sb.AppendLine("Device complies with SAM-3 T10/1561-D revision 13"); - - break; - case 0x0076: - sb.AppendLine("Device complies with SAM-3 T10/1561-D revision 14"); - - break; - case 0x0077: - sb.AppendLine("Device complies with SAM-3 ANSI INCITS 402-2005"); - - break; - case 0x0080: - sb.AppendLine("Device complies with SAM-4 (no version claimed)"); - - break; - case 0x0087: - sb.AppendLine("Device complies with SAM-4 T10/1683-D revision 13"); - - break; - case 0x008B: - sb.AppendLine("Device complies with SAM-4 T10/1683-D revision 14"); - - break; - case 0x0090: - sb.AppendLine("Device complies with SAM-4 ANSI INCITS 447-2008"); - - break; - case 0x0092: - sb.AppendLine("Device complies with SAM-4 ISO/IEC 14776-414"); - - break; - case 0x00A0: - sb.AppendLine("Device complies with SAM-5 (no version claimed)"); - - break; - case 0x00A2: - sb.AppendLine("Device complies with SAM-5 T10/2104-D revision 4"); - - break; - case 0x00A4: - sb.AppendLine("Device complies with SAM-5 T10/2104-D revision 20"); - - break; - case 0x00A6: - sb.AppendLine("Device complies with SAM-5 T10/2104-D revision 21"); - - break; - case 0x00C0: - sb.AppendLine("Device complies with SAM-6 (no version claimed)"); - - break; - case 0x0120: - sb.AppendLine("Device complies with SPC (no version claimed)"); - - break; - case 0x013B: - sb.AppendLine("Device complies with SPC T10/0995-D revision 11a"); - - break; - case 0x013C: - sb.AppendLine("Device complies with SPC ANSI INCITS 301-1997"); - - break; - case 0x0140: - sb.AppendLine("Device complies with MMC (no version claimed)"); - - break; - case 0x015B: - sb.AppendLine("Device complies with MMC T10/1048-D revision 10a"); - - break; - case 0x015C: - sb.AppendLine("Device complies with MMC ANSI INCITS 304-1997"); - - break; - case 0x0160: - sb.AppendLine("Device complies with SCC (no version claimed)"); - - break; - case 0x017B: - sb.AppendLine("Device complies with SCC T10/1047-D revision 06c"); - - break; - case 0x017C: - sb.AppendLine("Device complies with SCC ANSI INCITS 276-1997"); - - break; - case 0x0180: - sb.AppendLine("Device complies with SBC (no version claimed)"); - - break; - case 0x019B: - sb.AppendLine("Device complies with SBC T10/0996-D revision 08c"); - - break; - case 0x019C: - sb.AppendLine("Device complies with SBC ANSI INCITS 306-1998"); - - break; - case 0x01A0: - sb.AppendLine("Device complies with SMC (no version claimed)"); - - break; - case 0x01BB: - sb.AppendLine("Device complies with SMC T10/0999-D revision 10a"); - - break; - case 0x01BC: - sb.AppendLine("Device complies with SMC ANSI INCITS 314-1998"); - - break; - case 0x01BE: - sb.AppendLine("Device complies with SMC ISO/IEC 14776-351"); - - break; - case 0x01C0: - sb.AppendLine("Device complies with SES (no version claimed)"); - - break; - case 0x01DB: - sb.AppendLine("Device complies with SES T10/1212-D revision 08b"); - - break; - case 0x01DC: - sb.AppendLine("Device complies with SES ANSI INCITS 305-1998"); - - break; - case 0x01DD: - sb.AppendLine("Device complies with SES T10/1212 revision 08b w/ Amendment ANSI INCITS.305/AM1-2000"); - - break; - case 0x01DE: - sb.AppendLine("Device complies with SES ANSI INCITS 305-1998 w/ Amendment ANSI INCITS.305/AM1-2000"); - - break; - case 0x01E0: - sb.AppendLine("Device complies with SCC-2 (no version claimed)"); - - break; - case 0x01FB: - sb.AppendLine("Device complies with SCC-2 T10/1125-D revision 04"); - - break; - case 0x01FC: - sb.AppendLine("Device complies with SCC-2 ANSI INCITS 318-1998"); - - break; - case 0x0200: - sb.AppendLine("Device complies with SSC (no version claimed)"); - - break; - case 0x0201: - sb.AppendLine("Device complies with SSC T10/0997-D revision 17"); - - break; - case 0x0207: - sb.AppendLine("Device complies with SSC T10/0997-D revision 22"); - - break; - case 0x021C: - sb.AppendLine("Device complies with SSC ANSI INCITS 335-2000"); - - break; - case 0x0220: - sb.AppendLine("Device complies with RBC (no version claimed)"); - - break; - case 0x0238: - sb.AppendLine("Device complies with RBC T10/1240-D revision 10a"); - - break; - case 0x023C: - sb.AppendLine("Device complies with RBC ANSI INCITS 330-2000"); - - break; - case 0x0240: - sb.AppendLine("Device complies with MMC-2 (no version claimed)"); - - break; - case 0x0255: - sb.AppendLine("Device complies with MMC-2 T10/1228-D revision 11"); - - break; - case 0x025B: - sb.AppendLine("Device complies with MMC-2 T10/1228-D revision 11a"); - - break; - case 0x025C: - sb.AppendLine("Device complies with MMC-2 ANSI INCITS 333-2000"); - - break; - case 0x0260: - sb.AppendLine("Device complies with SPC-2 (no version claimed)"); - - break; - case 0x0267: - sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 12"); - - break; - case 0x0269: - sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 18"); - - break; - case 0x0275: - sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 19"); - - break; - case 0x0276: - sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 20"); - - break; - case 0x0277: - sb.AppendLine("Device complies with SPC-2 ANSI INCITS 351-2001"); - - break; - case 0x0278: - sb.AppendLine("Device complies with SPC-2 ISO/IEC 14776-452"); - - break; - case 0x0280: - sb.AppendLine("Device complies with OCRW (no version claimed)"); - - break; - case 0x029E: - sb.AppendLine("Device complies with OCRW ISO/IEC 14776-381"); - - break; - case 0x02A0: - sb.AppendLine("Device complies with MMC-3 (no version claimed)"); - - break; - case 0x02B5: - sb.AppendLine("Device complies with MMC-3 T10/1363-D revision 9"); - - break; - case 0x02B6: - sb.AppendLine("Device complies with MMC-3 T10/1363-D revision 10g"); - - break; - case 0x02B8: - sb.AppendLine("Device complies with MMC-3 ANSI INCITS 360-2002"); - - break; - case 0x02E0: - sb.AppendLine("Device complies with SMC-2 (no version claimed)"); - - break; - case 0x02F5: - sb.AppendLine("Device complies with SMC-2 T10/1383-D revision 5"); - - break; - case 0x02FC: - sb.AppendLine("Device complies with SMC-2 T10/1383-D revision 6"); - - break; - case 0x02FD: - sb.AppendLine("Device complies with SMC-2 T10/1383-D revision 7"); - - break; - case 0x02FE: - sb.AppendLine("Device complies with SMC-2 ANSI INCITS 382-2004"); - - break; - case 0x0300: - sb.AppendLine("Device complies with SPC-3 (no version claimed)"); - - break; - case 0x0301: - sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 7"); - - break; - case 0x0307: - sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 21"); - - break; - case 0x030F: - sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 22"); - - break; - case 0x0312: - sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 23"); - - break; - case 0x0314: - sb.AppendLine("Device complies with SPC-3 ANSI INCITS 408-2005"); - - break; - case 0x0316: - sb.AppendLine("Device complies with SPC-3 ISO/IEC 14776-453"); - - break; - case 0x0320: - sb.AppendLine("Device complies with SBC-2 (no version claimed)"); - - break; - case 0x0322: - sb.AppendLine("Device complies with SBC-2 T10/1417-D revision 5a"); - - break; - case 0x0324: - sb.AppendLine("Device complies with SBC-2 T10/1417-D revision 15"); - - break; - case 0x033B: - sb.AppendLine("Device complies with SBC-2 T10/1417-D revision 16"); - - break; - case 0x033D: - sb.AppendLine("Device complies with SBC-2 ANSI INCITS 405-2005"); - - break; - case 0x033E: - sb.AppendLine("Device complies with SBC-2 ISO/IEC 14776-322"); - - break; - case 0x0340: - sb.AppendLine("Device complies with OSD (no version claimed)"); - - break; - case 0x0341: - sb.AppendLine("Device complies with OSD T10/1355-D revision 0"); - - break; - case 0x0342: - sb.AppendLine("Device complies with OSD T10/1355-D revision 7a"); - - break; - case 0x0343: - sb.AppendLine("Device complies with OSD T10/1355-D revision 8"); - - break; - case 0x0344: - sb.AppendLine("Device complies with OSD T10/1355-D revision 9"); - - break; - case 0x0355: - sb.AppendLine("Device complies with OSD T10/1355-D revision 10"); - - break; - case 0x0356: - sb.AppendLine("Device complies with OSD ANSI INCITS 400-2004"); - - break; - case 0x0360: - sb.AppendLine("Device complies with SSC-2 (no version claimed)"); - - break; - case 0x0374: - sb.AppendLine("Device complies with SSC-2 T10/1434-D revision 7"); - - break; - case 0x0375: - sb.AppendLine("Device complies with SSC-2 T10/1434-D revision 9"); - - break; - case 0x037D: - sb.AppendLine("Device complies with SSC-2 ANSI INCITS 380-2003"); - - break; - case 0x0380: - sb.AppendLine("Device complies with BCC (no version claimed)"); - - break; - case 0x03A0: - sb.AppendLine("Device complies with MMC-4 (no version claimed)"); - - break; - case 0x03B0: - sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 5"); - - break; - case 0x03B1: - sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 5a"); - - break; - case 0x03BD: - sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 3"); - - break; - case 0x03BE: - sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 3d"); - - break; - case 0x03BF: - sb.AppendLine("Device complies with MMC-4 ANSI INCITS 401-2005"); - - break; - case 0x03C0: - sb.AppendLine("Device complies with ADC (no version claimed)"); - - break; - case 0x03D5: - sb.AppendLine("Device complies with ADC T10/1558-D revision 6"); - - break; - case 0x03D6: - sb.AppendLine("Device complies with ADC T10/1558-D revision 7"); - - break; - case 0x03D7: - sb.AppendLine("Device complies with ADC ANSI INCITS 403-2005"); - - break; - case 0x03E0: - sb.AppendLine("Device complies with SES-2 (no version claimed)"); - - break; - case 0x03E1: - sb.AppendLine("Device complies with SES-2 T10/1559-D revision 16"); - - break; - case 0x03E7: - sb.AppendLine("Device complies with SES-2 T10/1559-D revision 19"); - - break; - case 0x03EB: - sb.AppendLine("Device complies with SES-2 T10/1559-D revision 20"); - - break; - case 0x03F0: - sb.AppendLine("Device complies with SES-2 ANSI INCITS 448-2008"); - - break; - case 0x03F2: - sb.AppendLine("Device complies with SES-2 ISO/IEC 14776-372"); - - break; - case 0x0400: - sb.AppendLine("Device complies with SSC-3 (no version claimed)"); - - break; - case 0x0403: - sb.AppendLine("Device complies with SSC-3 T10/1611-D revision 04a"); - - break; - case 0x0407: - sb.AppendLine("Device complies with SSC-3 T10/1611-D revision 05"); - - break; - case 0x0409: - sb.AppendLine("Device complies with SSC-3 ANSI INCITS 467-2011"); - - break; - case 0x040B: - sb.AppendLine("Device complies with SSC-3 ISO/IEC 14776-333:2013"); - - break; - case 0x0420: - sb.AppendLine("Device complies with MMC-5 (no version claimed)"); - - break; - case 0x042F: - sb.AppendLine("Device complies with MMC-5 T10/1675-D revision 03"); - - break; - case 0x0431: - sb.AppendLine("Device complies with MMC-5 T10/1675-D revision 03b"); - - break; - case 0x0432: - sb.AppendLine("Device complies with MMC-5 T10/1675-D revision 04"); - - break; - case 0x0434: - sb.AppendLine("Device complies with MMC-5 ANSI INCITS 430-2007"); - - break; - case 0x0440: - sb.AppendLine("Device complies with OSD-2 (no version claimed)"); - - break; - case 0x0444: - sb.AppendLine("Device complies with OSD-2 T10/1729-D revision 4"); - - break; - case 0x0446: - sb.AppendLine("Device complies with OSD-2 T10/1729-D revision 5"); - - break; - case 0x0448: - sb.AppendLine("Device complies with OSD-2 ANSI INCITS 458-2011"); - - break; - case 0x0460: - sb.AppendLine("Device complies with SPC-4 (no version claimed)"); - - break; - case 0x0461: - sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 16"); - - break; - case 0x0462: - sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 18"); - - break; - case 0x0463: - sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 23"); - - break; - case 0x0466: - sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 36"); - - break; - case 0x0468: - sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 37"); - - break; - case 0x0469: - sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 37a"); - - break; - case 0x046C: - sb.AppendLine("Device complies with SPC-4 ANSI INCITS 513-2015"); - - break; - case 0x0480: - sb.AppendLine("Device complies with SMC-3 (no version claimed)"); - - break; - case 0x0482: - sb.AppendLine("Device complies with SMC-3 T10/1730-D revision 15"); - - break; - case 0x0484: - sb.AppendLine("Device complies with SMC-3 T10/1730-D revision 16"); - - break; - case 0x0486: - sb.AppendLine("Device complies with SMC-3 ANSI INCITS 484-2012"); - - break; - case 0x04A0: - sb.AppendLine("Device complies with ADC-2 (no version claimed)"); - - break; - case 0x04A7: - sb.AppendLine("Device complies with ADC-2 T10/1741-D revision 7"); - - break; - case 0x04AA: - sb.AppendLine("Device complies with ADC-2 T10/1741-D revision 8"); - - break; - case 0x04AC: - sb.AppendLine("Device complies with ADC-2 ANSI INCITS 441-2008"); - - break; - case 0x04C0: - sb.AppendLine("Device complies with SBC-3 (no version claimed)"); - - break; - case 0x04C3: - sb.AppendLine("Device complies with SBC-3 T10/BSR INCITS 514 revision 35"); - - break; - case 0x04C5: - sb.AppendLine("Device complies with SBC-3 T10/BSR INCITS 514 revision 36"); - - break; - case 0x04C8: - sb.AppendLine("Device complies with SBC-3 ANSI INCITS 514-2014"); - - break; - case 0x04E0: - sb.AppendLine("Device complies with MMC-6 (no version claimed)"); - - break; - case 0x04E3: - sb.AppendLine("Device complies with MMC-6 T10/1836-D revision 02b"); - - break; - case 0x04E5: - sb.AppendLine("Device complies with MMC-6 T10/1836-D revision 02g"); - - break; - case 0x04E6: - sb.AppendLine("Device complies with MMC-6 ANSI INCITS 468-2010"); - - break; - case 0x04E7: - sb.AppendLine("Device complies with MMC-6 ANSI INCITS 468-2010 + MMC-6/AM1 ANSI INCITS 468-2010/AM 1"); - - break; - case 0x0500: - sb.AppendLine("Device complies with ADC-3 (no version claimed)"); - - break; - case 0x0502: - sb.AppendLine("Device complies with ADC-3 T10/1895-D revision 04"); - - break; - case 0x0504: - sb.AppendLine("Device complies with ADC-3 T10/1895-D revision 05"); - - break; - case 0x0506: - sb.AppendLine("Device complies with ADC-3 T10/1895-D revision 05a"); - - break; - case 0x050A: - sb.AppendLine("Device complies with ADC-3 ANSI INCITS 497-2012"); - - break; - case 0x0520: - sb.AppendLine("Device complies with SSC-4 (no version claimed)"); - - break; - case 0x0523: - sb.AppendLine("Device complies with SSC-4 T10/BSR INCITS 516 revision 2"); - - break; - case 0x0525: - sb.AppendLine("Device complies with SSC-4 T10/BSR INCITS 516 revision 3"); - - break; - case 0x0527: - sb.AppendLine("Device complies with SSC-4 ANSI INCITS 516-2013"); - - break; - case 0x0560: - sb.AppendLine("Device complies with OSD-3 (no version claimed)"); - - break; - case 0x0580: - sb.AppendLine("Device complies with SES-3 (no version claimed)"); - - break; - case 0x05A0: - sb.AppendLine("Device complies with SSC-5 (no version claimed)"); - - break; - case 0x05C0: - sb.AppendLine("Device complies with SPC-5 (no version claimed)"); - - break; - case 0x05E0: - sb.AppendLine("Device complies with SFSC (no version claimed)"); - - break; - case 0x05E3: - sb.AppendLine("Device complies with SFSC BSR INCITS 501 revision 01"); - - break; - case 0x0600: - sb.AppendLine("Device complies with SBC-4 (no version claimed)"); - - break; - case 0x0620: - sb.AppendLine("Device complies with ZBC (no version claimed)"); - - break; - case 0x0622: - sb.AppendLine("Device complies with ZBC BSR INCITS 536 revision 02"); - - break; - case 0x0640: - sb.AppendLine("Device complies with ADC-4 (no version claimed)"); - - break; - case 0x0820: - sb.AppendLine("Device complies with SSA-TL2 (no version claimed)"); - - break; - case 0x083B: - sb.AppendLine("Device complies with SSA-TL2 T10.1/1147-D revision 05b"); - - break; - case 0x083C: - sb.AppendLine("Device complies with SSA-TL2 ANSI INCITS 308-1998"); - - break; - case 0x0840: - sb.AppendLine("Device complies with SSA-TL1 (no version claimed)"); - - break; - case 0x085B: - sb.AppendLine("Device complies with SSA-TL1 T10.1/0989-D revision 10b"); - - break; - case 0x085C: - sb.AppendLine("Device complies with SSA-TL1 ANSI INCITS 295-1996"); - - break; - case 0x0860: - sb.AppendLine("Device complies with SSA-S3P (no version claimed)"); - - break; - case 0x087B: - sb.AppendLine("Device complies with SSA-S3P T10.1/1051-D revision 05b"); - - break; - case 0x087C: - sb.AppendLine("Device complies with SSA-S3P ANSI INCITS 309-1998"); - - break; - case 0x0880: - sb.AppendLine("Device complies with SSA-S2P (no version claimed)"); - - break; - case 0x089B: - sb.AppendLine("Device complies with SSA-S2P T10.1/1121-D revision 07b"); - - break; - case 0x089C: - sb.AppendLine("Device complies with SSA-S2P ANSI INCITS 294-1996"); - - break; - case 0x08A0: - sb.AppendLine("Device complies with SIP (no version claimed)"); - - break; - case 0x08BB: - sb.AppendLine("Device complies with SIP T10/0856-D revision 10"); - - break; - case 0x08BC: - sb.AppendLine("Device complies with SIP ANSI INCITS 292-1997"); - - break; - case 0x08C0: - sb.AppendLine("Device complies with FCP (no version claimed)"); - - break; - case 0x08DB: - sb.AppendLine("Device complies with FCP T10/0993-D revision 12"); - - break; - case 0x08DC: - sb.AppendLine("Device complies with FCP ANSI INCITS 269-1996"); - - break; - case 0x08E0: - sb.AppendLine("Device complies with SBP-2 (no version claimed)"); - - break; - case 0x08FB: - sb.AppendLine("Device complies with SBP-2 T10/1155-D revision 04"); - - break; - case 0x08FC: - sb.AppendLine("Device complies with SBP-2 ANSI INCITS 325-1998"); - - break; - case 0x0900: - sb.AppendLine("Device complies with FCP-2 (no version claimed)"); - - break; - case 0x0901: - sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 4"); - - break; - case 0x0915: - sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 7"); - - break; - case 0x0916: - sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 7a"); - - break; - case 0x0917: - sb.AppendLine("Device complies with FCP-2 ANSI INCITS 350-2003"); - - break; - case 0x0918: - sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 8"); - - break; - case 0x0920: - sb.AppendLine("Device complies with SST (no version claimed)"); - - break; - case 0x0935: - sb.AppendLine("Device complies with SST T10/1380-D revision 8b"); - - break; - case 0x0940: - sb.AppendLine("Device complies with SRP (no version claimed)"); - - break; - case 0x0954: - sb.AppendLine("Device complies with SRP T10/1415-D revision 10"); - - break; - case 0x0955: - sb.AppendLine("Device complies with SRP T10/1415-D revision 16a"); - - break; - case 0x095C: - sb.AppendLine("Device complies with SRP ANSI INCITS 365-2002"); - - break; - case 0x0960: - sb.AppendLine("Device complies with iSCSI (no version claimed)"); - - break; - case 0x0961: - case 0x0962: - case 0x0963: - case 0x0964: - case 0x0965: - case 0x0966: - case 0x0967: - case 0x0968: - case 0x0969: - case 0x096A: - case 0x096B: - case 0x096C: - case 0x096D: - case 0x096E: - case 0x096F: - case 0x0970: - case 0x0971: - case 0x0972: - case 0x0973: - case 0x0974: - case 0x0975: - case 0x0976: - case 0x0977: - case 0x0978: - case 0x0979: - case 0x097A: - case 0x097B: - case 0x097C: - case 0x097D: - case 0x097E: - case 0x097F: - sb.AppendFormat("Device complies with iSCSI revision {0}", VersionDescriptor & 0x1F). - AppendLine(); - - break; - case 0x0980: - sb.AppendLine("Device complies with SBP-3 (no version claimed)"); - - break; - case 0x0982: - sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 1f"); - - break; - case 0x0994: - sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 3"); - - break; - case 0x099A: - sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 4"); - - break; - case 0x099B: - sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 5"); - - break; - case 0x099C: - sb.AppendLine("Device complies with SBP-3 ANSI INCITS 375-2004"); - - break; - case 0x09C0: - sb.AppendLine("Device complies with ADP (no version claimed)"); - - break; - case 0x09E0: - sb.AppendLine("Device complies with ADT (no version claimed)"); - - break; - case 0x09F9: - sb.AppendLine("Device complies with ADT T10/1557-D revision 11"); - - break; - case 0x09FA: - sb.AppendLine("Device complies with ADT T10/1557-D revision 14"); - - break; - case 0x09FD: - sb.AppendLine("Device complies with ADT ANSI INCITS 406-2005"); - - break; - case 0x0A00: - sb.AppendLine("Device complies with FCP-3 (no version claimed)"); - - break; - case 0x0A07: - sb.AppendLine("Device complies with FCP-3 T10/1560-D revision 3f"); - - break; - case 0x0A0F: - sb.AppendLine("Device complies with FCP-3 T10/1560-D revision 4"); - - break; - case 0x0A11: - sb.AppendLine("Device complies with FCP-3 ANSI INCITS 416-2006"); - - break; - case 0x0A1C: - sb.AppendLine("Device complies with FCP-3 ISO/IEC 14776-223"); - - break; - case 0x0A20: - sb.AppendLine("Device complies with ADT-2 (no version claimed)"); - - break; - case 0x0A22: - sb.AppendLine("Device complies with ADT-2 T10/1742-D revision 06"); - - break; - case 0x0A27: - sb.AppendLine("Device complies with ADT-2 T10/1742-D revision 08"); - - break; - case 0x0A28: - sb.AppendLine("Device complies with ADT-2 T10/1742-D revision 09"); - - break; - case 0x0A2B: - sb.AppendLine("Device complies with ADT-2 ANSI INCITS 472-2011"); - - break; - case 0x0A40: - sb.AppendLine("Device complies with FCP-4 (no version claimed)"); - - break; - case 0x0A42: - sb.AppendLine("Device complies with FCP-4 T10/1828-D revision 01"); - - break; - case 0x0A44: - sb.AppendLine("Device complies with FCP-4 T10/1828-D revision 02"); - - break; - case 0x0A45: - sb.AppendLine("Device complies with FCP-4 T10/1828-D revision 02b"); - - break; - case 0x0A46: - sb.AppendLine("Device complies with FCP-4 ANSI INCITS 481-2012"); - - break; - case 0x0A60: - sb.AppendLine("Device complies with ADT-3 (no version claimed)"); - - break; - case 0x0AA0: - sb.AppendLine("Device complies with SPI (no version claimed)"); - - break; - case 0x0AB9: - sb.AppendLine("Device complies with SPI T10/0855-D revision 15a"); - - break; - case 0x0ABA: - sb.AppendLine("Device complies with SPI ANSI INCITS 253-1995"); - - break; - case 0x0ABB: - sb.AppendLine("Device complies with SPI T10/0855-D revision 15a with SPI Amnd revision 3a"); - - break; - case 0x0ABC: - sb.AppendLine("Device complies with SPI ANSI INCITS 253-1995 with SPI Amnd ANSI INCITS 253/AM1-1998"); - - break; - case 0x0AC0: - sb.AppendLine("Device complies with Fast-20 (no version claimed)"); - - break; - case 0x0ADB: - sb.AppendLine("Device complies with Fast-20 T10/1071 revision 06"); - - break; - case 0x0ADC: - sb.AppendLine("Device complies with Fast-20 ANSI INCITS 277-1996"); - - break; - case 0x0AE0: - sb.AppendLine("Device complies with SPI-2 (no version claimed)"); - - break; - case 0x0AFB: - sb.AppendLine("Device complies with SPI-2 T10/1142-D revision 20b"); - - break; - case 0x0AFC: - sb.AppendLine("Device complies with SPI-2 ANSI INCITS 302-1999"); - - break; - case 0x0B00: - sb.AppendLine("Device complies with SPI-3 (no version claimed)"); - - break; - case 0x0B18: - sb.AppendLine("Device complies with SPI-3 T10/1302-D revision 10"); - - break; - case 0x0B19: - sb.AppendLine("Device complies with SPI-3 T10/1302-D revision 13a"); - - break; - case 0x0B1A: - sb.AppendLine("Device complies with SPI-3 T10/1302-D revision 14"); - - break; - case 0x0B1C: - sb.AppendLine("Device complies with SPI-3 ANSI INCITS 336-2000"); - - break; - case 0x0B20: - sb.AppendLine("Device complies with EPI (no version claimed)"); - - break; - case 0x0B3B: - sb.AppendLine("Device complies with EPI T10/1134 revision 16"); - - break; - case 0x0B3C: - sb.AppendLine("Device complies with EPI ANSI INCITS TR-23 1999"); - - break; - case 0x0B40: - sb.AppendLine("Device complies with SPI-4 (no version claimed)"); - - break; - case 0x0B54: - sb.AppendLine("Device complies with SPI-4 T10/1365-D revision 7"); - - break; - case 0x0B55: - sb.AppendLine("Device complies with SPI-4 T10/1365-D revision 9"); - - break; - case 0x0B56: - sb.AppendLine("Device complies with SPI-4 ANSI INCITS 362-2002"); - - break; - case 0x0B59: - sb.AppendLine("Device complies with SPI-4 T10/1365-D revision 10"); - - break; - case 0x0B60: - sb.AppendLine("Device complies with SPI-5 (no version claimed)"); - - break; - case 0x0B79: - sb.AppendLine("Device complies with SPI-5 T10/1525-D revision 3"); - - break; - case 0x0B7A: - sb.AppendLine("Device complies with SPI-5 T10/1525-D revision 5"); - - break; - case 0x0B7B: - sb.AppendLine("Device complies with SPI-5 T10/1525-D revision 6"); - - break; - case 0x0B7C: - sb.AppendLine("Device complies with SPI-5 ANSI INCITS 367-2003"); - - break; - case 0x0BE0: - sb.AppendLine("Device complies with SAS (no version claimed)"); - - break; - case 0x0BE1: - sb.AppendLine("Device complies with SAS T10/1562-D revision 01"); - - break; - case 0x0BF5: - sb.AppendLine("Device complies with SAS T10/1562-D revision 03"); - - break; - case 0x0BFA: - sb.AppendLine("Device complies with SAS T10/1562-D revision 04"); - - break; - case 0x0BFB: - sb.AppendLine("Device complies with SAS T10/1562-D revision 04"); - - break; - case 0x0BFC: - sb.AppendLine("Device complies with SAS T10/1562-D revision 05"); - - break; - case 0x0BFD: - sb.AppendLine("Device complies with SAS ANSI INCITS 376-2003"); - - break; - case 0x0C00: - sb.AppendLine("Device complies with SAS-1.1 (no version claimed)"); - - break; - case 0x0C07: - sb.AppendLine("Device complies with SAS-1.1 T10/1601-D revision 9"); - - break; - case 0x0C0F: - sb.AppendLine("Device complies with SAS-1.1 T10/1601-D revision 10"); - - break; - case 0x0C11: - sb.AppendLine("Device complies with SAS-1.1 ANSI INCITS 417-2006"); - - break; - case 0x0C12: - sb.AppendLine("Device complies with SAS-1.1 ISO/IEC 14776-151"); - - break; - case 0x0C20: - sb.AppendLine("Device complies with SAS-2 (no version claimed)"); - - break; - case 0x0C23: - sb.AppendLine("Device complies with SAS-2 T10/1760-D revision 14"); - - break; - case 0x0C27: - sb.AppendLine("Device complies with SAS-2 T10/1760-D revision 15"); - - break; - case 0x0C28: - sb.AppendLine("Device complies with SAS-2 T10/1760-D revision 16"); - - break; - case 0x0C2A: - sb.AppendLine("Device complies with SAS-2 ANSI INCITS 457-2010"); - - break; - case 0x0C40: - sb.AppendLine("Device complies with SAS-2.1 (no version claimed)"); - - break; - case 0x0C48: - sb.AppendLine("Device complies with SAS-2.1 T10/2125-D revision 04"); - - break; - case 0x0C4A: - sb.AppendLine("Device complies with SAS-2.1 T10/2125-D revision 06"); - - break; - case 0x0C4B: - sb.AppendLine("Device complies with SAS-2.1 T10/2125-D revision 07"); - - break; - case 0x0C4E: - sb.AppendLine("Device complies with SAS-2.1 ANSI INCITS 478-2011"); - - break; - case 0x0C4F: - sb.AppendLine("Device complies with SAS-2.1 ANSI INCITS 478-2011 w/ Amnd 1 ANSI INCITS 478/AM1-2014"); - - break; - case 0x0C52: - sb.AppendLine("Device complies with SAS-2.1 ISO/IEC 14776-153"); - - break; - case 0x0C60: - sb.AppendLine("Device complies with SAS-3 (no version claimed)"); - - break; - case 0x0C63: - sb.AppendLine("Device complies with SAS-3 T10/BSR INCITS 519 revision 05a"); - - break; - case 0x0C65: - sb.AppendLine("Device complies with SAS-3 T10/BSR INCITS 519 revision 06"); - - break; - case 0x0C68: - sb.AppendLine("Device complies with SAS-3 ANSI INCITS 519-2014"); - - break; - case 0x0C80: - sb.AppendLine("Device complies with SAS-4 (no version claimed)"); - - break; - case 0x0D20: - sb.AppendLine("Device complies with FC-PH (no version claimed)"); - - break; - case 0x0D3B: - sb.AppendLine("Device complies with FC-PH ANSI INCITS 230-1994"); - - break; - case 0x0D3C: - sb.AppendLine("Device complies with FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS 230/AM1-1996"); - - break; - case 0x0D40: - sb.AppendLine("Device complies with FC-AL (no version claimed)"); - - break; - case 0x0D5C: - sb.AppendLine("Device complies with FC-AL ANSI INCITS 272-1996"); - - break; - case 0x0D60: - sb.AppendLine("Device complies with FC-AL-2 (no version claimed)"); - - break; - case 0x0D61: - sb.AppendLine("Device complies with FC-AL-2 T11/1133-D revision 7.0"); - - break; - case 0x0D63: - sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999 with AM1-2003 & AM2-2006"); - - break; - case 0x0D64: - sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 2 AM2-2006"); - - break; - case 0x0D65: - sb.AppendLine("Device complies with FC-AL-2 ISO/IEC 14165-122 with AM1 & AM2"); - - break; - case 0x0D7C: - sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999"); - - break; - case 0x0D7D: - sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1-2003"); - - break; - case 0x0D80: - sb.AppendLine("Device complies with FC-PH-3 (no version claimed)"); - - break; - case 0x0D9C: - sb.AppendLine("Device complies with FC-PH-3 ANSI INCITS 303-1998"); - - break; - case 0x0DA0: - sb.AppendLine("Device complies with FC-FS (no version claimed)"); - - break; - case 0x0DB7: - sb.AppendLine("Device complies with FC-FS T11/1331-D revision 1.2"); - - break; - case 0x0DB8: - sb.AppendLine("Device complies with FC-FS T11/1331-D revision 1.7"); - - break; - case 0x0DBC: - sb.AppendLine("Device complies with FC-FS ANSI INCITS 373-2003"); - - break; - case 0x0DBD: - sb.AppendLine("Device complies with FC-FS ISO/IEC 14165-251"); - - break; - case 0x0DC0: - sb.AppendLine("Device complies with FC-PI (no version claimed)"); - - break; - case 0x0DDC: - sb.AppendLine("Device complies with FC-PI ANSI INCITS 352-2002"); - - break; - case 0x0DE0: - sb.AppendLine("Device complies with FC-PI-2 (no version claimed)"); - - break; - case 0x0DE2: - sb.AppendLine("Device complies with FC-PI-2 T11/1506-D revision 5.0"); - - break; - case 0x0DE4: - sb.AppendLine("Device complies with FC-PI-2 ANSI INCITS 404-2006"); - - break; - case 0x0E00: - sb.AppendLine("Device complies with FC-FS-2 (no version claimed)"); - - break; - case 0x0E02: - sb.AppendLine("Device complies with FC-FS-2 ANSI INCITS 242-2007"); - - break; - case 0x0E03: - sb.AppendLine("Device complies with FC-FS-2 ANSI INCITS 242-2007 with AM1 ANSI INCITS 242/AM1-2007"); - - break; - case 0x0E20: - sb.AppendLine("Device complies with FC-LS (no version claimed)"); - - break; - case 0x0E21: - sb.AppendLine("Device complies with FC-LS T11/1620-D revision 1.62"); - - break; - case 0x0E29: - sb.AppendLine("Device complies with FC-LS ANSI INCITS 433-2007"); - - break; - case 0x0E40: - sb.AppendLine("Device complies with FC-SP (no version claimed)"); - - break; - case 0x0E42: - sb.AppendLine("Device complies with FC-SP T11/1570-D revision 1.6"); - - break; - case 0x0E45: - sb.AppendLine("Device complies with FC-SP ANSI INCITS 426-2007"); - - break; - case 0x0E60: - sb.AppendLine("Device complies with FC-PI-3 (no version claimed)"); - - break; - case 0x0E62: - sb.AppendLine("Device complies with FC-PI-3 T11/1625-D revision 2.0"); - - break; - case 0x0E68: - sb.AppendLine("Device complies with FC-PI-3 T11/1625-D revision 2.1"); - - break; - case 0x0E6A: - sb.AppendLine("Device complies with FC-PI-3 T11/1625-D revision 4.0"); - - break; - case 0x0E6E: - sb.AppendLine("Device complies with FC-PI-3 ANSI INCITS 460-2011"); - - break; - case 0x0E80: - sb.AppendLine("Device complies with FC-PI-4 (no version claimed)"); - - break; - case 0x0E82: - sb.AppendLine("Device complies with FC-PI-4 T11/1647-D revision 8.0"); - - break; - case 0x0E88: - sb.AppendLine("Device complies with FC-PI-4 ANSI INCITS 450-2009"); - - break; - case 0x0EA0: - sb.AppendLine("Device complies with FC 10GFC (no version claimed)"); - - break; - case 0x0EA2: - sb.AppendLine("Device complies with FC 10GFC ANSI INCITS 364-2003"); - - break; - case 0x0EA3: - sb.AppendLine("Device complies with FC 10GFC ISO/IEC 14165-116"); - - break; - case 0x0EA5: - sb.AppendLine("Device complies with FC 10GFC ISO/IEC 14165-116 with AM1"); - - break; - case 0x0EA6: - sb.AppendLine("Device complies with FC 10GFC ANSI INCITS 364-2003 with AM1 ANSI INCITS 364/AM1-2007"); - - break; - case 0x0EC0: - sb.AppendLine("Device complies with FC-SP-2 (no version claimed)"); - - break; - case 0x0EE0: - sb.AppendLine("Device complies with FC-FS-3 (no version claimed)"); - - break; - case 0x0EE2: - sb.AppendLine("Device complies with FC-FS-3 T11/1861-D revision 0.9"); - - break; - case 0x0EE7: - sb.AppendLine("Device complies with FC-FS-3 T11/1861-D revision 1.0"); - - break; - case 0x0EE9: - sb.AppendLine("Device complies with FC-FS-3 T11/1861-D revision 1.10"); - - break; - case 0x0EEB: - sb.AppendLine("Device complies with FC-FS-3 ANSI INCITS 470-2011"); - - break; - case 0x0F00: - sb.AppendLine("Device complies with FC-LS-2 (no version claimed)"); - - break; - case 0x0F03: - sb.AppendLine("Device complies with FC-LS-2 T11/2103-D revision 2.11"); - - break; - case 0x0F05: - sb.AppendLine("Device complies with FC-LS-2 T11/2103-D revision 2.21"); - - break; - case 0x0F07: - sb.AppendLine("Device complies with FC-LS-2 ANSI INCITS 477-2011"); - - break; - case 0x0F20: - sb.AppendLine("Device complies with FC-PI-5 (no version claimed)"); - - break; - case 0x0F27: - sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 2.00"); - - break; - case 0x0F28: - sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 3.00"); - - break; - case 0x0F2A: - sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 6.00"); - - break; - case 0x0F2B: - sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 6.10"); - - break; - case 0x0F2E: - sb.AppendLine("Device complies with FC-PI-5 ANSI INCITS 479-2011"); - - break; - case 0x0F40: - sb.AppendLine("Device complies with FC-PI-6 (no version claimed)"); - - break; - case 0x0F60: - sb.AppendLine("Device complies with FC-FS-4 (no version claimed)"); - - break; - case 0x0F80: - sb.AppendLine("Device complies with FC-LS-3 (no version claimed)"); - - break; - case 0x12A0: - sb.AppendLine("Device complies with FC-SCM (no version claimed)"); - - break; - case 0x12A3: - sb.AppendLine("Device complies with FC-SCM T11/1824DT revision 1.0"); - - break; - case 0x12A5: - sb.AppendLine("Device complies with FC-SCM T11/1824DT revision 1.1"); - - break; - case 0x12A7: - sb.AppendLine("Device complies with FC-SCM T11/1824DT revision 1.4"); - - break; - case 0x12AA: - sb.AppendLine("Device complies with FC-SCM INCITS TR-47 2012"); - - break; - case 0x12C0: - sb.AppendLine("Device complies with FC-DA-2 (no version claimed)"); - - break; - case 0x12C3: - sb.AppendLine("Device complies with FC-DA-2 T11/1870DT revision 1.04"); - - break; - case 0x12C5: - sb.AppendLine("Device complies with FC-DA-2 T11/1870DT revision 1.06"); - - break; - case 0x12C9: - sb.AppendLine("Device complies with FC-DA-2 INCITS TR-49 2012"); - - break; - case 0x12E0: - sb.AppendLine("Device complies with FC-DA (no version claimed)"); - - break; - case 0x12E2: - sb.AppendLine("Device complies with FC-DA T11/1513-DT revision 3.1"); - - break; - case 0x12E8: - sb.AppendLine("Device complies with FC-DA ANSI INCITS TR-36 2004"); - - break; - case 0x12E9: - sb.AppendLine("Device complies with FC-DA ISO/IEC 14165-341"); - - break; - case 0x1300: - sb.AppendLine("Device complies with FC-Tape (no version claimed)"); - - break; - case 0x1301: - sb.AppendLine("Device complies with FC-Tape T11/1315 revision 1.16"); - - break; - case 0x131B: - sb.AppendLine("Device complies with FC-Tape T11/1315 revision 1.17"); - - break; - case 0x131C: - sb.AppendLine("Device complies with FC-Tape ANSI INCITS TR-24 1999"); - - break; - case 0x1320: - sb.AppendLine("Device complies with FC-FLA (no version claimed)"); - - break; - case 0x133B: - sb.AppendLine("Device complies with FC-FLA T11/1235 revision 7"); - - break; - case 0x133C: - sb.AppendLine("Device complies with FC-FLA ANSI INCITS TR-20 1998"); - - break; - case 0x1340: - sb.AppendLine("Device complies with FC-PLDA (no version claimed)"); - - break; - case 0x135B: - sb.AppendLine("Device complies with FC-PLDA T11/1162 revision 2.1"); - - break; - case 0x135C: - sb.AppendLine("Device complies with FC-PLDA ANSI INCITS TR-19 1998"); - - break; - case 0x1360: - sb.AppendLine("Device complies with SSA-PH2 (no version claimed)"); - - break; - case 0x137B: - sb.AppendLine("Device complies with SSA-PH2 T10.1/1145-D revision 09c"); - - break; - case 0x137C: - sb.AppendLine("Device complies with SSA-PH2 ANSI INCITS 293-1996"); - - break; - case 0x1380: - sb.AppendLine("Device complies with SSA-PH3 (no version claimed)"); - - break; - case 0x139B: - sb.AppendLine("Device complies with SSA-PH3 T10.1/1146-D revision 05b"); - - break; - case 0x139C: - sb.AppendLine("Device complies with SSA-PH3 ANSI INCITS 307-1998"); - - break; - case 0x14A0: - sb.AppendLine("Device complies with IEEE 1394 (no version claimed)"); - - break; - case 0x14BD: - sb.AppendLine("Device complies with ANSI IEEE 1394-1995"); - - break; - case 0x14C0: - sb.AppendLine("Device complies with IEEE 1394a (no version claimed)"); - - break; - case 0x14E0: - sb.AppendLine("Device complies with IEEE 1394b (no version claimed)"); - - break; - case 0x15E0: - sb.AppendLine("Device complies with ATA/ATAPI-6 (no version claimed)"); - - break; - case 0x15FD: - sb.AppendLine("Device complies with ATA/ATAPI-6 ANSI INCITS 361-2002"); - - break; - case 0x1600: - sb.AppendLine("Device complies with ATA/ATAPI-7 (no version claimed)"); - - break; - case 0x1602: - sb.AppendLine("Device complies with ATA/ATAPI-7 T13/1532-D revision 3"); - - break; - case 0x161C: - sb.AppendLine("Device complies with ATA/ATAPI-7 ANSI INCITS 397-2005"); - - break; - case 0x161E: - sb.AppendLine("Device complies with ATA/ATAPI-7 ISO/IEC 24739"); - - break; - case 0x1620: - sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-AAM (no version claimed)"); - - break; - case 0x1621: - sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-APT Parallel Transport (no version claimed)"); - - break; - case 0x1622: - sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-AST Serial Transport (no version claimed)"); - - break; - case 0x1623: - sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-ACS ATA/ATAPI Command Set (no version claimed)"); - - break; - case 0x1628: - sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-AAM ANSI INCITS 451-2008"); - - break; - case 0x162A: - sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-ACS ANSI INCITS 452-2009 w/ Amendment 1"); - - break; - case 0x1728: - sb.AppendLine("Device complies with Universal Serial Bus Specification, Revision 1.1"); - - break; - case 0x1729: - sb.AppendLine("Device complies with Universal Serial Bus Specification, Revision 2.0"); - - break; - case 0x1730: - sb.AppendLine("Device complies with USB Mass Storage Class Bulk-Only Transport, Revision 1.0"); - - break; - case 0x1740: - sb.AppendLine("Device complies with UAS (no version claimed)"); - - break; - case 0x1743: - sb.AppendLine("Device complies with UAS T10/2095-D revision 02"); - - break; - case 0x1747: - sb.AppendLine("Device complies with UAS T10/2095-D revision 04"); - - break; - case 0x1748: - sb.AppendLine("Device complies with UAS ANSI INCITS 471-2010"); - - break; - case 0x1749: - sb.AppendLine("Device complies with UAS ISO/IEC 14776-251:2014"); - - break; - case 0x1761: - sb.AppendLine("Device complies with ACS-2 (no version claimed)"); - - break; - case 0x1762: - sb.AppendLine("Device complies with ACS-2 ANSI INCITS 482-2013"); - - break; - case 0x1765: - sb.AppendLine("Device complies with ACS-3 (no version claimed)"); - - break; - case 0x1780: - sb.AppendLine("Device complies with UAS-2 (no version claimed)"); - - break; - case 0x1EA0: - sb.AppendLine("Device complies with SAT (no version claimed)"); - - break; - case 0x1EA7: - sb.AppendLine("Device complies with SAT T10/1711-D revision 8"); - - break; - case 0x1EAB: - sb.AppendLine("Device complies with SAT T10/1711-D revision 9"); - - break; - case 0x1EAD: - sb.AppendLine("Device complies with SAT ANSI INCITS 431-2007"); - - break; - case 0x1EC0: - sb.AppendLine("Device complies with SAT-2 (no version claimed)"); - - break; - case 0x1EC4: - sb.AppendLine("Device complies with SAT-2 T10/1826-D revision 06"); - - break; - case 0x1EC8: - sb.AppendLine("Device complies with SAT-2 T10/1826-D revision 09"); - - break; - case 0x1ECA: - sb.AppendLine("Device complies with SAT-2 ANSI INCITS 465-2010"); - - break; - case 0x1EE0: - sb.AppendLine("Device complies with SAT-3 (no version claimed)"); - - break; - case 0x1EE2: - sb.AppendLine("Device complies with SAT-3 T10/BSR INCITS 517 revision 4"); - - break; - case 0x1EE4: - sb.AppendLine("Device complies with SAT-3 T10/BSR INCITS 517 revision 7"); - - break; - case 0x1EE8: - sb.AppendLine("Device complies with SAT-3 ANSI INCITS 517-2015"); - - break; - case 0x1F00: - sb.AppendLine("Device complies with SAT-4 (no version claimed)"); - - break; - case 0x20A0: - sb.AppendLine("Device complies with SPL (no version claimed)"); - - break; - case 0x20A3: - sb.AppendLine("Device complies with SPL T10/2124-D revision 6a"); - - break; - case 0x20A5: - sb.AppendLine("Device complies with SPL T10/2124-D revision 7"); - - break; - case 0x20A7: - sb.AppendLine("Device complies with SPL ANSI INCITS 476-2011"); - - break; - case 0x20A8: - sb.AppendLine("Device complies with SPL ANSI INCITS 476-2011 + SPL AM1 INCITS 476/AM1 2012"); - - break; - case 0x20AA: - sb.AppendLine("Device complies with SPL ISO/IEC 14776-261:2012"); - - break; - case 0x20C0: - sb.AppendLine("Device complies with SPL-2 (no version claimed)"); - - break; - case 0x20C2: - sb.AppendLine("Device complies with SPL-2 T10/BSR INCITS 505 revision 4"); - - break; - case 0x20C4: - sb.AppendLine("Device complies with SPL-2 T10/BSR INCITS 505 revision 5"); - - break; - case 0x20C8: - sb.AppendLine("Device complies with SPL-2 ANSI INCITS 505-2013"); - - break; - case 0x20E0: - sb.AppendLine("Device complies with SPL-3 (no version claimed)"); - - break; - case 0x20E4: - sb.AppendLine("Device complies with SPL-3 T10/BSR INCITS 492 revision 6"); - - break; - case 0x20E6: - sb.AppendLine("Device complies with SPL-3 T10/BSR INCITS 492 revision 7"); - - break; - case 0x20E8: - sb.AppendLine("Device complies with SPL-3 ANSI INCITS 492-2015"); - - break; - case 0x2100: - sb.AppendLine("Device complies with SPL-4 (no version claimed)"); - - break; - case 0x21E0: - sb.AppendLine("Device complies with SOP (no version claimed)"); - - break; - case 0x21E4: - sb.AppendLine("Device complies with SOP T10/BSR INCITS 489 revision 4"); - - break; - case 0x21E6: - sb.AppendLine("Device complies with SOP T10/BSR INCITS 489 revision 5"); - - break; - case 0x21E8: - sb.AppendLine("Device complies with SOP ANSI INCITS 489-2014"); - - break; - case 0x2200: - sb.AppendLine("Device complies with PQI (no version claimed)"); - - break; - case 0x2204: - sb.AppendLine("Device complies with PQI T10/BSR INCITS 490 revision 6"); - - break; - case 0x2206: - sb.AppendLine("Device complies with PQI T10/BSR INCITS 490 revision 7"); - - break; - case 0x2208: - sb.AppendLine("Device complies with PQI ANSI INCITS 490-2014"); - - break; - case 0x2220: - sb.AppendLine("Device complies with SOP-2 (no version claimed)"); - - break; - case 0x2240: - sb.AppendLine("Device complies with PQI-2 (no version claimed)"); - - break; - case 0xFFC0: - sb.AppendLine("Device complies with IEEE 1667 (no version claimed)"); - - break; - case 0xFFC1: - sb.AppendLine("Device complies with IEEE 1667-2006"); - - break; - case 0xFFC2: - sb.AppendLine("Device complies with IEEE 1667-2009"); - - break; - default: - sb.AppendFormat("Device complies with unknown standard code 0x{0:X4}", VersionDescriptor). - AppendLine(); - - break; - } - - #region Quantum vendor prettifying - if(response.QuantumPresent && - StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "quantum") - { - sb.AppendLine("Quantum vendor-specific information:"); - - switch(response.Qt_ProductFamily) + if(response.VersionDescriptors != null) + foreach(ushort VersionDescriptor in response.VersionDescriptors) + switch(VersionDescriptor) { - case 0: - sb.AppendLine("Product family is not specified"); + case 0xFFFF: + case 0x0000: break; + case 0x0020: + sb.AppendLine("Device complies with SAM (no version claimed)"); break; - case 1: - sb.AppendLine("Product family is 2.6 GB"); + case 0x003B: + sb.AppendLine("Device complies with SAM T10/0994-D revision 18"); break; - case 2: - sb.AppendLine("Product family is 6.0 GB"); + case 0x003C: + sb.AppendLine("Device complies with SAM ANSI INCITS 270-1996"); break; - case 3: - sb.AppendLine("Product family is 10.0/20.0 GB"); + case 0x0040: + sb.AppendLine("Device complies with SAM-2 (no version claimed)"); break; - case 5: - sb.AppendLine("Product family is 20.0/40.0 GB"); + case 0x0054: + sb.AppendLine("Device complies with SAM-2 T10/1157-D revision 23"); break; - case 6: - sb.AppendLine("Product family is 15.0/30.0 GB"); + case 0x0055: + sb.AppendLine("Device complies with SAM-2 T10/1157-D revision 24"); + + break; + case 0x005C: + sb.AppendLine("Device complies with SAM-2 ANSI INCITS 366-2003"); + + break; + case 0x005E: + sb.AppendLine("Device complies with SAM-2 ISO/IEC 14776-412"); + + break; + case 0x0060: + sb.AppendLine("Device complies with SAM-3 (no version claimed)"); + + break; + case 0x0062: + sb.AppendLine("Device complies with SAM-3 T10/1561-D revision 7"); + + break; + case 0x0075: + sb.AppendLine("Device complies with SAM-3 T10/1561-D revision 13"); + + break; + case 0x0076: + sb.AppendLine("Device complies with SAM-3 T10/1561-D revision 14"); + + break; + case 0x0077: + sb.AppendLine("Device complies with SAM-3 ANSI INCITS 402-2005"); + + break; + case 0x0080: + sb.AppendLine("Device complies with SAM-4 (no version claimed)"); + + break; + case 0x0087: + sb.AppendLine("Device complies with SAM-4 T10/1683-D revision 13"); + + break; + case 0x008B: + sb.AppendLine("Device complies with SAM-4 T10/1683-D revision 14"); + + break; + case 0x0090: + sb.AppendLine("Device complies with SAM-4 ANSI INCITS 447-2008"); + + break; + case 0x0092: + sb.AppendLine("Device complies with SAM-4 ISO/IEC 14776-414"); + + break; + case 0x00A0: + sb.AppendLine("Device complies with SAM-5 (no version claimed)"); + + break; + case 0x00A2: + sb.AppendLine("Device complies with SAM-5 T10/2104-D revision 4"); + + break; + case 0x00A4: + sb.AppendLine("Device complies with SAM-5 T10/2104-D revision 20"); + + break; + case 0x00A6: + sb.AppendLine("Device complies with SAM-5 T10/2104-D revision 21"); + + break; + case 0x00C0: + sb.AppendLine("Device complies with SAM-6 (no version claimed)"); + + break; + case 0x0120: + sb.AppendLine("Device complies with SPC (no version claimed)"); + + break; + case 0x013B: + sb.AppendLine("Device complies with SPC T10/0995-D revision 11a"); + + break; + case 0x013C: + sb.AppendLine("Device complies with SPC ANSI INCITS 301-1997"); + + break; + case 0x0140: + sb.AppendLine("Device complies with MMC (no version claimed)"); + + break; + case 0x015B: + sb.AppendLine("Device complies with MMC T10/1048-D revision 10a"); + + break; + case 0x015C: + sb.AppendLine("Device complies with MMC ANSI INCITS 304-1997"); + + break; + case 0x0160: + sb.AppendLine("Device complies with SCC (no version claimed)"); + + break; + case 0x017B: + sb.AppendLine("Device complies with SCC T10/1047-D revision 06c"); + + break; + case 0x017C: + sb.AppendLine("Device complies with SCC ANSI INCITS 276-1997"); + + break; + case 0x0180: + sb.AppendLine("Device complies with SBC (no version claimed)"); + + break; + case 0x019B: + sb.AppendLine("Device complies with SBC T10/0996-D revision 08c"); + + break; + case 0x019C: + sb.AppendLine("Device complies with SBC ANSI INCITS 306-1998"); + + break; + case 0x01A0: + sb.AppendLine("Device complies with SMC (no version claimed)"); + + break; + case 0x01BB: + sb.AppendLine("Device complies with SMC T10/0999-D revision 10a"); + + break; + case 0x01BC: + sb.AppendLine("Device complies with SMC ANSI INCITS 314-1998"); + + break; + case 0x01BE: + sb.AppendLine("Device complies with SMC ISO/IEC 14776-351"); + + break; + case 0x01C0: + sb.AppendLine("Device complies with SES (no version claimed)"); + + break; + case 0x01DB: + sb.AppendLine("Device complies with SES T10/1212-D revision 08b"); + + break; + case 0x01DC: + sb.AppendLine("Device complies with SES ANSI INCITS 305-1998"); + + break; + case 0x01DD: + sb.AppendLine("Device complies with SES T10/1212 revision 08b w/ Amendment ANSI INCITS.305/AM1-2000"); + + break; + case 0x01DE: + sb.AppendLine("Device complies with SES ANSI INCITS 305-1998 w/ Amendment ANSI INCITS.305/AM1-2000"); + + break; + case 0x01E0: + sb.AppendLine("Device complies with SCC-2 (no version claimed)"); + + break; + case 0x01FB: + sb.AppendLine("Device complies with SCC-2 T10/1125-D revision 04"); + + break; + case 0x01FC: + sb.AppendLine("Device complies with SCC-2 ANSI INCITS 318-1998"); + + break; + case 0x0200: + sb.AppendLine("Device complies with SSC (no version claimed)"); + + break; + case 0x0201: + sb.AppendLine("Device complies with SSC T10/0997-D revision 17"); + + break; + case 0x0207: + sb.AppendLine("Device complies with SSC T10/0997-D revision 22"); + + break; + case 0x021C: + sb.AppendLine("Device complies with SSC ANSI INCITS 335-2000"); + + break; + case 0x0220: + sb.AppendLine("Device complies with RBC (no version claimed)"); + + break; + case 0x0238: + sb.AppendLine("Device complies with RBC T10/1240-D revision 10a"); + + break; + case 0x023C: + sb.AppendLine("Device complies with RBC ANSI INCITS 330-2000"); + + break; + case 0x0240: + sb.AppendLine("Device complies with MMC-2 (no version claimed)"); + + break; + case 0x0255: + sb.AppendLine("Device complies with MMC-2 T10/1228-D revision 11"); + + break; + case 0x025B: + sb.AppendLine("Device complies with MMC-2 T10/1228-D revision 11a"); + + break; + case 0x025C: + sb.AppendLine("Device complies with MMC-2 ANSI INCITS 333-2000"); + + break; + case 0x0260: + sb.AppendLine("Device complies with SPC-2 (no version claimed)"); + + break; + case 0x0267: + sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 12"); + + break; + case 0x0269: + sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 18"); + + break; + case 0x0275: + sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 19"); + + break; + case 0x0276: + sb.AppendLine("Device complies with SPC-2 T10/1236-D revision 20"); + + break; + case 0x0277: + sb.AppendLine("Device complies with SPC-2 ANSI INCITS 351-2001"); + + break; + case 0x0278: + sb.AppendLine("Device complies with SPC-2 ISO/IEC 14776-452"); + + break; + case 0x0280: + sb.AppendLine("Device complies with OCRW (no version claimed)"); + + break; + case 0x029E: + sb.AppendLine("Device complies with OCRW ISO/IEC 14776-381"); + + break; + case 0x02A0: + sb.AppendLine("Device complies with MMC-3 (no version claimed)"); + + break; + case 0x02B5: + sb.AppendLine("Device complies with MMC-3 T10/1363-D revision 9"); + + break; + case 0x02B6: + sb.AppendLine("Device complies with MMC-3 T10/1363-D revision 10g"); + + break; + case 0x02B8: + sb.AppendLine("Device complies with MMC-3 ANSI INCITS 360-2002"); + + break; + case 0x02E0: + sb.AppendLine("Device complies with SMC-2 (no version claimed)"); + + break; + case 0x02F5: + sb.AppendLine("Device complies with SMC-2 T10/1383-D revision 5"); + + break; + case 0x02FC: + sb.AppendLine("Device complies with SMC-2 T10/1383-D revision 6"); + + break; + case 0x02FD: + sb.AppendLine("Device complies with SMC-2 T10/1383-D revision 7"); + + break; + case 0x02FE: + sb.AppendLine("Device complies with SMC-2 ANSI INCITS 382-2004"); + + break; + case 0x0300: + sb.AppendLine("Device complies with SPC-3 (no version claimed)"); + + break; + case 0x0301: + sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 7"); + + break; + case 0x0307: + sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 21"); + + break; + case 0x030F: + sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 22"); + + break; + case 0x0312: + sb.AppendLine("Device complies with SPC-3 T10/1416-D revision 23"); + + break; + case 0x0314: + sb.AppendLine("Device complies with SPC-3 ANSI INCITS 408-2005"); + + break; + case 0x0316: + sb.AppendLine("Device complies with SPC-3 ISO/IEC 14776-453"); + + break; + case 0x0320: + sb.AppendLine("Device complies with SBC-2 (no version claimed)"); + + break; + case 0x0322: + sb.AppendLine("Device complies with SBC-2 T10/1417-D revision 5a"); + + break; + case 0x0324: + sb.AppendLine("Device complies with SBC-2 T10/1417-D revision 15"); + + break; + case 0x033B: + sb.AppendLine("Device complies with SBC-2 T10/1417-D revision 16"); + + break; + case 0x033D: + sb.AppendLine("Device complies with SBC-2 ANSI INCITS 405-2005"); + + break; + case 0x033E: + sb.AppendLine("Device complies with SBC-2 ISO/IEC 14776-322"); + + break; + case 0x0340: + sb.AppendLine("Device complies with OSD (no version claimed)"); + + break; + case 0x0341: + sb.AppendLine("Device complies with OSD T10/1355-D revision 0"); + + break; + case 0x0342: + sb.AppendLine("Device complies with OSD T10/1355-D revision 7a"); + + break; + case 0x0343: + sb.AppendLine("Device complies with OSD T10/1355-D revision 8"); + + break; + case 0x0344: + sb.AppendLine("Device complies with OSD T10/1355-D revision 9"); + + break; + case 0x0355: + sb.AppendLine("Device complies with OSD T10/1355-D revision 10"); + + break; + case 0x0356: + sb.AppendLine("Device complies with OSD ANSI INCITS 400-2004"); + + break; + case 0x0360: + sb.AppendLine("Device complies with SSC-2 (no version claimed)"); + + break; + case 0x0374: + sb.AppendLine("Device complies with SSC-2 T10/1434-D revision 7"); + + break; + case 0x0375: + sb.AppendLine("Device complies with SSC-2 T10/1434-D revision 9"); + + break; + case 0x037D: + sb.AppendLine("Device complies with SSC-2 ANSI INCITS 380-2003"); + + break; + case 0x0380: + sb.AppendLine("Device complies with BCC (no version claimed)"); + + break; + case 0x03A0: + sb.AppendLine("Device complies with MMC-4 (no version claimed)"); + + break; + case 0x03B0: + sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 5"); + + break; + case 0x03B1: + sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 5a"); + + break; + case 0x03BD: + sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 3"); + + break; + case 0x03BE: + sb.AppendLine("Device complies with MMC-4 T10/1545-D revision 3d"); + + break; + case 0x03BF: + sb.AppendLine("Device complies with MMC-4 ANSI INCITS 401-2005"); + + break; + case 0x03C0: + sb.AppendLine("Device complies with ADC (no version claimed)"); + + break; + case 0x03D5: + sb.AppendLine("Device complies with ADC T10/1558-D revision 6"); + + break; + case 0x03D6: + sb.AppendLine("Device complies with ADC T10/1558-D revision 7"); + + break; + case 0x03D7: + sb.AppendLine("Device complies with ADC ANSI INCITS 403-2005"); + + break; + case 0x03E0: + sb.AppendLine("Device complies with SES-2 (no version claimed)"); + + break; + case 0x03E1: + sb.AppendLine("Device complies with SES-2 T10/1559-D revision 16"); + + break; + case 0x03E7: + sb.AppendLine("Device complies with SES-2 T10/1559-D revision 19"); + + break; + case 0x03EB: + sb.AppendLine("Device complies with SES-2 T10/1559-D revision 20"); + + break; + case 0x03F0: + sb.AppendLine("Device complies with SES-2 ANSI INCITS 448-2008"); + + break; + case 0x03F2: + sb.AppendLine("Device complies with SES-2 ISO/IEC 14776-372"); + + break; + case 0x0400: + sb.AppendLine("Device complies with SSC-3 (no version claimed)"); + + break; + case 0x0403: + sb.AppendLine("Device complies with SSC-3 T10/1611-D revision 04a"); + + break; + case 0x0407: + sb.AppendLine("Device complies with SSC-3 T10/1611-D revision 05"); + + break; + case 0x0409: + sb.AppendLine("Device complies with SSC-3 ANSI INCITS 467-2011"); + + break; + case 0x040B: + sb.AppendLine("Device complies with SSC-3 ISO/IEC 14776-333:2013"); + + break; + case 0x0420: + sb.AppendLine("Device complies with MMC-5 (no version claimed)"); + + break; + case 0x042F: + sb.AppendLine("Device complies with MMC-5 T10/1675-D revision 03"); + + break; + case 0x0431: + sb.AppendLine("Device complies with MMC-5 T10/1675-D revision 03b"); + + break; + case 0x0432: + sb.AppendLine("Device complies with MMC-5 T10/1675-D revision 04"); + + break; + case 0x0434: + sb.AppendLine("Device complies with MMC-5 ANSI INCITS 430-2007"); + + break; + case 0x0440: + sb.AppendLine("Device complies with OSD-2 (no version claimed)"); + + break; + case 0x0444: + sb.AppendLine("Device complies with OSD-2 T10/1729-D revision 4"); + + break; + case 0x0446: + sb.AppendLine("Device complies with OSD-2 T10/1729-D revision 5"); + + break; + case 0x0448: + sb.AppendLine("Device complies with OSD-2 ANSI INCITS 458-2011"); + + break; + case 0x0460: + sb.AppendLine("Device complies with SPC-4 (no version claimed)"); + + break; + case 0x0461: + sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 16"); + + break; + case 0x0462: + sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 18"); + + break; + case 0x0463: + sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 23"); + + break; + case 0x0466: + sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 36"); + + break; + case 0x0468: + sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 37"); + + break; + case 0x0469: + sb.AppendLine("Device complies with SPC-4 T10/BSR INCITS 513 revision 37a"); + + break; + case 0x046C: + sb.AppendLine("Device complies with SPC-4 ANSI INCITS 513-2015"); + + break; + case 0x0480: + sb.AppendLine("Device complies with SMC-3 (no version claimed)"); + + break; + case 0x0482: + sb.AppendLine("Device complies with SMC-3 T10/1730-D revision 15"); + + break; + case 0x0484: + sb.AppendLine("Device complies with SMC-3 T10/1730-D revision 16"); + + break; + case 0x0486: + sb.AppendLine("Device complies with SMC-3 ANSI INCITS 484-2012"); + + break; + case 0x04A0: + sb.AppendLine("Device complies with ADC-2 (no version claimed)"); + + break; + case 0x04A7: + sb.AppendLine("Device complies with ADC-2 T10/1741-D revision 7"); + + break; + case 0x04AA: + sb.AppendLine("Device complies with ADC-2 T10/1741-D revision 8"); + + break; + case 0x04AC: + sb.AppendLine("Device complies with ADC-2 ANSI INCITS 441-2008"); + + break; + case 0x04C0: + sb.AppendLine("Device complies with SBC-3 (no version claimed)"); + + break; + case 0x04C3: + sb.AppendLine("Device complies with SBC-3 T10/BSR INCITS 514 revision 35"); + + break; + case 0x04C5: + sb.AppendLine("Device complies with SBC-3 T10/BSR INCITS 514 revision 36"); + + break; + case 0x04C8: + sb.AppendLine("Device complies with SBC-3 ANSI INCITS 514-2014"); + + break; + case 0x04E0: + sb.AppendLine("Device complies with MMC-6 (no version claimed)"); + + break; + case 0x04E3: + sb.AppendLine("Device complies with MMC-6 T10/1836-D revision 02b"); + + break; + case 0x04E5: + sb.AppendLine("Device complies with MMC-6 T10/1836-D revision 02g"); + + break; + case 0x04E6: + sb.AppendLine("Device complies with MMC-6 ANSI INCITS 468-2010"); + + break; + case 0x04E7: + sb.AppendLine("Device complies with MMC-6 ANSI INCITS 468-2010 + MMC-6/AM1 ANSI INCITS 468-2010/AM 1"); + + break; + case 0x0500: + sb.AppendLine("Device complies with ADC-3 (no version claimed)"); + + break; + case 0x0502: + sb.AppendLine("Device complies with ADC-3 T10/1895-D revision 04"); + + break; + case 0x0504: + sb.AppendLine("Device complies with ADC-3 T10/1895-D revision 05"); + + break; + case 0x0506: + sb.AppendLine("Device complies with ADC-3 T10/1895-D revision 05a"); + + break; + case 0x050A: + sb.AppendLine("Device complies with ADC-3 ANSI INCITS 497-2012"); + + break; + case 0x0520: + sb.AppendLine("Device complies with SSC-4 (no version claimed)"); + + break; + case 0x0523: + sb.AppendLine("Device complies with SSC-4 T10/BSR INCITS 516 revision 2"); + + break; + case 0x0525: + sb.AppendLine("Device complies with SSC-4 T10/BSR INCITS 516 revision 3"); + + break; + case 0x0527: + sb.AppendLine("Device complies with SSC-4 ANSI INCITS 516-2013"); + + break; + case 0x0560: + sb.AppendLine("Device complies with OSD-3 (no version claimed)"); + + break; + case 0x0580: + sb.AppendLine("Device complies with SES-3 (no version claimed)"); + + break; + case 0x05A0: + sb.AppendLine("Device complies with SSC-5 (no version claimed)"); + + break; + case 0x05C0: + sb.AppendLine("Device complies with SPC-5 (no version claimed)"); + + break; + case 0x05E0: + sb.AppendLine("Device complies with SFSC (no version claimed)"); + + break; + case 0x05E3: + sb.AppendLine("Device complies with SFSC BSR INCITS 501 revision 01"); + + break; + case 0x0600: + sb.AppendLine("Device complies with SBC-4 (no version claimed)"); + + break; + case 0x0620: + sb.AppendLine("Device complies with ZBC (no version claimed)"); + + break; + case 0x0622: + sb.AppendLine("Device complies with ZBC BSR INCITS 536 revision 02"); + + break; + case 0x0640: + sb.AppendLine("Device complies with ADC-4 (no version claimed)"); + + break; + case 0x0820: + sb.AppendLine("Device complies with SSA-TL2 (no version claimed)"); + + break; + case 0x083B: + sb.AppendLine("Device complies with SSA-TL2 T10.1/1147-D revision 05b"); + + break; + case 0x083C: + sb.AppendLine("Device complies with SSA-TL2 ANSI INCITS 308-1998"); + + break; + case 0x0840: + sb.AppendLine("Device complies with SSA-TL1 (no version claimed)"); + + break; + case 0x085B: + sb.AppendLine("Device complies with SSA-TL1 T10.1/0989-D revision 10b"); + + break; + case 0x085C: + sb.AppendLine("Device complies with SSA-TL1 ANSI INCITS 295-1996"); + + break; + case 0x0860: + sb.AppendLine("Device complies with SSA-S3P (no version claimed)"); + + break; + case 0x087B: + sb.AppendLine("Device complies with SSA-S3P T10.1/1051-D revision 05b"); + + break; + case 0x087C: + sb.AppendLine("Device complies with SSA-S3P ANSI INCITS 309-1998"); + + break; + case 0x0880: + sb.AppendLine("Device complies with SSA-S2P (no version claimed)"); + + break; + case 0x089B: + sb.AppendLine("Device complies with SSA-S2P T10.1/1121-D revision 07b"); + + break; + case 0x089C: + sb.AppendLine("Device complies with SSA-S2P ANSI INCITS 294-1996"); + + break; + case 0x08A0: + sb.AppendLine("Device complies with SIP (no version claimed)"); + + break; + case 0x08BB: + sb.AppendLine("Device complies with SIP T10/0856-D revision 10"); + + break; + case 0x08BC: + sb.AppendLine("Device complies with SIP ANSI INCITS 292-1997"); + + break; + case 0x08C0: + sb.AppendLine("Device complies with FCP (no version claimed)"); + + break; + case 0x08DB: + sb.AppendLine("Device complies with FCP T10/0993-D revision 12"); + + break; + case 0x08DC: + sb.AppendLine("Device complies with FCP ANSI INCITS 269-1996"); + + break; + case 0x08E0: + sb.AppendLine("Device complies with SBP-2 (no version claimed)"); + + break; + case 0x08FB: + sb.AppendLine("Device complies with SBP-2 T10/1155-D revision 04"); + + break; + case 0x08FC: + sb.AppendLine("Device complies with SBP-2 ANSI INCITS 325-1998"); + + break; + case 0x0900: + sb.AppendLine("Device complies with FCP-2 (no version claimed)"); + + break; + case 0x0901: + sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 4"); + + break; + case 0x0915: + sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 7"); + + break; + case 0x0916: + sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 7a"); + + break; + case 0x0917: + sb.AppendLine("Device complies with FCP-2 ANSI INCITS 350-2003"); + + break; + case 0x0918: + sb.AppendLine("Device complies with FCP-2 T10/1144-D revision 8"); + + break; + case 0x0920: + sb.AppendLine("Device complies with SST (no version claimed)"); + + break; + case 0x0935: + sb.AppendLine("Device complies with SST T10/1380-D revision 8b"); + + break; + case 0x0940: + sb.AppendLine("Device complies with SRP (no version claimed)"); + + break; + case 0x0954: + sb.AppendLine("Device complies with SRP T10/1415-D revision 10"); + + break; + case 0x0955: + sb.AppendLine("Device complies with SRP T10/1415-D revision 16a"); + + break; + case 0x095C: + sb.AppendLine("Device complies with SRP ANSI INCITS 365-2002"); + + break; + case 0x0960: + sb.AppendLine("Device complies with iSCSI (no version claimed)"); + + break; + case 0x0961: + case 0x0962: + case 0x0963: + case 0x0964: + case 0x0965: + case 0x0966: + case 0x0967: + case 0x0968: + case 0x0969: + case 0x096A: + case 0x096B: + case 0x096C: + case 0x096D: + case 0x096E: + case 0x096F: + case 0x0970: + case 0x0971: + case 0x0972: + case 0x0973: + case 0x0974: + case 0x0975: + case 0x0976: + case 0x0977: + case 0x0978: + case 0x0979: + case 0x097A: + case 0x097B: + case 0x097C: + case 0x097D: + case 0x097E: + case 0x097F: + sb.AppendFormat("Device complies with iSCSI revision {0}", VersionDescriptor & 0x1F). + AppendLine(); + + break; + case 0x0980: + sb.AppendLine("Device complies with SBP-3 (no version claimed)"); + + break; + case 0x0982: + sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 1f"); + + break; + case 0x0994: + sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 3"); + + break; + case 0x099A: + sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 4"); + + break; + case 0x099B: + sb.AppendLine("Device complies with SBP-3 T10/1467-D revision 5"); + + break; + case 0x099C: + sb.AppendLine("Device complies with SBP-3 ANSI INCITS 375-2004"); + + break; + case 0x09C0: + sb.AppendLine("Device complies with ADP (no version claimed)"); + + break; + case 0x09E0: + sb.AppendLine("Device complies with ADT (no version claimed)"); + + break; + case 0x09F9: + sb.AppendLine("Device complies with ADT T10/1557-D revision 11"); + + break; + case 0x09FA: + sb.AppendLine("Device complies with ADT T10/1557-D revision 14"); + + break; + case 0x09FD: + sb.AppendLine("Device complies with ADT ANSI INCITS 406-2005"); + + break; + case 0x0A00: + sb.AppendLine("Device complies with FCP-3 (no version claimed)"); + + break; + case 0x0A07: + sb.AppendLine("Device complies with FCP-3 T10/1560-D revision 3f"); + + break; + case 0x0A0F: + sb.AppendLine("Device complies with FCP-3 T10/1560-D revision 4"); + + break; + case 0x0A11: + sb.AppendLine("Device complies with FCP-3 ANSI INCITS 416-2006"); + + break; + case 0x0A1C: + sb.AppendLine("Device complies with FCP-3 ISO/IEC 14776-223"); + + break; + case 0x0A20: + sb.AppendLine("Device complies with ADT-2 (no version claimed)"); + + break; + case 0x0A22: + sb.AppendLine("Device complies with ADT-2 T10/1742-D revision 06"); + + break; + case 0x0A27: + sb.AppendLine("Device complies with ADT-2 T10/1742-D revision 08"); + + break; + case 0x0A28: + sb.AppendLine("Device complies with ADT-2 T10/1742-D revision 09"); + + break; + case 0x0A2B: + sb.AppendLine("Device complies with ADT-2 ANSI INCITS 472-2011"); + + break; + case 0x0A40: + sb.AppendLine("Device complies with FCP-4 (no version claimed)"); + + break; + case 0x0A42: + sb.AppendLine("Device complies with FCP-4 T10/1828-D revision 01"); + + break; + case 0x0A44: + sb.AppendLine("Device complies with FCP-4 T10/1828-D revision 02"); + + break; + case 0x0A45: + sb.AppendLine("Device complies with FCP-4 T10/1828-D revision 02b"); + + break; + case 0x0A46: + sb.AppendLine("Device complies with FCP-4 ANSI INCITS 481-2012"); + + break; + case 0x0A60: + sb.AppendLine("Device complies with ADT-3 (no version claimed)"); + + break; + case 0x0AA0: + sb.AppendLine("Device complies with SPI (no version claimed)"); + + break; + case 0x0AB9: + sb.AppendLine("Device complies with SPI T10/0855-D revision 15a"); + + break; + case 0x0ABA: + sb.AppendLine("Device complies with SPI ANSI INCITS 253-1995"); + + break; + case 0x0ABB: + sb.AppendLine("Device complies with SPI T10/0855-D revision 15a with SPI Amnd revision 3a"); + + break; + case 0x0ABC: + sb.AppendLine("Device complies with SPI ANSI INCITS 253-1995 with SPI Amnd ANSI INCITS 253/AM1-1998"); + + break; + case 0x0AC0: + sb.AppendLine("Device complies with Fast-20 (no version claimed)"); + + break; + case 0x0ADB: + sb.AppendLine("Device complies with Fast-20 T10/1071 revision 06"); + + break; + case 0x0ADC: + sb.AppendLine("Device complies with Fast-20 ANSI INCITS 277-1996"); + + break; + case 0x0AE0: + sb.AppendLine("Device complies with SPI-2 (no version claimed)"); + + break; + case 0x0AFB: + sb.AppendLine("Device complies with SPI-2 T10/1142-D revision 20b"); + + break; + case 0x0AFC: + sb.AppendLine("Device complies with SPI-2 ANSI INCITS 302-1999"); + + break; + case 0x0B00: + sb.AppendLine("Device complies with SPI-3 (no version claimed)"); + + break; + case 0x0B18: + sb.AppendLine("Device complies with SPI-3 T10/1302-D revision 10"); + + break; + case 0x0B19: + sb.AppendLine("Device complies with SPI-3 T10/1302-D revision 13a"); + + break; + case 0x0B1A: + sb.AppendLine("Device complies with SPI-3 T10/1302-D revision 14"); + + break; + case 0x0B1C: + sb.AppendLine("Device complies with SPI-3 ANSI INCITS 336-2000"); + + break; + case 0x0B20: + sb.AppendLine("Device complies with EPI (no version claimed)"); + + break; + case 0x0B3B: + sb.AppendLine("Device complies with EPI T10/1134 revision 16"); + + break; + case 0x0B3C: + sb.AppendLine("Device complies with EPI ANSI INCITS TR-23 1999"); + + break; + case 0x0B40: + sb.AppendLine("Device complies with SPI-4 (no version claimed)"); + + break; + case 0x0B54: + sb.AppendLine("Device complies with SPI-4 T10/1365-D revision 7"); + + break; + case 0x0B55: + sb.AppendLine("Device complies with SPI-4 T10/1365-D revision 9"); + + break; + case 0x0B56: + sb.AppendLine("Device complies with SPI-4 ANSI INCITS 362-2002"); + + break; + case 0x0B59: + sb.AppendLine("Device complies with SPI-4 T10/1365-D revision 10"); + + break; + case 0x0B60: + sb.AppendLine("Device complies with SPI-5 (no version claimed)"); + + break; + case 0x0B79: + sb.AppendLine("Device complies with SPI-5 T10/1525-D revision 3"); + + break; + case 0x0B7A: + sb.AppendLine("Device complies with SPI-5 T10/1525-D revision 5"); + + break; + case 0x0B7B: + sb.AppendLine("Device complies with SPI-5 T10/1525-D revision 6"); + + break; + case 0x0B7C: + sb.AppendLine("Device complies with SPI-5 ANSI INCITS 367-2003"); + + break; + case 0x0BE0: + sb.AppendLine("Device complies with SAS (no version claimed)"); + + break; + case 0x0BE1: + sb.AppendLine("Device complies with SAS T10/1562-D revision 01"); + + break; + case 0x0BF5: + sb.AppendLine("Device complies with SAS T10/1562-D revision 03"); + + break; + case 0x0BFA: + sb.AppendLine("Device complies with SAS T10/1562-D revision 04"); + + break; + case 0x0BFB: + sb.AppendLine("Device complies with SAS T10/1562-D revision 04"); + + break; + case 0x0BFC: + sb.AppendLine("Device complies with SAS T10/1562-D revision 05"); + + break; + case 0x0BFD: + sb.AppendLine("Device complies with SAS ANSI INCITS 376-2003"); + + break; + case 0x0C00: + sb.AppendLine("Device complies with SAS-1.1 (no version claimed)"); + + break; + case 0x0C07: + sb.AppendLine("Device complies with SAS-1.1 T10/1601-D revision 9"); + + break; + case 0x0C0F: + sb.AppendLine("Device complies with SAS-1.1 T10/1601-D revision 10"); + + break; + case 0x0C11: + sb.AppendLine("Device complies with SAS-1.1 ANSI INCITS 417-2006"); + + break; + case 0x0C12: + sb.AppendLine("Device complies with SAS-1.1 ISO/IEC 14776-151"); + + break; + case 0x0C20: + sb.AppendLine("Device complies with SAS-2 (no version claimed)"); + + break; + case 0x0C23: + sb.AppendLine("Device complies with SAS-2 T10/1760-D revision 14"); + + break; + case 0x0C27: + sb.AppendLine("Device complies with SAS-2 T10/1760-D revision 15"); + + break; + case 0x0C28: + sb.AppendLine("Device complies with SAS-2 T10/1760-D revision 16"); + + break; + case 0x0C2A: + sb.AppendLine("Device complies with SAS-2 ANSI INCITS 457-2010"); + + break; + case 0x0C40: + sb.AppendLine("Device complies with SAS-2.1 (no version claimed)"); + + break; + case 0x0C48: + sb.AppendLine("Device complies with SAS-2.1 T10/2125-D revision 04"); + + break; + case 0x0C4A: + sb.AppendLine("Device complies with SAS-2.1 T10/2125-D revision 06"); + + break; + case 0x0C4B: + sb.AppendLine("Device complies with SAS-2.1 T10/2125-D revision 07"); + + break; + case 0x0C4E: + sb.AppendLine("Device complies with SAS-2.1 ANSI INCITS 478-2011"); + + break; + case 0x0C4F: + sb.AppendLine("Device complies with SAS-2.1 ANSI INCITS 478-2011 w/ Amnd 1 ANSI INCITS 478/AM1-2014"); + + break; + case 0x0C52: + sb.AppendLine("Device complies with SAS-2.1 ISO/IEC 14776-153"); + + break; + case 0x0C60: + sb.AppendLine("Device complies with SAS-3 (no version claimed)"); + + break; + case 0x0C63: + sb.AppendLine("Device complies with SAS-3 T10/BSR INCITS 519 revision 05a"); + + break; + case 0x0C65: + sb.AppendLine("Device complies with SAS-3 T10/BSR INCITS 519 revision 06"); + + break; + case 0x0C68: + sb.AppendLine("Device complies with SAS-3 ANSI INCITS 519-2014"); + + break; + case 0x0C80: + sb.AppendLine("Device complies with SAS-4 (no version claimed)"); + + break; + case 0x0D20: + sb.AppendLine("Device complies with FC-PH (no version claimed)"); + + break; + case 0x0D3B: + sb.AppendLine("Device complies with FC-PH ANSI INCITS 230-1994"); + + break; + case 0x0D3C: + sb.AppendLine("Device complies with FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS 230/AM1-1996"); + + break; + case 0x0D40: + sb.AppendLine("Device complies with FC-AL (no version claimed)"); + + break; + case 0x0D5C: + sb.AppendLine("Device complies with FC-AL ANSI INCITS 272-1996"); + + break; + case 0x0D60: + sb.AppendLine("Device complies with FC-AL-2 (no version claimed)"); + + break; + case 0x0D61: + sb.AppendLine("Device complies with FC-AL-2 T11/1133-D revision 7.0"); + + break; + case 0x0D63: + sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999 with AM1-2003 & AM2-2006"); + + break; + case 0x0D64: + sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 2 AM2-2006"); + + break; + case 0x0D65: + sb.AppendLine("Device complies with FC-AL-2 ISO/IEC 14165-122 with AM1 & AM2"); + + break; + case 0x0D7C: + sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999"); + + break; + case 0x0D7D: + sb.AppendLine("Device complies with FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1-2003"); + + break; + case 0x0D80: + sb.AppendLine("Device complies with FC-PH-3 (no version claimed)"); + + break; + case 0x0D9C: + sb.AppendLine("Device complies with FC-PH-3 ANSI INCITS 303-1998"); + + break; + case 0x0DA0: + sb.AppendLine("Device complies with FC-FS (no version claimed)"); + + break; + case 0x0DB7: + sb.AppendLine("Device complies with FC-FS T11/1331-D revision 1.2"); + + break; + case 0x0DB8: + sb.AppendLine("Device complies with FC-FS T11/1331-D revision 1.7"); + + break; + case 0x0DBC: + sb.AppendLine("Device complies with FC-FS ANSI INCITS 373-2003"); + + break; + case 0x0DBD: + sb.AppendLine("Device complies with FC-FS ISO/IEC 14165-251"); + + break; + case 0x0DC0: + sb.AppendLine("Device complies with FC-PI (no version claimed)"); + + break; + case 0x0DDC: + sb.AppendLine("Device complies with FC-PI ANSI INCITS 352-2002"); + + break; + case 0x0DE0: + sb.AppendLine("Device complies with FC-PI-2 (no version claimed)"); + + break; + case 0x0DE2: + sb.AppendLine("Device complies with FC-PI-2 T11/1506-D revision 5.0"); + + break; + case 0x0DE4: + sb.AppendLine("Device complies with FC-PI-2 ANSI INCITS 404-2006"); + + break; + case 0x0E00: + sb.AppendLine("Device complies with FC-FS-2 (no version claimed)"); + + break; + case 0x0E02: + sb.AppendLine("Device complies with FC-FS-2 ANSI INCITS 242-2007"); + + break; + case 0x0E03: + sb.AppendLine("Device complies with FC-FS-2 ANSI INCITS 242-2007 with AM1 ANSI INCITS 242/AM1-2007"); + + break; + case 0x0E20: + sb.AppendLine("Device complies with FC-LS (no version claimed)"); + + break; + case 0x0E21: + sb.AppendLine("Device complies with FC-LS T11/1620-D revision 1.62"); + + break; + case 0x0E29: + sb.AppendLine("Device complies with FC-LS ANSI INCITS 433-2007"); + + break; + case 0x0E40: + sb.AppendLine("Device complies with FC-SP (no version claimed)"); + + break; + case 0x0E42: + sb.AppendLine("Device complies with FC-SP T11/1570-D revision 1.6"); + + break; + case 0x0E45: + sb.AppendLine("Device complies with FC-SP ANSI INCITS 426-2007"); + + break; + case 0x0E60: + sb.AppendLine("Device complies with FC-PI-3 (no version claimed)"); + + break; + case 0x0E62: + sb.AppendLine("Device complies with FC-PI-3 T11/1625-D revision 2.0"); + + break; + case 0x0E68: + sb.AppendLine("Device complies with FC-PI-3 T11/1625-D revision 2.1"); + + break; + case 0x0E6A: + sb.AppendLine("Device complies with FC-PI-3 T11/1625-D revision 4.0"); + + break; + case 0x0E6E: + sb.AppendLine("Device complies with FC-PI-3 ANSI INCITS 460-2011"); + + break; + case 0x0E80: + sb.AppendLine("Device complies with FC-PI-4 (no version claimed)"); + + break; + case 0x0E82: + sb.AppendLine("Device complies with FC-PI-4 T11/1647-D revision 8.0"); + + break; + case 0x0E88: + sb.AppendLine("Device complies with FC-PI-4 ANSI INCITS 450-2009"); + + break; + case 0x0EA0: + sb.AppendLine("Device complies with FC 10GFC (no version claimed)"); + + break; + case 0x0EA2: + sb.AppendLine("Device complies with FC 10GFC ANSI INCITS 364-2003"); + + break; + case 0x0EA3: + sb.AppendLine("Device complies with FC 10GFC ISO/IEC 14165-116"); + + break; + case 0x0EA5: + sb.AppendLine("Device complies with FC 10GFC ISO/IEC 14165-116 with AM1"); + + break; + case 0x0EA6: + sb.AppendLine("Device complies with FC 10GFC ANSI INCITS 364-2003 with AM1 ANSI INCITS 364/AM1-2007"); + + break; + case 0x0EC0: + sb.AppendLine("Device complies with FC-SP-2 (no version claimed)"); + + break; + case 0x0EE0: + sb.AppendLine("Device complies with FC-FS-3 (no version claimed)"); + + break; + case 0x0EE2: + sb.AppendLine("Device complies with FC-FS-3 T11/1861-D revision 0.9"); + + break; + case 0x0EE7: + sb.AppendLine("Device complies with FC-FS-3 T11/1861-D revision 1.0"); + + break; + case 0x0EE9: + sb.AppendLine("Device complies with FC-FS-3 T11/1861-D revision 1.10"); + + break; + case 0x0EEB: + sb.AppendLine("Device complies with FC-FS-3 ANSI INCITS 470-2011"); + + break; + case 0x0F00: + sb.AppendLine("Device complies with FC-LS-2 (no version claimed)"); + + break; + case 0x0F03: + sb.AppendLine("Device complies with FC-LS-2 T11/2103-D revision 2.11"); + + break; + case 0x0F05: + sb.AppendLine("Device complies with FC-LS-2 T11/2103-D revision 2.21"); + + break; + case 0x0F07: + sb.AppendLine("Device complies with FC-LS-2 ANSI INCITS 477-2011"); + + break; + case 0x0F20: + sb.AppendLine("Device complies with FC-PI-5 (no version claimed)"); + + break; + case 0x0F27: + sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 2.00"); + + break; + case 0x0F28: + sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 3.00"); + + break; + case 0x0F2A: + sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 6.00"); + + break; + case 0x0F2B: + sb.AppendLine("Device complies with FC-PI-5 T11/2118-D revision 6.10"); + + break; + case 0x0F2E: + sb.AppendLine("Device complies with FC-PI-5 ANSI INCITS 479-2011"); + + break; + case 0x0F40: + sb.AppendLine("Device complies with FC-PI-6 (no version claimed)"); + + break; + case 0x0F60: + sb.AppendLine("Device complies with FC-FS-4 (no version claimed)"); + + break; + case 0x0F80: + sb.AppendLine("Device complies with FC-LS-3 (no version claimed)"); + + break; + case 0x12A0: + sb.AppendLine("Device complies with FC-SCM (no version claimed)"); + + break; + case 0x12A3: + sb.AppendLine("Device complies with FC-SCM T11/1824DT revision 1.0"); + + break; + case 0x12A5: + sb.AppendLine("Device complies with FC-SCM T11/1824DT revision 1.1"); + + break; + case 0x12A7: + sb.AppendLine("Device complies with FC-SCM T11/1824DT revision 1.4"); + + break; + case 0x12AA: + sb.AppendLine("Device complies with FC-SCM INCITS TR-47 2012"); + + break; + case 0x12C0: + sb.AppendLine("Device complies with FC-DA-2 (no version claimed)"); + + break; + case 0x12C3: + sb.AppendLine("Device complies with FC-DA-2 T11/1870DT revision 1.04"); + + break; + case 0x12C5: + sb.AppendLine("Device complies with FC-DA-2 T11/1870DT revision 1.06"); + + break; + case 0x12C9: + sb.AppendLine("Device complies with FC-DA-2 INCITS TR-49 2012"); + + break; + case 0x12E0: + sb.AppendLine("Device complies with FC-DA (no version claimed)"); + + break; + case 0x12E2: + sb.AppendLine("Device complies with FC-DA T11/1513-DT revision 3.1"); + + break; + case 0x12E8: + sb.AppendLine("Device complies with FC-DA ANSI INCITS TR-36 2004"); + + break; + case 0x12E9: + sb.AppendLine("Device complies with FC-DA ISO/IEC 14165-341"); + + break; + case 0x1300: + sb.AppendLine("Device complies with FC-Tape (no version claimed)"); + + break; + case 0x1301: + sb.AppendLine("Device complies with FC-Tape T11/1315 revision 1.16"); + + break; + case 0x131B: + sb.AppendLine("Device complies with FC-Tape T11/1315 revision 1.17"); + + break; + case 0x131C: + sb.AppendLine("Device complies with FC-Tape ANSI INCITS TR-24 1999"); + + break; + case 0x1320: + sb.AppendLine("Device complies with FC-FLA (no version claimed)"); + + break; + case 0x133B: + sb.AppendLine("Device complies with FC-FLA T11/1235 revision 7"); + + break; + case 0x133C: + sb.AppendLine("Device complies with FC-FLA ANSI INCITS TR-20 1998"); + + break; + case 0x1340: + sb.AppendLine("Device complies with FC-PLDA (no version claimed)"); + + break; + case 0x135B: + sb.AppendLine("Device complies with FC-PLDA T11/1162 revision 2.1"); + + break; + case 0x135C: + sb.AppendLine("Device complies with FC-PLDA ANSI INCITS TR-19 1998"); + + break; + case 0x1360: + sb.AppendLine("Device complies with SSA-PH2 (no version claimed)"); + + break; + case 0x137B: + sb.AppendLine("Device complies with SSA-PH2 T10.1/1145-D revision 09c"); + + break; + case 0x137C: + sb.AppendLine("Device complies with SSA-PH2 ANSI INCITS 293-1996"); + + break; + case 0x1380: + sb.AppendLine("Device complies with SSA-PH3 (no version claimed)"); + + break; + case 0x139B: + sb.AppendLine("Device complies with SSA-PH3 T10.1/1146-D revision 05b"); + + break; + case 0x139C: + sb.AppendLine("Device complies with SSA-PH3 ANSI INCITS 307-1998"); + + break; + case 0x14A0: + sb.AppendLine("Device complies with IEEE 1394 (no version claimed)"); + + break; + case 0x14BD: + sb.AppendLine("Device complies with ANSI IEEE 1394-1995"); + + break; + case 0x14C0: + sb.AppendLine("Device complies with IEEE 1394a (no version claimed)"); + + break; + case 0x14E0: + sb.AppendLine("Device complies with IEEE 1394b (no version claimed)"); + + break; + case 0x15E0: + sb.AppendLine("Device complies with ATA/ATAPI-6 (no version claimed)"); + + break; + case 0x15FD: + sb.AppendLine("Device complies with ATA/ATAPI-6 ANSI INCITS 361-2002"); + + break; + case 0x1600: + sb.AppendLine("Device complies with ATA/ATAPI-7 (no version claimed)"); + + break; + case 0x1602: + sb.AppendLine("Device complies with ATA/ATAPI-7 T13/1532-D revision 3"); + + break; + case 0x161C: + sb.AppendLine("Device complies with ATA/ATAPI-7 ANSI INCITS 397-2005"); + + break; + case 0x161E: + sb.AppendLine("Device complies with ATA/ATAPI-7 ISO/IEC 24739"); + + break; + case 0x1620: + sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-AAM (no version claimed)"); + + break; + case 0x1621: + sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-APT Parallel Transport (no version claimed)"); + + break; + case 0x1622: + sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-AST Serial Transport (no version claimed)"); + + break; + case 0x1623: + sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-ACS ATA/ATAPI Command Set (no version claimed)"); + + break; + case 0x1628: + sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-AAM ANSI INCITS 451-2008"); + + break; + case 0x162A: + sb.AppendLine("Device complies with ATA/ATAPI-8 ATA8-ACS ANSI INCITS 452-2009 w/ Amendment 1"); + + break; + case 0x1728: + sb.AppendLine("Device complies with Universal Serial Bus Specification, Revision 1.1"); + + break; + case 0x1729: + sb.AppendLine("Device complies with Universal Serial Bus Specification, Revision 2.0"); + + break; + case 0x1730: + sb.AppendLine("Device complies with USB Mass Storage Class Bulk-Only Transport, Revision 1.0"); + + break; + case 0x1740: + sb.AppendLine("Device complies with UAS (no version claimed)"); + + break; + case 0x1743: + sb.AppendLine("Device complies with UAS T10/2095-D revision 02"); + + break; + case 0x1747: + sb.AppendLine("Device complies with UAS T10/2095-D revision 04"); + + break; + case 0x1748: + sb.AppendLine("Device complies with UAS ANSI INCITS 471-2010"); + + break; + case 0x1749: + sb.AppendLine("Device complies with UAS ISO/IEC 14776-251:2014"); + + break; + case 0x1761: + sb.AppendLine("Device complies with ACS-2 (no version claimed)"); + + break; + case 0x1762: + sb.AppendLine("Device complies with ACS-2 ANSI INCITS 482-2013"); + + break; + case 0x1765: + sb.AppendLine("Device complies with ACS-3 (no version claimed)"); + + break; + case 0x1780: + sb.AppendLine("Device complies with UAS-2 (no version claimed)"); + + break; + case 0x1EA0: + sb.AppendLine("Device complies with SAT (no version claimed)"); + + break; + case 0x1EA7: + sb.AppendLine("Device complies with SAT T10/1711-D revision 8"); + + break; + case 0x1EAB: + sb.AppendLine("Device complies with SAT T10/1711-D revision 9"); + + break; + case 0x1EAD: + sb.AppendLine("Device complies with SAT ANSI INCITS 431-2007"); + + break; + case 0x1EC0: + sb.AppendLine("Device complies with SAT-2 (no version claimed)"); + + break; + case 0x1EC4: + sb.AppendLine("Device complies with SAT-2 T10/1826-D revision 06"); + + break; + case 0x1EC8: + sb.AppendLine("Device complies with SAT-2 T10/1826-D revision 09"); + + break; + case 0x1ECA: + sb.AppendLine("Device complies with SAT-2 ANSI INCITS 465-2010"); + + break; + case 0x1EE0: + sb.AppendLine("Device complies with SAT-3 (no version claimed)"); + + break; + case 0x1EE2: + sb.AppendLine("Device complies with SAT-3 T10/BSR INCITS 517 revision 4"); + + break; + case 0x1EE4: + sb.AppendLine("Device complies with SAT-3 T10/BSR INCITS 517 revision 7"); + + break; + case 0x1EE8: + sb.AppendLine("Device complies with SAT-3 ANSI INCITS 517-2015"); + + break; + case 0x1F00: + sb.AppendLine("Device complies with SAT-4 (no version claimed)"); + + break; + case 0x20A0: + sb.AppendLine("Device complies with SPL (no version claimed)"); + + break; + case 0x20A3: + sb.AppendLine("Device complies with SPL T10/2124-D revision 6a"); + + break; + case 0x20A5: + sb.AppendLine("Device complies with SPL T10/2124-D revision 7"); + + break; + case 0x20A7: + sb.AppendLine("Device complies with SPL ANSI INCITS 476-2011"); + + break; + case 0x20A8: + sb.AppendLine("Device complies with SPL ANSI INCITS 476-2011 + SPL AM1 INCITS 476/AM1 2012"); + + break; + case 0x20AA: + sb.AppendLine("Device complies with SPL ISO/IEC 14776-261:2012"); + + break; + case 0x20C0: + sb.AppendLine("Device complies with SPL-2 (no version claimed)"); + + break; + case 0x20C2: + sb.AppendLine("Device complies with SPL-2 T10/BSR INCITS 505 revision 4"); + + break; + case 0x20C4: + sb.AppendLine("Device complies with SPL-2 T10/BSR INCITS 505 revision 5"); + + break; + case 0x20C8: + sb.AppendLine("Device complies with SPL-2 ANSI INCITS 505-2013"); + + break; + case 0x20E0: + sb.AppendLine("Device complies with SPL-3 (no version claimed)"); + + break; + case 0x20E4: + sb.AppendLine("Device complies with SPL-3 T10/BSR INCITS 492 revision 6"); + + break; + case 0x20E6: + sb.AppendLine("Device complies with SPL-3 T10/BSR INCITS 492 revision 7"); + + break; + case 0x20E8: + sb.AppendLine("Device complies with SPL-3 ANSI INCITS 492-2015"); + + break; + case 0x2100: + sb.AppendLine("Device complies with SPL-4 (no version claimed)"); + + break; + case 0x21E0: + sb.AppendLine("Device complies with SOP (no version claimed)"); + + break; + case 0x21E4: + sb.AppendLine("Device complies with SOP T10/BSR INCITS 489 revision 4"); + + break; + case 0x21E6: + sb.AppendLine("Device complies with SOP T10/BSR INCITS 489 revision 5"); + + break; + case 0x21E8: + sb.AppendLine("Device complies with SOP ANSI INCITS 489-2014"); + + break; + case 0x2200: + sb.AppendLine("Device complies with PQI (no version claimed)"); + + break; + case 0x2204: + sb.AppendLine("Device complies with PQI T10/BSR INCITS 490 revision 6"); + + break; + case 0x2206: + sb.AppendLine("Device complies with PQI T10/BSR INCITS 490 revision 7"); + + break; + case 0x2208: + sb.AppendLine("Device complies with PQI ANSI INCITS 490-2014"); + + break; + case 0x2220: + sb.AppendLine("Device complies with SOP-2 (no version claimed)"); + + break; + case 0x2240: + sb.AppendLine("Device complies with PQI-2 (no version claimed)"); + + break; + case 0xFFC0: + sb.AppendLine("Device complies with IEEE 1667 (no version claimed)"); + + break; + case 0xFFC1: + sb.AppendLine("Device complies with IEEE 1667-2006"); + + break; + case 0xFFC2: + sb.AppendLine("Device complies with IEEE 1667-2009"); break; default: - sb.AppendFormat("Product family: {0}", response.Qt_ProductFamily).AppendLine(); + sb.AppendFormat("Device complies with unknown standard code 0x{0:X4}", VersionDescriptor). + AppendLine(); break; } - sb.AppendFormat("Release firmware: {0}", response.Qt_ReleasedFirmware).AppendLine(); - - sb.AppendFormat("Firmware version: {0}.{1}", response.Qt_FirmwareMajorVersion, - response.Qt_FirmwareMinorVersion).AppendLine(); - - sb.AppendFormat("EEPROM format version: {0}.{1}", response.Qt_EEPROMFormatMajorVersion, - response.Qt_EEPROMFormatMinorVersion).AppendLine(); - - sb.AppendFormat("Firmware personality: {0}", response.Qt_FirmwarePersonality).AppendLine(); - sb.AppendFormat("Firmware subpersonality: {0}", response.Qt_FirmwareSubPersonality).AppendLine(); - - sb.AppendFormat("Tape directory format version: {0}", response.Qt_TapeDirectoryFormatVersion). - AppendLine(); - - sb.AppendFormat("Controller hardware version: {0}", response.Qt_ControllerHardwareVersion).AppendLine(); - sb.AppendFormat("Drive EEPROM version: {0}", response.Qt_DriveEEPROMVersion).AppendLine(); - sb.AppendFormat("Drive hardware version: {0}", response.Qt_DriveHardwareVersion).AppendLine(); - - sb.AppendFormat("Media loader firmware version: {0}", response.Qt_MediaLoaderFirmwareVersion). - AppendLine(); - - sb.AppendFormat("Media loader hardware version: {0}", response.Qt_MediaLoaderHardwareVersion). - AppendLine(); - - sb.AppendFormat("Media loader mechanical version: {0}", response.Qt_MediaLoaderMechanicalVersion). - AppendLine(); - - if(response.Qt_LibraryPresent) - sb.AppendLine("Library is present"); - - if(response.Qt_MediaLoaderPresent) - sb.AppendLine("Media loader is present"); - - sb.AppendFormat("Module revision: {0}", StringHandlers.CToString(response.Qt_ModuleRevision)). - AppendLine(); - } - #endregion Quantum vendor prettifying - - #region IBM vendor prettifying - if(response.IBMPresent && - StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "ibm") - { - sb.AppendLine("IBM vendor-specific information:"); - - if(response.IBM_PerformanceLimit == 0) - sb.AppendLine("Performance is not limited"); - else - sb.AppendFormat("Performance is limited using factor {0}", response.IBM_PerformanceLimit); - - if(response.IBM_AutDis) - sb.AppendLine("Automation is disabled"); - - sb.AppendFormat("IBM OEM Specific Field: {0}", response.IBM_OEMSpecific).AppendLine(); - } - #endregion IBM vendor prettifying - - #region HP vendor prettifying - if(response.HPPresent && - StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "hp") - { - sb.AppendLine("HP vendor-specific information:"); - - if(response.HP_WORM) - sb.AppendFormat("Device supports WORM version {0}", response.HP_WORMVersion).AppendLine(); - - byte[] OBDRSign = - { - 0x24, 0x44, 0x52, 0x2D, 0x31, 0x30 - }; - - if(OBDRSign.SequenceEqual(response.HP_OBDR)) - sb.AppendLine("Device supports Tape Disaster Recovery"); - } - #endregion HP vendor prettifying - - #region Seagate vendor prettifying - if((response.SeagatePresent || response.Seagate2Present || response.Seagate3Present) && - StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "seagate") - { - sb.AppendLine("Seagate vendor-specific information:"); - - if(response.SeagatePresent) - sb.AppendFormat("Drive serial number: {0}", - StringHandlers.CToString(response.Seagate_DriveSerialNumber)).AppendLine(); - - if(response.Seagate2Present) - sb.AppendFormat("Drive copyright: {0}", StringHandlers.CToString(response.Seagate_Copyright)). - AppendLine(); - - if(response.Seagate3Present) - sb.AppendFormat("Drive servo part number: {0}", - PrintHex.ByteArrayToHexArrayString(response.Seagate_ServoPROMPartNo, 40)). - AppendLine(); - } - #endregion Seagate vendor prettifying - - #region Kreon vendor prettifying - if(response.KreonPresent) - sb.AppendFormat("Drive is flashed with Kreon firmware {0}.", - StringHandlers.CToString(response.KreonVersion)).AppendLine(); - #endregion Kreon vendor prettifying - - #if DEBUG - if(response.DeviceTypeModifier != 0) - sb.AppendFormat("Vendor's device type modifier = 0x{0:X2}", response.DeviceTypeModifier).AppendLine(); - - if(response.Reserved2 != 0) - sb.AppendFormat("Reserved byte 5, bits 2 to 1 = 0x{0:X2}", response.Reserved2).AppendLine(); - - if(response.Reserved3 != 0) - sb.AppendFormat("Reserved byte 56, bits 7 to 4 = 0x{0:X2}", response.Reserved3).AppendLine(); - - if(response.Reserved4 != 0) - sb.AppendFormat("Reserved byte 57 = 0x{0:X2}", response.Reserved4).AppendLine(); - - if(response.Reserved5 != null) - { - sb.AppendLine("Reserved bytes 74 to 95"); - sb.AppendLine("============================================================"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.Reserved5, 60)); - sb.AppendLine("============================================================"); - } - - if(response.VendorSpecific != null && - response.IsHiMD) - if(response.KreonPresent) - { - byte[] vendor = new byte[7]; - Array.Copy(response.VendorSpecific, 11, vendor, 0, 7); - sb.AppendLine("Vendor-specific bytes 47 to 55"); - sb.AppendLine("============================================================"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(vendor, 60)); - sb.AppendLine("============================================================"); - } - else - { - sb.AppendLine("Vendor-specific bytes 36 to 55"); - sb.AppendLine("============================================================"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VendorSpecific, 60)); - sb.AppendLine("============================================================"); - } - - if(response.IsHiMD) - { - sb.AppendLine("Hi-MD device."); - - if(response.HiMDSpecific != null) - { - sb.AppendLine("Hi-MD specific bytes 44 to 55"); - sb.AppendLine("============================================================"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.HiMDSpecific, 60)); - sb.AppendLine("============================================================"); - } - } - - if(response.VendorSpecific2 == null) - return sb.ToString(); - - sb.AppendFormat("Vendor-specific bytes 96 to {0}", response.AdditionalLength + 4).AppendLine(); - sb.AppendLine("============================================================"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VendorSpecific2, 60)); - sb.AppendLine("============================================================"); - #endif - - return sb.ToString(); - } - - public static string Prettify(byte[] SCSIInquiryResponse) + #region Quantum vendor prettifying + if(response.QuantumPresent && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "quantum") { - CommonTypes.Structs.Devices.SCSI.Inquiry? decoded = - CommonTypes.Structs.Devices.SCSI.Inquiry.Decode(SCSIInquiryResponse); + sb.AppendLine("Quantum vendor-specific information:"); - return Prettify(decoded); + switch(response.Qt_ProductFamily) + { + case 0: + sb.AppendLine("Product family is not specified"); + + break; + case 1: + sb.AppendLine("Product family is 2.6 GB"); + + break; + case 2: + sb.AppendLine("Product family is 6.0 GB"); + + break; + case 3: + sb.AppendLine("Product family is 10.0/20.0 GB"); + + break; + case 5: + sb.AppendLine("Product family is 20.0/40.0 GB"); + + break; + case 6: + sb.AppendLine("Product family is 15.0/30.0 GB"); + + break; + default: + sb.AppendFormat("Product family: {0}", response.Qt_ProductFamily).AppendLine(); + + break; + } + + sb.AppendFormat("Release firmware: {0}", response.Qt_ReleasedFirmware).AppendLine(); + + sb.AppendFormat("Firmware version: {0}.{1}", response.Qt_FirmwareMajorVersion, + response.Qt_FirmwareMinorVersion).AppendLine(); + + sb.AppendFormat("EEPROM format version: {0}.{1}", response.Qt_EEPROMFormatMajorVersion, + response.Qt_EEPROMFormatMinorVersion).AppendLine(); + + sb.AppendFormat("Firmware personality: {0}", response.Qt_FirmwarePersonality).AppendLine(); + sb.AppendFormat("Firmware subpersonality: {0}", response.Qt_FirmwareSubPersonality).AppendLine(); + + sb.AppendFormat("Tape directory format version: {0}", response.Qt_TapeDirectoryFormatVersion). + AppendLine(); + + sb.AppendFormat("Controller hardware version: {0}", response.Qt_ControllerHardwareVersion).AppendLine(); + sb.AppendFormat("Drive EEPROM version: {0}", response.Qt_DriveEEPROMVersion).AppendLine(); + sb.AppendFormat("Drive hardware version: {0}", response.Qt_DriveHardwareVersion).AppendLine(); + + sb.AppendFormat("Media loader firmware version: {0}", response.Qt_MediaLoaderFirmwareVersion). + AppendLine(); + + sb.AppendFormat("Media loader hardware version: {0}", response.Qt_MediaLoaderHardwareVersion). + AppendLine(); + + sb.AppendFormat("Media loader mechanical version: {0}", response.Qt_MediaLoaderMechanicalVersion). + AppendLine(); + + if(response.Qt_LibraryPresent) + sb.AppendLine("Library is present"); + + if(response.Qt_MediaLoaderPresent) + sb.AppendLine("Media loader is present"); + + sb.AppendFormat("Module revision: {0}", StringHandlers.CToString(response.Qt_ModuleRevision)). + AppendLine(); } + #endregion Quantum vendor prettifying + + #region IBM vendor prettifying + if(response.IBMPresent && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "ibm") + { + sb.AppendLine("IBM vendor-specific information:"); + + if(response.IBM_PerformanceLimit == 0) + sb.AppendLine("Performance is not limited"); + else + sb.AppendFormat("Performance is limited using factor {0}", response.IBM_PerformanceLimit); + + if(response.IBM_AutDis) + sb.AppendLine("Automation is disabled"); + + sb.AppendFormat("IBM OEM Specific Field: {0}", response.IBM_OEMSpecific).AppendLine(); + } + #endregion IBM vendor prettifying + + #region HP vendor prettifying + if(response.HPPresent && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "hp") + { + sb.AppendLine("HP vendor-specific information:"); + + if(response.HP_WORM) + sb.AppendFormat("Device supports WORM version {0}", response.HP_WORMVersion).AppendLine(); + + byte[] OBDRSign = + { + 0x24, 0x44, 0x52, 0x2D, 0x31, 0x30 + }; + + if(OBDRSign.SequenceEqual(response.HP_OBDR)) + sb.AppendLine("Device supports Tape Disaster Recovery"); + } + #endregion HP vendor prettifying + + #region Seagate vendor prettifying + if((response.SeagatePresent || response.Seagate2Present || response.Seagate3Present) && + StringHandlers.CToString(response.VendorIdentification).ToLowerInvariant().Trim() == "seagate") + { + sb.AppendLine("Seagate vendor-specific information:"); + + if(response.SeagatePresent) + sb.AppendFormat("Drive serial number: {0}", + StringHandlers.CToString(response.Seagate_DriveSerialNumber)).AppendLine(); + + if(response.Seagate2Present) + sb.AppendFormat("Drive copyright: {0}", StringHandlers.CToString(response.Seagate_Copyright)). + AppendLine(); + + if(response.Seagate3Present) + sb.AppendFormat("Drive servo part number: {0}", + PrintHex.ByteArrayToHexArrayString(response.Seagate_ServoPROMPartNo, 40)). + AppendLine(); + } + #endregion Seagate vendor prettifying + + #region Kreon vendor prettifying + if(response.KreonPresent) + sb.AppendFormat("Drive is flashed with Kreon firmware {0}.", + StringHandlers.CToString(response.KreonVersion)).AppendLine(); + #endregion Kreon vendor prettifying + + #if DEBUG + if(response.DeviceTypeModifier != 0) + sb.AppendFormat("Vendor's device type modifier = 0x{0:X2}", response.DeviceTypeModifier).AppendLine(); + + if(response.Reserved2 != 0) + sb.AppendFormat("Reserved byte 5, bits 2 to 1 = 0x{0:X2}", response.Reserved2).AppendLine(); + + if(response.Reserved3 != 0) + sb.AppendFormat("Reserved byte 56, bits 7 to 4 = 0x{0:X2}", response.Reserved3).AppendLine(); + + if(response.Reserved4 != 0) + sb.AppendFormat("Reserved byte 57 = 0x{0:X2}", response.Reserved4).AppendLine(); + + if(response.Reserved5 != null) + { + sb.AppendLine("Reserved bytes 74 to 95"); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.Reserved5, 60)); + sb.AppendLine("============================================================"); + } + + if(response.VendorSpecific != null && + response.IsHiMD) + if(response.KreonPresent) + { + byte[] vendor = new byte[7]; + Array.Copy(response.VendorSpecific, 11, vendor, 0, 7); + sb.AppendLine("Vendor-specific bytes 47 to 55"); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(vendor, 60)); + sb.AppendLine("============================================================"); + } + else + { + sb.AppendLine("Vendor-specific bytes 36 to 55"); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VendorSpecific, 60)); + sb.AppendLine("============================================================"); + } + + if(response.IsHiMD) + { + sb.AppendLine("Hi-MD device."); + + if(response.HiMDSpecific != null) + { + sb.AppendLine("Hi-MD specific bytes 44 to 55"); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.HiMDSpecific, 60)); + sb.AppendLine("============================================================"); + } + } + + if(response.VendorSpecific2 == null) + return sb.ToString(); + + sb.AppendFormat("Vendor-specific bytes 96 to {0}", response.AdditionalLength + 4).AppendLine(); + sb.AppendLine("============================================================"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VendorSpecific2, 60)); + sb.AppendLine("============================================================"); + #endif + + return sb.ToString(); + } + + public static string Prettify(byte[] SCSIInquiryResponse) + { + CommonTypes.Structs.Devices.SCSI.Inquiry? decoded = + CommonTypes.Structs.Devices.SCSI.Inquiry.Decode(SCSIInquiryResponse); + + return Prettify(decoded); } } \ No newline at end of file diff --git a/SCSI/MMC/AACS.cs b/SCSI/MMC/AACS.cs index fa7820f..d5683d5 100644 --- a/SCSI/MMC/AACS.cs +++ b/SCSI/MMC/AACS.cs @@ -35,395 +35,394 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class AACS { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class AACS + public static AACSVolumeIdentifier? DecodeAACSVolumeIdentifier(byte[] AACSVIResponse) { - public static AACSVolumeIdentifier? DecodeAACSVolumeIdentifier(byte[] AACSVIResponse) + if(AACSVIResponse == null) + return null; + + var decoded = new AACSVolumeIdentifier(); + + decoded.VolumeIdentifier = new byte[AACSVIResponse.Length - 4]; + + decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSVIResponse, 0); + decoded.Reserved1 = AACSVIResponse[2]; + decoded.Reserved2 = AACSVIResponse[3]; + Array.Copy(AACSVIResponse, 4, decoded.VolumeIdentifier, 0, AACSVIResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSVolumeIdentifier(AACSVolumeIdentifier? AACSVIResponse) + { + if(AACSVIResponse == null) + return null; + + AACSVolumeIdentifier response = AACSVIResponse.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 + sb.AppendFormat("AACS Volume Identifier in hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VolumeIdentifier, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSVolumeIdentifier(byte[] AACSVIResponse) + { + AACSVolumeIdentifier? decoded = DecodeAACSVolumeIdentifier(AACSVIResponse); + + return PrettifyAACSVolumeIdentifier(decoded); + } + + public static AACSMediaSerialNumber? DecodeAACSMediaSerialNumber(byte[] AACSMSNResponse) + { + if(AACSMSNResponse == null) + return null; + + var decoded = new AACSMediaSerialNumber(); + + decoded.MediaSerialNumber = new byte[AACSMSNResponse.Length - 4]; + + decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSMSNResponse, 0); + decoded.Reserved1 = AACSMSNResponse[2]; + decoded.Reserved2 = AACSMSNResponse[3]; + Array.Copy(AACSMSNResponse, 4, decoded.MediaSerialNumber, 0, AACSMSNResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSMediaSerialNumber(AACSMediaSerialNumber? AACSMSNResponse) + { + if(AACSMSNResponse == null) + return null; + + AACSMediaSerialNumber response = AACSMSNResponse.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 + sb.AppendFormat("AACS Media Serial Number in hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaSerialNumber, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSMediaSerialNumber(byte[] AACSMSNResponse) + { + AACSMediaSerialNumber? decoded = DecodeAACSMediaSerialNumber(AACSMSNResponse); + + return PrettifyAACSMediaSerialNumber(decoded); + } + + public static AACSMediaIdentifier? DecodeAACSMediaIdentifier(byte[] AACSMIResponse) + { + if(AACSMIResponse == null) + return null; + + var decoded = new AACSMediaIdentifier(); + + decoded.MediaIdentifier = new byte[AACSMIResponse.Length - 4]; + + decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSMIResponse, 0); + decoded.Reserved1 = AACSMIResponse[2]; + decoded.Reserved2 = AACSMIResponse[3]; + Array.Copy(AACSMIResponse, 4, decoded.MediaIdentifier, 0, AACSMIResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSMediaIdentifier(AACSMediaIdentifier? AACSMIResponse) + { + if(AACSMIResponse == null) + return null; + + AACSMediaIdentifier response = AACSMIResponse.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 + sb.AppendFormat("AACS Media Identifier in hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaIdentifier, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSMediaIdentifier(byte[] AACSMIResponse) + { + AACSMediaIdentifier? decoded = DecodeAACSMediaIdentifier(AACSMIResponse); + + return PrettifyAACSMediaIdentifier(decoded); + } + + public static AACSMediaKeyBlock? DecodeAACSMediaKeyBlock(byte[] AACSMKBResponse) + { + if(AACSMKBResponse == null) + return null; + + var decoded = new AACSMediaKeyBlock(); + + decoded.MediaKeyBlockPacks = new byte[AACSMKBResponse.Length - 4]; + + decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSMKBResponse, 0); + decoded.Reserved = AACSMKBResponse[2]; + decoded.TotalPacks = AACSMKBResponse[3]; + Array.Copy(AACSMKBResponse, 4, decoded.MediaKeyBlockPacks, 0, AACSMKBResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSMediaKeyBlock(AACSMediaKeyBlock? AACSMKBResponse) + { + if(AACSMKBResponse == null) + return null; + + AACSMediaKeyBlock response = AACSMKBResponse.Value; + + 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(); + + sb.AppendFormat("AACS Media Key Blocks in hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaKeyBlockPacks, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSMediaKeyBlock(byte[] AACSMKBResponse) + { + AACSMediaKeyBlock? decoded = DecodeAACSMediaKeyBlock(AACSMKBResponse); + + return PrettifyAACSMediaKeyBlock(decoded); + } + + public static AACSDataKeys? DecodeAACSDataKeys(byte[] AACSDKResponse) + { + if(AACSDKResponse == null) + return null; + + var decoded = new AACSDataKeys(); + + decoded.DataKeys = new byte[AACSDKResponse.Length - 4]; + + decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSDKResponse, 0); + decoded.Reserved1 = AACSDKResponse[2]; + decoded.Reserved2 = AACSDKResponse[3]; + Array.Copy(AACSDKResponse, 4, decoded.DataKeys, 0, AACSDKResponse.Length - 4); + + return decoded; + } + + public static string PrettifyAACSDataKeys(AACSDataKeys? AACSDKResponse) + { + if(AACSDKResponse == null) + return null; + + AACSDataKeys response = AACSDKResponse.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 + sb.AppendFormat("AACS Data Keys in hex follows:"); + sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.DataKeys, 80)); + + return sb.ToString(); + } + + public static string PrettifyAACSDataKeys(byte[] AACSDKResponse) + { + AACSDataKeys? decoded = DecodeAACSDataKeys(AACSDKResponse); + + return PrettifyAACSDataKeys(decoded); + } + + public static AACSLBAExtentsResponse? DecodeAACSLBAExtents(byte[] AACSLBAExtsResponse) + { + if(AACSLBAExtsResponse == null) + return null; + + var decoded = new AACSLBAExtentsResponse { - if(AACSVIResponse == null) - return null; - - var decoded = new AACSVolumeIdentifier(); - - decoded.VolumeIdentifier = new byte[AACSVIResponse.Length - 4]; - - decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSVIResponse, 0); - decoded.Reserved1 = AACSVIResponse[2]; - decoded.Reserved2 = AACSVIResponse[3]; - Array.Copy(AACSVIResponse, 4, decoded.VolumeIdentifier, 0, AACSVIResponse.Length - 4); + DataLength = BigEndianBitConverter.ToUInt16(AACSLBAExtsResponse, 0), + Reserved = AACSLBAExtsResponse[2], + MaxLBAExtents = AACSLBAExtsResponse[3] + }; + if((AACSLBAExtsResponse.Length - 4) % 16 != 0) return decoded; - } - public static string PrettifyAACSVolumeIdentifier(AACSVolumeIdentifier? AACSVIResponse) + decoded.Extents = new AACSLBAExtent[(AACSLBAExtsResponse.Length - 4) / 16]; + + for(int i = 0; i < (AACSLBAExtsResponse.Length - 4) / 16; i++) { - if(AACSVIResponse == null) - return null; - - AACSVolumeIdentifier response = AACSVIResponse.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 - sb.AppendFormat("AACS Volume Identifier in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.VolumeIdentifier, 80)); - - return sb.ToString(); + decoded.Extents[i].Reserved = new byte[8]; + Array.Copy(AACSLBAExtsResponse, 0 + (i * 16) + 4, decoded.Extents[i].Reserved, 0, 8); + decoded.Extents[i].StartLBA = BigEndianBitConverter.ToUInt32(AACSLBAExtsResponse, 8 + (i * 16) + 4); + decoded.Extents[i].LBACount = BigEndianBitConverter.ToUInt32(AACSLBAExtsResponse, 12 + (i * 16) + 4); } - public static string PrettifyAACSVolumeIdentifier(byte[] AACSVIResponse) - { - AACSVolumeIdentifier? decoded = DecodeAACSVolumeIdentifier(AACSVIResponse); - - return PrettifyAACSVolumeIdentifier(decoded); - } - - public static AACSMediaSerialNumber? DecodeAACSMediaSerialNumber(byte[] AACSMSNResponse) - { - if(AACSMSNResponse == null) - return null; - - var decoded = new AACSMediaSerialNumber(); - - decoded.MediaSerialNumber = new byte[AACSMSNResponse.Length - 4]; - - decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSMSNResponse, 0); - decoded.Reserved1 = AACSMSNResponse[2]; - decoded.Reserved2 = AACSMSNResponse[3]; - Array.Copy(AACSMSNResponse, 4, decoded.MediaSerialNumber, 0, AACSMSNResponse.Length - 4); - - return decoded; - } - - public static string PrettifyAACSMediaSerialNumber(AACSMediaSerialNumber? AACSMSNResponse) - { - if(AACSMSNResponse == null) - return null; - - AACSMediaSerialNumber response = AACSMSNResponse.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 - sb.AppendFormat("AACS Media Serial Number in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaSerialNumber, 80)); - - return sb.ToString(); - } - - public static string PrettifyAACSMediaSerialNumber(byte[] AACSMSNResponse) - { - AACSMediaSerialNumber? decoded = DecodeAACSMediaSerialNumber(AACSMSNResponse); - - return PrettifyAACSMediaSerialNumber(decoded); - } - - public static AACSMediaIdentifier? DecodeAACSMediaIdentifier(byte[] AACSMIResponse) - { - if(AACSMIResponse == null) - return null; - - var decoded = new AACSMediaIdentifier(); - - decoded.MediaIdentifier = new byte[AACSMIResponse.Length - 4]; - - decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSMIResponse, 0); - decoded.Reserved1 = AACSMIResponse[2]; - decoded.Reserved2 = AACSMIResponse[3]; - Array.Copy(AACSMIResponse, 4, decoded.MediaIdentifier, 0, AACSMIResponse.Length - 4); - - return decoded; - } - - public static string PrettifyAACSMediaIdentifier(AACSMediaIdentifier? AACSMIResponse) - { - if(AACSMIResponse == null) - return null; - - AACSMediaIdentifier response = AACSMIResponse.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 - sb.AppendFormat("AACS Media Identifier in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaIdentifier, 80)); - - return sb.ToString(); - } - - public static string PrettifyAACSMediaIdentifier(byte[] AACSMIResponse) - { - AACSMediaIdentifier? decoded = DecodeAACSMediaIdentifier(AACSMIResponse); - - return PrettifyAACSMediaIdentifier(decoded); - } - - public static AACSMediaKeyBlock? DecodeAACSMediaKeyBlock(byte[] AACSMKBResponse) - { - if(AACSMKBResponse == null) - return null; - - var decoded = new AACSMediaKeyBlock(); - - decoded.MediaKeyBlockPacks = new byte[AACSMKBResponse.Length - 4]; - - decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSMKBResponse, 0); - decoded.Reserved = AACSMKBResponse[2]; - decoded.TotalPacks = AACSMKBResponse[3]; - Array.Copy(AACSMKBResponse, 4, decoded.MediaKeyBlockPacks, 0, AACSMKBResponse.Length - 4); - - return decoded; - } - - public static string PrettifyAACSMediaKeyBlock(AACSMediaKeyBlock? AACSMKBResponse) - { - if(AACSMKBResponse == null) - return null; - - AACSMediaKeyBlock response = AACSMKBResponse.Value; - - 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(); - - sb.AppendFormat("AACS Media Key Blocks in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MediaKeyBlockPacks, 80)); - - return sb.ToString(); - } - - public static string PrettifyAACSMediaKeyBlock(byte[] AACSMKBResponse) - { - AACSMediaKeyBlock? decoded = DecodeAACSMediaKeyBlock(AACSMKBResponse); - - return PrettifyAACSMediaKeyBlock(decoded); - } - - public static AACSDataKeys? DecodeAACSDataKeys(byte[] AACSDKResponse) - { - if(AACSDKResponse == null) - return null; - - var decoded = new AACSDataKeys(); - - decoded.DataKeys = new byte[AACSDKResponse.Length - 4]; - - decoded.DataLength = BigEndianBitConverter.ToUInt16(AACSDKResponse, 0); - decoded.Reserved1 = AACSDKResponse[2]; - decoded.Reserved2 = AACSDKResponse[3]; - Array.Copy(AACSDKResponse, 4, decoded.DataKeys, 0, AACSDKResponse.Length - 4); - - return decoded; - } - - public static string PrettifyAACSDataKeys(AACSDataKeys? AACSDKResponse) - { - if(AACSDKResponse == null) - return null; - - AACSDataKeys response = AACSDKResponse.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 - sb.AppendFormat("AACS Data Keys in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.DataKeys, 80)); - - return sb.ToString(); - } - - public static string PrettifyAACSDataKeys(byte[] AACSDKResponse) - { - AACSDataKeys? decoded = DecodeAACSDataKeys(AACSDKResponse); - - return PrettifyAACSDataKeys(decoded); - } - - public static AACSLBAExtentsResponse? DecodeAACSLBAExtents(byte[] AACSLBAExtsResponse) - { - if(AACSLBAExtsResponse == null) - return null; - - var decoded = new AACSLBAExtentsResponse - { - DataLength = BigEndianBitConverter.ToUInt16(AACSLBAExtsResponse, 0), - Reserved = AACSLBAExtsResponse[2], - MaxLBAExtents = AACSLBAExtsResponse[3] - }; - - if((AACSLBAExtsResponse.Length - 4) % 16 != 0) - return decoded; - - decoded.Extents = new AACSLBAExtent[(AACSLBAExtsResponse.Length - 4) / 16]; - - for(int i = 0; i < (AACSLBAExtsResponse.Length - 4) / 16; i++) - { - decoded.Extents[i].Reserved = new byte[8]; - Array.Copy(AACSLBAExtsResponse, 0 + (i * 16) + 4, decoded.Extents[i].Reserved, 0, 8); - decoded.Extents[i].StartLBA = BigEndianBitConverter.ToUInt32(AACSLBAExtsResponse, 8 + (i * 16) + 4); - decoded.Extents[i].LBACount = BigEndianBitConverter.ToUInt32(AACSLBAExtsResponse, 12 + (i * 16) + 4); - } - - return decoded; - } - - public static string PrettifyAACSLBAExtents(AACSLBAExtentsResponse? AACSLBAExtsResponse) - { - if(AACSLBAExtsResponse == null) - return null; - - AACSLBAExtentsResponse response = AACSLBAExtsResponse.Value; - - var sb = new StringBuilder(); - - if(response.MaxLBAExtents == 0) - 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(); - - for(int i = 0; i < response.Extents.Length; i++) - sb.AppendFormat("LBA Extent {0} starts at LBA {1} and goes for {2} sectors", i, - response.Extents[i].StartLBA, response.Extents[i].LBACount); - - return sb.ToString(); - } - - public static string PrettifyAACSLBAExtents(byte[] AACSLBAExtsResponse) - { - AACSLBAExtentsResponse? decoded = DecodeAACSLBAExtents(AACSLBAExtsResponse); - - return PrettifyAACSLBAExtents(decoded); - } - - public struct AACSVolumeIdentifier - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end AACS volume identifier data - public byte[] VolumeIdentifier; - } - - public struct AACSMediaSerialNumber - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end AACS media serial number - public byte[] MediaSerialNumber; - } - - public struct AACSMediaIdentifier - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end AACS media identifier data - public byte[] MediaIdentifier; - } - - public struct AACSMediaKeyBlock - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved; - /// Byte 3 Number of MKB packs available to transfer - public byte TotalPacks; - /// Bytes 4 to end AACS media key block packs - public byte[] MediaKeyBlockPacks; - } - - public struct AACSDataKeys - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to end AACS data keys - public byte[] DataKeys; - } - - public struct AACSLBAExtentsResponse - { - /// Bytes 0 to 1 Data Length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved; - /// - /// Byte 3 Number of LBA extents the drive can store. if(MaxLBAExtents == 0 && DataLength > 2), 256 - /// extents can be stored - /// - public byte MaxLBAExtents; - /// Bytes 4 to end LBA Extents - public AACSLBAExtent[] Extents; - } - - public struct AACSLBAExtent - { - /// Bytes 0 to 7 Reserved - public byte[] Reserved; - /// Bytes 8 to 11 Start LBA of extent - public uint StartLBA; - /// Bytes 12 to 15 Extent length - public uint LBACount; - } + return decoded; + } + + public static string PrettifyAACSLBAExtents(AACSLBAExtentsResponse? AACSLBAExtsResponse) + { + if(AACSLBAExtsResponse == null) + return null; + + AACSLBAExtentsResponse response = AACSLBAExtsResponse.Value; + + var sb = new StringBuilder(); + + if(response.MaxLBAExtents == 0) + 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(); + + for(int i = 0; i < response.Extents.Length; i++) + sb.AppendFormat("LBA Extent {0} starts at LBA {1} and goes for {2} sectors", i, + response.Extents[i].StartLBA, response.Extents[i].LBACount); + + return sb.ToString(); + } + + public static string PrettifyAACSLBAExtents(byte[] AACSLBAExtsResponse) + { + AACSLBAExtentsResponse? decoded = DecodeAACSLBAExtents(AACSLBAExtsResponse); + + return PrettifyAACSLBAExtents(decoded); + } + + public struct AACSVolumeIdentifier + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS volume identifier data + public byte[] VolumeIdentifier; + } + + public struct AACSMediaSerialNumber + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS media serial number + public byte[] MediaSerialNumber; + } + + public struct AACSMediaIdentifier + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS media identifier data + public byte[] MediaIdentifier; + } + + public struct AACSMediaKeyBlock + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved; + /// Byte 3 Number of MKB packs available to transfer + public byte TotalPacks; + /// Bytes 4 to end AACS media key block packs + public byte[] MediaKeyBlockPacks; + } + + public struct AACSDataKeys + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to end AACS data keys + public byte[] DataKeys; + } + + public struct AACSLBAExtentsResponse + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved; + /// + /// Byte 3 Number of LBA extents the drive can store. if(MaxLBAExtents == 0 && DataLength > 2), 256 + /// extents can be stored + /// + public byte MaxLBAExtents; + /// Bytes 4 to end LBA Extents + public AACSLBAExtent[] Extents; + } + + public struct AACSLBAExtent + { + /// Bytes 0 to 7 Reserved + public byte[] Reserved; + /// Bytes 8 to 11 Start LBA of extent + public uint StartLBA; + /// Bytes 12 to 15 Extent length + public uint LBACount; } } \ No newline at end of file diff --git a/SCSI/MMC/CPRM.cs b/SCSI/MMC/CPRM.cs index b3325ef..88fd500 100644 --- a/SCSI/MMC/CPRM.cs +++ b/SCSI/MMC/CPRM.cs @@ -35,82 +35,81 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class CPRM { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class CPRM + public static CPRMMediaKeyBlock? DecodeCPRMMediaKeyBlock(byte[] CPRMMKBResponse) { - public static CPRMMediaKeyBlock? DecodeCPRMMediaKeyBlock(byte[] CPRMMKBResponse) + if(CPRMMKBResponse == null) + return null; + + var decoded = new CPRMMediaKeyBlock { - if(CPRMMKBResponse == null) - return null; + MKBPackData = new byte[CPRMMKBResponse.Length - 4], + DataLength = BigEndianBitConverter.ToUInt16(CPRMMKBResponse, 0), + Reserved = CPRMMKBResponse[2], + TotalPacks = CPRMMKBResponse[3] + }; - var decoded = new CPRMMediaKeyBlock - { - MKBPackData = new byte[CPRMMKBResponse.Length - 4], - DataLength = BigEndianBitConverter.ToUInt16(CPRMMKBResponse, 0), - Reserved = CPRMMKBResponse[2], - TotalPacks = CPRMMKBResponse[3] - }; + Array.Copy(CPRMMKBResponse, 4, decoded.MKBPackData, 0, CPRMMKBResponse.Length - 4); - Array.Copy(CPRMMKBResponse, 4, decoded.MKBPackData, 0, CPRMMKBResponse.Length - 4); + return decoded; + } - return decoded; - } + public static string PrettifyCPRMMediaKeyBlock(CPRMMediaKeyBlock? CPRMMKBResponse) + { + if(CPRMMKBResponse == null) + return null; - public static string PrettifyCPRMMediaKeyBlock(CPRMMediaKeyBlock? CPRMMKBResponse) - { - if(CPRMMKBResponse == null) - return null; + CPRMMediaKeyBlock response = CPRMMKBResponse.Value; - CPRMMediaKeyBlock response = CPRMMKBResponse.Value; + var 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)); - sb.AppendFormat("CPRM Media Key Blocks in hex follows:"); - sb.AppendLine(PrintHex.ByteArrayToHexArrayString(response.MKBPackData, 80)); + return sb.ToString(); + } - return sb.ToString(); - } + public static string PrettifyCPRMMediaKeyBlock(byte[] CPRMMKBResponse) + { + CPRMMediaKeyBlock? decoded = DecodeCPRMMediaKeyBlock(CPRMMKBResponse); - public static string PrettifyCPRMMediaKeyBlock(byte[] CPRMMKBResponse) - { - CPRMMediaKeyBlock? decoded = DecodeCPRMMediaKeyBlock(CPRMMKBResponse); + return PrettifyCPRMMediaKeyBlock(decoded); + } - return PrettifyCPRMMediaKeyBlock(decoded); - } - - public struct CPRMMediaKeyBlock - { - /// Bytes 0 to 1 Data Length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved; - /// Byte 3 Number of MKB packs available to transfer - public byte TotalPacks; - /// Byte 4 MKB Packs - public byte[] MKBPackData; - } + public struct CPRMMediaKeyBlock + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved; + /// Byte 3 Number of MKB packs available to transfer + public byte TotalPacks; + /// Byte 4 MKB Packs + public byte[] MKBPackData; } } \ No newline at end of file diff --git a/SCSI/MMC/DiscInformation.cs b/SCSI/MMC/DiscInformation.cs index 468a841..eae7eee 100644 --- a/SCSI/MMC/DiscInformation.cs +++ b/SCSI/MMC/DiscInformation.cs @@ -34,433 +34,432 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DiscInformation { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class DiscInformation + public static StandardDiscInformation? Decode000b(byte[] response) { - public static StandardDiscInformation? Decode000b(byte[] response) - { - if(response.Length < 32) - return null; - - if((response[2] & 0xE0) != 0) - return null; - - var decoded = new StandardDiscInformation - { - DataLength = (ushort)((response[0] << 8) + response[1]) - }; - - if(decoded.DataLength + 2 != response.Length) - return null; - - decoded.DataType = (byte)((response[2] & 0xE0) >> 5); - decoded.Erasable |= (response[2] & 0x10) == 0x10; - decoded.LastSessionStatus = (byte)((response[2] & 0x0C) >> 2); - decoded.DiscStatus = (byte)(response[2] & 0x03); - decoded.FirstTrackNumber = response[3]; - decoded.Sessions = (ushort)((response[9] << 8) + response[4]); - decoded.FirstTrackLastSession = (ushort)((response[10] << 8) + response[5]); - decoded.LastTrackLastSession = (ushort)((response[11] << 8) + response[6]); - - decoded.DID_V |= (response[7] & 0x80) == 0x80; - decoded.DBC_V |= (response[7] & 0x40) == 0x40; - decoded.URU |= (response[7] & 0x20) == 0x20; - decoded.DAC_V |= (response[7] & 0x10) == 0x10; - decoded.Reserved |= (response[7] & 0x08) == 0x08; - decoded.Dbit |= (response[7] & 0x04) == 0x04; - decoded.BGFormatStatus = (byte)(response[7] & 0x03); - - 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]); - - byte[] temp = new byte[8]; - Array.Copy(response, 24, temp, 0, 8); - Array.Reverse(temp); - decoded.DiscBarcode = BitConverter.ToUInt64(temp, 0); - - if(response.Length < 34) - return null; - - decoded.DiscApplicationCode = response[32]; - decoded.OPCTablesNumber = response[33]; - - 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]); - - decoded.OPCTables[i].OPCValues = new byte[6]; - Array.Copy(response, 34 + (i * 8) + 2, decoded.OPCTables[i].OPCValues, 0, 6); - } - - return decoded; - } - - public static string Prettify000b(StandardDiscInformation? information) - { - if(information?.DataType != 0) - return null; - - var sb = new StringBuilder(); - - switch(information.Value.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", information.Value.DiscType).AppendLine(); - - break; - } - - switch(information.Value.DiscStatus) - { - 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(information.Value.Erasable) - sb.AppendLine("Disc is erasable"); - - switch(information.Value.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; - } - - switch(information.Value.BGFormatStatus) - { - 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(information.Value.Dbit) - sb.AppendLine("MRW is dirty"); - - sb.AppendFormat("First track on disc is track {0}", information.Value.FirstTrackNumber).AppendLine(); - sb.AppendFormat("Disc has {0} sessions", information.Value.Sessions).AppendLine(); - - sb.AppendFormat("First track in last session is track {0}", information.Value.FirstTrackLastSession). - AppendLine(); - - sb.AppendFormat("Last track in last session is track {0}", information.Value.LastTrackLastSession). - AppendLine(); - - sb.AppendFormat("Last session Lead-In address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}", - information.Value.LastSessionLeadInStartLBA, - (information.Value.LastSessionLeadInStartLBA & 0xFF0000) >> 16, - (information.Value.LastSessionLeadInStartLBA & 0xFF00) >> 8, - information.Value.LastSessionLeadInStartLBA & 0xFF).AppendLine(); - - sb.AppendFormat("Last possible Lead-Out address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}", - information.Value.LastPossibleLeadOutStartLBA, - (information.Value.LastPossibleLeadOutStartLBA & 0xFF0000) >> 16, - (information.Value.LastPossibleLeadOutStartLBA & 0xFF00) >> 8, - information.Value.LastPossibleLeadOutStartLBA & 0xFF).AppendLine(); - - sb.AppendLine(information.Value.URU ? "Disc is defined for unrestricted use" - : "Disc is defined for restricted use"); - - if(information.Value.DID_V) - sb.AppendFormat("Disc ID: {0:X6}", information.Value.DiscIdentification & 0x00FFFFFF).AppendLine(); - - if(information.Value.DBC_V) - sb.AppendFormat("Disc barcode: {0:X16}", information.Value.DiscBarcode).AppendLine(); - - if(information.Value.DAC_V) - sb.AppendFormat("Disc application code: {0}", information.Value.DiscApplicationCode).AppendLine(); - - if(information.Value.OPCTables == null) - return sb.ToString(); - - foreach(OPCTable table in information.Value.OPCTables) - sb.AppendFormat("OPC values for {0}Kbit/sec.: {1}, {2}, {3}, {4}, {5}, {6}", table.Speed, - table.OPCValues[0], table.OPCValues[1], table.OPCValues[2], table.OPCValues[3], - table.OPCValues[4], table.OPCValues[5]).AppendLine(); - - return sb.ToString(); - } - - public static TrackResourcesInformation? Decode001b(byte[] response) - { - if(response.Length != 12) - return null; - - if((response[2] & 0xE0) != 0x20) - return null; - - var decoded = new TrackResourcesInformation - { - DataLength = (ushort)((response[0] << 8) + response[1]) - }; - - if(decoded.DataLength + 2 != response.Length) - return null; - - decoded.DataType = (byte)((response[2] & 0xE0) >> 5); - decoded.MaxTracks = (ushort)((response[4] << 8) + response[5]); - decoded.AssignedTracks = (ushort)((response[6] << 8) + response[7]); - decoded.MaxAppendableTracks = (ushort)((response[8] << 8) + response[9]); - decoded.AppendableTracks = (ushort)((response[10] << 8) + response[11]); - - return decoded; - } - - public static string Prettify001b(TrackResourcesInformation? information) - { - if(information?.DataType != 1) - return null; - - var sb = new StringBuilder(); - - sb.AppendFormat("{0} maximum possible tracks on the disc", information.Value.MaxTracks).AppendLine(); - sb.AppendFormat("{0} assigned tracks on the disc", information.Value.AssignedTracks).AppendLine(); - - sb.AppendFormat("{0} maximum possible appendable tracks on the disc", information.Value.AppendableTracks). - AppendLine(); - - sb.AppendFormat("{0} current appendable tracks on the disc", information.Value.MaxAppendableTracks). - AppendLine(); - - return sb.ToString(); - } - - public static POWResourcesInformation? Decode010b(byte[] response) - { - if(response.Length != 16) - return null; - - if((response[2] & 0xE0) != 0x40) - return null; - - var decoded = new POWResourcesInformation - { - DataLength = (ushort)((response[0] << 8) + response[1]) - }; - - 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]); - - return decoded; - } - - public static string Prettify010b(POWResourcesInformation? information) - { - if(information?.DataType != 1) - return null; - - var sb = new StringBuilder(); - - sb.AppendFormat("{0} remaining POW replacements", information.Value.RemainingPOWReplacements).AppendLine(); - - sb.AppendFormat("{0} remaining POW reallocation map entries", information.Value.RemainingPOWReallocation). - AppendLine(); - - sb.AppendFormat("{0} remaining POW updates", information.Value.RemainingPOWUpdates).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify(byte[] response) - { - if(response == null) - return null; - - if(response.Length < 12) - return null; - - switch(response[2] & 0xE0) - { - case 0x00: return Prettify000b(Decode000b(response)); - case 0x20: return Prettify001b(Decode001b(response)); - case 0x40: return Prettify010b(Decode010b(response)); - } - + if(response.Length < 32) return null; + + if((response[2] & 0xE0) != 0) + return null; + + var decoded = new StandardDiscInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]) + }; + + if(decoded.DataLength + 2 != response.Length) + return null; + + decoded.DataType = (byte)((response[2] & 0xE0) >> 5); + decoded.Erasable |= (response[2] & 0x10) == 0x10; + decoded.LastSessionStatus = (byte)((response[2] & 0x0C) >> 2); + decoded.DiscStatus = (byte)(response[2] & 0x03); + decoded.FirstTrackNumber = response[3]; + decoded.Sessions = (ushort)((response[9] << 8) + response[4]); + decoded.FirstTrackLastSession = (ushort)((response[10] << 8) + response[5]); + decoded.LastTrackLastSession = (ushort)((response[11] << 8) + response[6]); + + decoded.DID_V |= (response[7] & 0x80) == 0x80; + decoded.DBC_V |= (response[7] & 0x40) == 0x40; + decoded.URU |= (response[7] & 0x20) == 0x20; + decoded.DAC_V |= (response[7] & 0x10) == 0x10; + decoded.Reserved |= (response[7] & 0x08) == 0x08; + decoded.Dbit |= (response[7] & 0x04) == 0x04; + decoded.BGFormatStatus = (byte)(response[7] & 0x03); + + 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]); + + byte[] temp = new byte[8]; + Array.Copy(response, 24, temp, 0, 8); + Array.Reverse(temp); + decoded.DiscBarcode = BitConverter.ToUInt64(temp, 0); + + if(response.Length < 34) + return null; + + decoded.DiscApplicationCode = response[32]; + decoded.OPCTablesNumber = response[33]; + + 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]); + + decoded.OPCTables[i].OPCValues = new byte[6]; + Array.Copy(response, 34 + (i * 8) + 2, decoded.OPCTables[i].OPCValues, 0, 6); } - public struct StandardDiscInformation + return decoded; + } + + public static string Prettify000b(StandardDiscInformation? information) + { + if(information?.DataType != 0) + return null; + + var sb = new StringBuilder(); + + switch(information.Value.DiscType) { - /// Bytes 0 to 1 32 + OPCTablesNumber*8 - public ushort DataLength; - /// Byte 2, bits 7 to 5 000b - public byte DataType; - /// Byte 2, bit 4 If set, disc is erasable - public bool Erasable; - /// Byte 2, bits 3 to 2 Status of last session - public byte LastSessionStatus; - /// Byte 2, bits 1 to 0 Status of disc - public byte DiscStatus; - /// Byte 3 Number of logical track that contains LBA 0 - public byte FirstTrackNumber; - /// Byte 9 (MSB) and byte 4 (LSB) Number of sessions - public ushort Sessions; - /// Byte 10 (MSB) and byte 5 (LSB) Number of first track in last session - public ushort FirstTrackLastSession; - /// Byte 11 (MSB) and byte 6 (LSB) Number of last track in last session - public ushort LastTrackLastSession; - /// Byte 7, bit 7 If set, DiscIdentification is valid - public bool DID_V; - /// Byte 7, bit 6 If set, DiscBarcode is valid - public bool DBC_V; - /// Byte 7, bit 5 If set, disc is unrestricted - public bool URU; - /// Byte 7, bit 4 If set DiscApplicationCode is valid - public bool DAC_V; - /// Byte 7, bit 3 Reserved - public bool Reserved; - /// Byte 7, bit 2 Copy of dirty bit from MRW status - public bool Dbit; - /// Byte 7, bits 1 to 0 Background format status - public byte BGFormatStatus; - /// Byte 8 Disc type code - public byte DiscType; - /// Bytes 12 to 15 Disc identification number from PMA - public uint DiscIdentification; - /// Bytes 16 to 19 Last Session Lead-in Start Address (MSF for CD, LBA for others) - public uint LastSessionLeadInStartLBA; - /// Bytes 20 to 23 Last Possible Lead-out Start Address (MSF for CD, LBA for others) - public uint LastPossibleLeadOutStartLBA; - /// Bytes 24 to 31 Disc barcode - public ulong DiscBarcode; - /// Byte 32 Disc application code - public byte DiscApplicationCode; - /// Byte 33 How many OPC tables are - public byte OPCTablesNumber; - /// Bytes 34 to end OPC tables (8 bytes each) - public OPCTable[] OPCTables; + 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", information.Value.DiscType).AppendLine(); + + break; } - public struct OPCTable + switch(information.Value.DiscStatus) { - /// Bytes 0 to 1 kilobytes/sec this OPC table applies to - public ushort Speed; - /// Bytes 2 to 7 OPC values - public byte[] OPCValues; + case 0: + sb.AppendLine("Disc is empty"); + + break; + case 1: + sb.AppendLine("Disc is incomplete"); + + break; + case 2: + sb.AppendLine("Disc is finalized"); + + break; } - public struct TrackResourcesInformation + if(information.Value.Erasable) + sb.AppendLine("Disc is erasable"); + + switch(information.Value.LastSessionStatus) { - /// Bytes 0 to 1 10 - public ushort DataLength; - /// Byte 2, bits 7 to 5 001b - public byte DataType; - /// Byte 2, bits 4 to 0 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 5 Maximum possible number of the tracks on the disc - public ushort MaxTracks; - /// Bytes 6 to 7 Number of the assigned tracks on the disc - public ushort AssignedTracks; - /// Bytes 8 to 9 Maximum possible number of appendable tracks on the disc - public ushort MaxAppendableTracks; - /// Bytes 10 to 11 Current number of appendable tracks on the disc - public ushort AppendableTracks; + 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; } - public struct POWResourcesInformation + switch(information.Value.BGFormatStatus) { - /// Bytes 0 to 1 14 - public ushort DataLength; - /// Byte 2, bits 7 to 5 010b - public byte DataType; - /// Byte 2, bits 4 to 0 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Bytes 4 to 7 Remaining POW replacements - public uint RemainingPOWReplacements; - /// Bytes 8 to 11 Remaining POW reallocation map entries - public uint RemainingPOWReallocation; - /// Bytes 12 to 15 Number of remaining POW updates - public uint RemainingPOWUpdates; + 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(information.Value.Dbit) + sb.AppendLine("MRW is dirty"); + + sb.AppendFormat("First track on disc is track {0}", information.Value.FirstTrackNumber).AppendLine(); + sb.AppendFormat("Disc has {0} sessions", information.Value.Sessions).AppendLine(); + + sb.AppendFormat("First track in last session is track {0}", information.Value.FirstTrackLastSession). + AppendLine(); + + sb.AppendFormat("Last track in last session is track {0}", information.Value.LastTrackLastSession). + AppendLine(); + + sb.AppendFormat("Last session Lead-In address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}", + information.Value.LastSessionLeadInStartLBA, + (information.Value.LastSessionLeadInStartLBA & 0xFF0000) >> 16, + (information.Value.LastSessionLeadInStartLBA & 0xFF00) >> 8, + information.Value.LastSessionLeadInStartLBA & 0xFF).AppendLine(); + + sb.AppendFormat("Last possible Lead-Out address is {0} (as LBA) or {1:X2}:{2:X2}:{3:X2}", + information.Value.LastPossibleLeadOutStartLBA, + (information.Value.LastPossibleLeadOutStartLBA & 0xFF0000) >> 16, + (information.Value.LastPossibleLeadOutStartLBA & 0xFF00) >> 8, + information.Value.LastPossibleLeadOutStartLBA & 0xFF).AppendLine(); + + sb.AppendLine(information.Value.URU ? "Disc is defined for unrestricted use" + : "Disc is defined for restricted use"); + + if(information.Value.DID_V) + sb.AppendFormat("Disc ID: {0:X6}", information.Value.DiscIdentification & 0x00FFFFFF).AppendLine(); + + if(information.Value.DBC_V) + sb.AppendFormat("Disc barcode: {0:X16}", information.Value.DiscBarcode).AppendLine(); + + if(information.Value.DAC_V) + sb.AppendFormat("Disc application code: {0}", information.Value.DiscApplicationCode).AppendLine(); + + if(information.Value.OPCTables == null) + return sb.ToString(); + + foreach(OPCTable table in information.Value.OPCTables) + sb.AppendFormat("OPC values for {0}Kbit/sec.: {1}, {2}, {3}, {4}, {5}, {6}", table.Speed, + table.OPCValues[0], table.OPCValues[1], table.OPCValues[2], table.OPCValues[3], + table.OPCValues[4], table.OPCValues[5]).AppendLine(); + + return sb.ToString(); + } + + public static TrackResourcesInformation? Decode001b(byte[] response) + { + if(response.Length != 12) + return null; + + if((response[2] & 0xE0) != 0x20) + return null; + + var decoded = new TrackResourcesInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]) + }; + + if(decoded.DataLength + 2 != response.Length) + return null; + + decoded.DataType = (byte)((response[2] & 0xE0) >> 5); + decoded.MaxTracks = (ushort)((response[4] << 8) + response[5]); + decoded.AssignedTracks = (ushort)((response[6] << 8) + response[7]); + decoded.MaxAppendableTracks = (ushort)((response[8] << 8) + response[9]); + decoded.AppendableTracks = (ushort)((response[10] << 8) + response[11]); + + return decoded; + } + + public static string Prettify001b(TrackResourcesInformation? information) + { + if(information?.DataType != 1) + return null; + + var sb = new StringBuilder(); + + sb.AppendFormat("{0} maximum possible tracks on the disc", information.Value.MaxTracks).AppendLine(); + sb.AppendFormat("{0} assigned tracks on the disc", information.Value.AssignedTracks).AppendLine(); + + sb.AppendFormat("{0} maximum possible appendable tracks on the disc", information.Value.AppendableTracks). + AppendLine(); + + sb.AppendFormat("{0} current appendable tracks on the disc", information.Value.MaxAppendableTracks). + AppendLine(); + + return sb.ToString(); + } + + public static POWResourcesInformation? Decode010b(byte[] response) + { + if(response.Length != 16) + return null; + + if((response[2] & 0xE0) != 0x40) + return null; + + var decoded = new POWResourcesInformation + { + DataLength = (ushort)((response[0] << 8) + response[1]) + }; + + 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]); + + return decoded; + } + + public static string Prettify010b(POWResourcesInformation? information) + { + if(information?.DataType != 1) + return null; + + var sb = new StringBuilder(); + + sb.AppendFormat("{0} remaining POW replacements", information.Value.RemainingPOWReplacements).AppendLine(); + + sb.AppendFormat("{0} remaining POW reallocation map entries", information.Value.RemainingPOWReallocation). + AppendLine(); + + sb.AppendFormat("{0} remaining POW updates", information.Value.RemainingPOWUpdates).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify(byte[] response) + { + if(response == null) + return null; + + if(response.Length < 12) + return null; + + switch(response[2] & 0xE0) + { + case 0x00: return Prettify000b(Decode000b(response)); + case 0x20: return Prettify001b(Decode001b(response)); + case 0x40: return Prettify010b(Decode010b(response)); + } + + return null; + } + + public struct StandardDiscInformation + { + /// Bytes 0 to 1 32 + OPCTablesNumber*8 + public ushort DataLength; + /// Byte 2, bits 7 to 5 000b + public byte DataType; + /// Byte 2, bit 4 If set, disc is erasable + public bool Erasable; + /// Byte 2, bits 3 to 2 Status of last session + public byte LastSessionStatus; + /// Byte 2, bits 1 to 0 Status of disc + public byte DiscStatus; + /// Byte 3 Number of logical track that contains LBA 0 + public byte FirstTrackNumber; + /// Byte 9 (MSB) and byte 4 (LSB) Number of sessions + public ushort Sessions; + /// Byte 10 (MSB) and byte 5 (LSB) Number of first track in last session + public ushort FirstTrackLastSession; + /// Byte 11 (MSB) and byte 6 (LSB) Number of last track in last session + public ushort LastTrackLastSession; + /// Byte 7, bit 7 If set, DiscIdentification is valid + public bool DID_V; + /// Byte 7, bit 6 If set, DiscBarcode is valid + public bool DBC_V; + /// Byte 7, bit 5 If set, disc is unrestricted + public bool URU; + /// Byte 7, bit 4 If set DiscApplicationCode is valid + public bool DAC_V; + /// Byte 7, bit 3 Reserved + public bool Reserved; + /// Byte 7, bit 2 Copy of dirty bit from MRW status + public bool Dbit; + /// Byte 7, bits 1 to 0 Background format status + public byte BGFormatStatus; + /// Byte 8 Disc type code + public byte DiscType; + /// Bytes 12 to 15 Disc identification number from PMA + public uint DiscIdentification; + /// Bytes 16 to 19 Last Session Lead-in Start Address (MSF for CD, LBA for others) + public uint LastSessionLeadInStartLBA; + /// Bytes 20 to 23 Last Possible Lead-out Start Address (MSF for CD, LBA for others) + public uint LastPossibleLeadOutStartLBA; + /// Bytes 24 to 31 Disc barcode + public ulong DiscBarcode; + /// Byte 32 Disc application code + public byte DiscApplicationCode; + /// Byte 33 How many OPC tables are + public byte OPCTablesNumber; + /// Bytes 34 to end OPC tables (8 bytes each) + public OPCTable[] OPCTables; + } + + public struct OPCTable + { + /// Bytes 0 to 1 kilobytes/sec this OPC table applies to + public ushort Speed; + /// Bytes 2 to 7 OPC values + public byte[] OPCValues; + } + + public struct TrackResourcesInformation + { + /// Bytes 0 to 1 10 + public ushort DataLength; + /// Byte 2, bits 7 to 5 001b + public byte DataType; + /// Byte 2, bits 4 to 0 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 5 Maximum possible number of the tracks on the disc + public ushort MaxTracks; + /// Bytes 6 to 7 Number of the assigned tracks on the disc + public ushort AssignedTracks; + /// Bytes 8 to 9 Maximum possible number of appendable tracks on the disc + public ushort MaxAppendableTracks; + /// Bytes 10 to 11 Current number of appendable tracks on the disc + public ushort AppendableTracks; + } + + public struct POWResourcesInformation + { + /// Bytes 0 to 1 14 + public ushort DataLength; + /// Byte 2, bits 7 to 5 010b + public byte DataType; + /// Byte 2, bits 4 to 0 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Bytes 4 to 7 Remaining POW replacements + public uint RemainingPOWReplacements; + /// Bytes 8 to 11 Remaining POW reallocation map entries + public uint RemainingPOWReallocation; + /// Bytes 12 to 15 Number of remaining POW updates + public uint RemainingPOWUpdates; } } \ No newline at end of file diff --git a/SCSI/MMC/Enums.cs b/SCSI/MMC/Enums.cs index 24126c2..0ffa0a6 100644 --- a/SCSI/MMC/Enums.cs +++ b/SCSI/MMC/Enums.cs @@ -32,46 +32,45 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] +public enum FormatLayerTypeCodes : ushort { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] - public enum FormatLayerTypeCodes : ushort - { - CDLayer = 0x0008, DVDLayer = 0x0010, BDLayer = 0x0040, - HDDVDLayer = 0x0050 - } + CDLayer = 0x0008, DVDLayer = 0x0010, BDLayer = 0x0040, + HDDVDLayer = 0x0050 +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] - public enum SessionStatusCodes : byte - { - Empty = 0x00, Incomplete = 0x01, ReservedOrDamaged = 0x02, - Complete = 0x03 - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] +public enum SessionStatusCodes : byte +{ + Empty = 0x00, Incomplete = 0x01, ReservedOrDamaged = 0x02, + Complete = 0x03 +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] - public enum DiscStatusCodes : byte - { - Empty = 0x00, Incomplete = 0x01, Finalized = 0x02, - Others = 0x03 - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] +public enum DiscStatusCodes : byte +{ + Empty = 0x00, Incomplete = 0x01, Finalized = 0x02, + Others = 0x03 +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] - public enum BGFormatStatusCodes : byte - { - NoFormattable = 0x00, IncompleteBackgroundFormat = 0x01, BackgroundFormatInProgress = 0x02, - FormatComplete = 0x03 - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] +public enum BGFormatStatusCodes : byte +{ + NoFormattable = 0x00, IncompleteBackgroundFormat = 0x01, BackgroundFormatInProgress = 0x02, + FormatComplete = 0x03 +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] - public enum DiscTypeCodes : byte - { - /// Also valid for CD-DA, DVD and BD - CDROM = 0x00, CDi = 0x10, CDROMXA = 0x20, Undefined = 0xFF - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal")] +public enum DiscTypeCodes : byte +{ + /// Also valid for CD-DA, DVD and BD + CDROM = 0x00, CDi = 0x10, CDROMXA = 0x20, Undefined = 0xFF +} - public enum LayerJumpRecordingStatus : byte - { - Incremental = 0, Unspecified = 1, Manual = 2, - RegularInterval = 3 - } +public enum LayerJumpRecordingStatus : byte +{ + Incremental = 0, Unspecified = 1, Manual = 2, + RegularInterval = 3 } \ No newline at end of file diff --git a/SCSI/MMC/Features.cs b/SCSI/MMC/Features.cs index 1b5bc58..5be965e 100644 --- a/SCSI/MMC/Features.cs +++ b/SCSI/MMC/Features.cs @@ -39,3874 +39,3529 @@ using Aaru.Helpers; // ReSharper disable MemberCanBePrivate.Global -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +/// MMC Feature enumeration +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum FeatureNumber : ushort { - /// MMC Feature enumeration - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum FeatureNumber : ushort - { - /// Lists all profiles - ProfileList = 0x0000, - /// Mandatory behaviour - Core = 0x0001, - /// Operational changes - Morphing = 0x0002, - /// Removable medium - Removable = 0x0003, - /// Ability to control write protection status - WriteProtect = 0x0004, - /// Ability to read sectors with random addressing - RandomRead = 0x0010, - /// Reads on OSTA Multi-Read - MultiRead = 0x001D, - /// Able to read CD structures - CDRead = 0x001E, - /// Able to read DVD structures - DVDRead = 0x001F, - /// Ability to write sectors with random addressing - RandomWrite = 0x0020, - /// Ability to sequentially write - IncrementalWrite = 0x0021, - /// Support for media that requires erase before write - SectorErasable = 0x0022, - /// Supports formatting media - Formattable = 0x0023, - /// Ability to provide defect-free space - HardwareDefectMgmt = 0x0024, - /// Supports for write-once media in random order - WriteOnce = 0x0025, - /// Supports for media that shall be written from blocking boundaries - RestrictedOverwrite = 0x0026, - /// Supports high speed CD-RW - CDRWCAV = 0x0027, - /// Read and optionally write MRW - MRW = 0x0028, - /// Ability to control RECOVERED ERROR reporting - EnDefectReport = 0x0029, - /// Ability to recognize, read and optionally write DVD+RW - DVDRWPlus = 0x002A, - /// Ability to read DVD+R - DVDRPlus = 0x002B, RigidOverWrite = 0x002C, - /// Ability to write CD in Track-at-Once - CDTAO = 0x002D, - /// Ability to write CD in Session-at-Once or RAW - CDMastering = 0x002E, - /// Ability to write DVD structures - DVDRWrite = 0x002F, - /// Ability to read DDCD - DDCD = 0x0030, - /// Ability to write DDCD-R - DDCDR = 0x0031, - /// Ability to write DDCD-RW - DDCDRW = 0x0032, - /// Ability to record in layer jump mode - LayerJump = 0x0033, - /// Ability to perform Layer Jump recording on Rigid Restricted Overwrite - LJRigid = 0x0034, - /// Ability to stop the long immediate operation - StopLong = 0x0035, - /// Ability to report CD-RW media sub-types supported for write - CDRWMediaWrite = 0x0037, - /// Logical block overwrite service on BD-R formatted as SRM+POW - BDRPOW = 0x0038, - /// Ability to read DVD+RW DL - DVDRWDLPlus = 0x003A, - /// Ability to read DVD+R DL - DVDRDLPlus = 0x003B, - /// Ability to read BD discs - BDRead = 0x0040, - /// Ability to write BD discs - BDWrite = 0x0041, - /// Timely, Safe Recording - TSR = 0x0042, - /// Ability to read HD DVD - HDDVDRead = 0x0050, - /// Ability to write HD DVD - HDDVDWrite = 0x0051, - /// Ability to write HD DVD-RW fragmented - HDDVDRWFragment = 0x0052, - /// Supports some Hybrid Discs - Hybrid = 0x0080, - /// Host and device directed power management - PowerMgmt = 0x0100, - /// Supports S.M.A.R.T. - SMART = 0x0101, - /// Single machanism multiple disc changer - Changer = 0x0102, - /// Ability to play CD audio to an analogue output - CDAudioExt = 0x0103, - /// Ability to accept new microcode - MicrocodeUpgrade = 0x0104, - /// Ability to respond to all commands within a specific time - Timeout = 0x0105, - /// Supports DVD CSS/CPPM - CSS = 0x0106, - /// Ability to read and write using host requested performance parameters - RTS = 0x0107, - /// Drive has a unique identifier - DriveSerial = 0x0108, - /// Ability to return unique Media Serial Number - MediaSerial = 0x0109, - /// Ability to read and/or write DCBs - DCBs = 0x010A, - /// Supports DVD CPRM - CPRM = 0x010B, - /// Firmware creation date report - FirmwareInfo = 0x010C, - /// Ability to decode and optionally encode AACS - AACS = 0x010D, - /// Ability to perform DVD CSS managed recording - CSSManagedRec = 0x010E, - /// Ability to decode and optionally encode VCPS - VCPS = 0x0110, - /// Supports SecurDisc - SecurDisc = 0x0113, - /// TCG Optical Security Subsystem Class - OSSC = 0x0142 - } + /// Lists all profiles + ProfileList = 0x0000, + /// Mandatory behaviour + Core = 0x0001, + /// Operational changes + Morphing = 0x0002, + /// Removable medium + Removable = 0x0003, + /// Ability to control write protection status + WriteProtect = 0x0004, + /// Ability to read sectors with random addressing + RandomRead = 0x0010, + /// Reads on OSTA Multi-Read + MultiRead = 0x001D, + /// Able to read CD structures + CDRead = 0x001E, + /// Able to read DVD structures + DVDRead = 0x001F, + /// Ability to write sectors with random addressing + RandomWrite = 0x0020, + /// Ability to sequentially write + IncrementalWrite = 0x0021, + /// Support for media that requires erase before write + SectorErasable = 0x0022, + /// Supports formatting media + Formattable = 0x0023, + /// Ability to provide defect-free space + HardwareDefectMgmt = 0x0024, + /// Supports for write-once media in random order + WriteOnce = 0x0025, + /// Supports for media that shall be written from blocking boundaries + RestrictedOverwrite = 0x0026, + /// Supports high speed CD-RW + CDRWCAV = 0x0027, + /// Read and optionally write MRW + MRW = 0x0028, + /// Ability to control RECOVERED ERROR reporting + EnDefectReport = 0x0029, + /// Ability to recognize, read and optionally write DVD+RW + DVDRWPlus = 0x002A, + /// Ability to read DVD+R + DVDRPlus = 0x002B, RigidOverWrite = 0x002C, + /// Ability to write CD in Track-at-Once + CDTAO = 0x002D, + /// Ability to write CD in Session-at-Once or RAW + CDMastering = 0x002E, + /// Ability to write DVD structures + DVDRWrite = 0x002F, + /// Ability to read DDCD + DDCD = 0x0030, + /// Ability to write DDCD-R + DDCDR = 0x0031, + /// Ability to write DDCD-RW + DDCDRW = 0x0032, + /// Ability to record in layer jump mode + LayerJump = 0x0033, + /// Ability to perform Layer Jump recording on Rigid Restricted Overwrite + LJRigid = 0x0034, + /// Ability to stop the long immediate operation + StopLong = 0x0035, + /// Ability to report CD-RW media sub-types supported for write + CDRWMediaWrite = 0x0037, + /// Logical block overwrite service on BD-R formatted as SRM+POW + BDRPOW = 0x0038, + /// Ability to read DVD+RW DL + DVDRWDLPlus = 0x003A, + /// Ability to read DVD+R DL + DVDRDLPlus = 0x003B, + /// Ability to read BD discs + BDRead = 0x0040, + /// Ability to write BD discs + BDWrite = 0x0041, + /// Timely, Safe Recording + TSR = 0x0042, + /// Ability to read HD DVD + HDDVDRead = 0x0050, + /// Ability to write HD DVD + HDDVDWrite = 0x0051, + /// Ability to write HD DVD-RW fragmented + HDDVDRWFragment = 0x0052, + /// Supports some Hybrid Discs + Hybrid = 0x0080, + /// Host and device directed power management + PowerMgmt = 0x0100, + /// Supports S.M.A.R.T. + SMART = 0x0101, + /// Single machanism multiple disc changer + Changer = 0x0102, + /// Ability to play CD audio to an analogue output + CDAudioExt = 0x0103, + /// Ability to accept new microcode + MicrocodeUpgrade = 0x0104, + /// Ability to respond to all commands within a specific time + Timeout = 0x0105, + /// Supports DVD CSS/CPPM + CSS = 0x0106, + /// Ability to read and write using host requested performance parameters + RTS = 0x0107, + /// Drive has a unique identifier + DriveSerial = 0x0108, + /// Ability to return unique Media Serial Number + MediaSerial = 0x0109, + /// Ability to read and/or write DCBs + DCBs = 0x010A, + /// Supports DVD CPRM + CPRM = 0x010B, + /// Firmware creation date report + FirmwareInfo = 0x010C, + /// Ability to decode and optionally encode AACS + AACS = 0x010D, + /// Ability to perform DVD CSS managed recording + CSSManagedRec = 0x010E, + /// Ability to decode and optionally encode VCPS + VCPS = 0x0110, + /// Supports SecurDisc + SecurDisc = 0x0113, + /// TCG Optical Security Subsystem Class + OSSC = 0x0142 +} - /// MMC Profile enumeration - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ProfileNumber : ushort - { - /// Not to use - Reserved = 0x0000, - /// Non-removable disk profile - NonRemovable = 0x0001, - /// Rewritable with removable media - Removable = 0x0002, - /// Magneto-Optical with sector erase - MOErasable = 0x0003, - /// Optical write once - OpticalWORM = 0x0004, - /// Advance Storage - Magneto-Optical - ASMO = 0x0005, - /// Read-only Compact Disc - CDROM = 0x0008, - /// Write-once Compact Disc - CDR = 0x0009, - /// Re-writable Compact Disc - CDRW = 0x000A, - /// Read-only DVD - DVDROM = 0x0010, - /// Write-once sequentially recorded DVD-R - DVDRSeq = 0x0011, - /// DVD-RAM - DVDRAM = 0x0012, - /// Restricted overwrite DVD-RW - DVDRWRes = 0x0013, - /// Sequential recording DVD-RW - DVDRWSeq = 0x0014, - /// Sequential recording DVD-R DL - DVDRDLSeq = 0x0015, - /// Layer jump recording DVD-R DL - DVDRDLJump = 0x0016, - /// DVD-RW DL - DVDRWDL = 0x0017, - /// DVD-Download - DVDDownload = 0x0018, - /// DVD+RW - DVDRWPlus = 0x001A, - /// DVD+R - DVDRPlus = 0x001B, - /// DDCD-ROM - DDCDROM = 0x0020, - /// DDCD-R - DDCDR = 0x0021, - /// DDCD-RW - DDCDRW = 0x0022, - /// DVD+RW DL - DVDRWDLPlus = 0x002A, - /// DVD+R DL - DVDRDLPlus = 0x002B, - /// BD-ROM - BDROM = 0x0040, - /// BD-R SRM - BDRSeq = 0x0041, - /// BD-R RRM - BDRRdm = 0x0042, - /// BD-RE - BDRE = 0x0043, - /// HD DVD-ROM - HDDVDROM = 0x0050, - /// HD DVD-R - HDDVDR = 0x0051, - /// HD DVD-RAM - HDDVDRAM = 0x0052, - /// HD DVD-RW - HDDVDRW = 0x0053, - /// HD DVD-R DL - HDDVDRDL = 0x0058, - /// HD DVD-RW DL - HDDVDRWDL = 0x005A, - /// HDBurn CD-ROM - HDBURNROM = 0x0080, - /// HDBurn CD-R - HDBURNR = 0x0081, - /// HDBurn CD-RW - HDBURNRW = 0x0082, - /// Drive does not conform to any profiles - Unconforming = 0xFFFF - } +/// MMC Profile enumeration +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum ProfileNumber : ushort +{ + /// Not to use + Reserved = 0x0000, + /// Non-removable disk profile + NonRemovable = 0x0001, + /// Rewritable with removable media + Removable = 0x0002, + /// Magneto-Optical with sector erase + MOErasable = 0x0003, + /// Optical write once + OpticalWORM = 0x0004, + /// Advance Storage - Magneto-Optical + ASMO = 0x0005, + /// Read-only Compact Disc + CDROM = 0x0008, + /// Write-once Compact Disc + CDR = 0x0009, + /// Re-writable Compact Disc + CDRW = 0x000A, + /// Read-only DVD + DVDROM = 0x0010, + /// Write-once sequentially recorded DVD-R + DVDRSeq = 0x0011, + /// DVD-RAM + DVDRAM = 0x0012, + /// Restricted overwrite DVD-RW + DVDRWRes = 0x0013, + /// Sequential recording DVD-RW + DVDRWSeq = 0x0014, + /// Sequential recording DVD-R DL + DVDRDLSeq = 0x0015, + /// Layer jump recording DVD-R DL + DVDRDLJump = 0x0016, + /// DVD-RW DL + DVDRWDL = 0x0017, + /// DVD-Download + DVDDownload = 0x0018, + /// DVD+RW + DVDRWPlus = 0x001A, + /// DVD+R + DVDRPlus = 0x001B, + /// DDCD-ROM + DDCDROM = 0x0020, + /// DDCD-R + DDCDR = 0x0021, + /// DDCD-RW + DDCDRW = 0x0022, + /// DVD+RW DL + DVDRWDLPlus = 0x002A, + /// DVD+R DL + DVDRDLPlus = 0x002B, + /// BD-ROM + BDROM = 0x0040, + /// BD-R SRM + BDRSeq = 0x0041, + /// BD-R RRM + BDRRdm = 0x0042, + /// BD-RE + BDRE = 0x0043, + /// HD DVD-ROM + HDDVDROM = 0x0050, + /// HD DVD-R + HDDVDR = 0x0051, + /// HD DVD-RAM + HDDVDRAM = 0x0052, + /// HD DVD-RW + HDDVDRW = 0x0053, + /// HD DVD-R DL + HDDVDRDL = 0x0058, + /// HD DVD-RW DL + HDDVDRWDL = 0x005A, + /// HDBurn CD-ROM + HDBURNROM = 0x0080, + /// HDBurn CD-R + HDBURNR = 0x0081, + /// HDBurn CD-RW + HDBURNRW = 0x0082, + /// Drive does not conform to any profiles + Unconforming = 0xFFFF +} - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Profile - { - public ProfileNumber Number; - public bool Current; - } +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Profile +{ + public ProfileNumber Number; + public bool Current; +} - /// Profile List Feature (0000h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0000 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// All supported profiles - public Profile[] Profiles; - } +/// Profile List Feature (0000h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0000 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// All supported profiles + public Profile[] Profiles; +} - /// Core Feature (0001h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0001 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Currently in-use physical interface standard - public PhysicalInterfaces PhysicalInterfaceStandard; - /// Supports EVPD, Page Code and 16-bit Allocation Length as defined in SPC-3 - public bool INQ2; - /// Supports Device Busy Event - public bool DBE; - } +/// Core Feature (0001h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0001 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Currently in-use physical interface standard + public PhysicalInterfaces PhysicalInterfaceStandard; + /// Supports EVPD, Page Code and 16-bit Allocation Length as defined in SPC-3 + public bool INQ2; + /// Supports Device Busy Event + public bool DBE; +} - /// Morphing Feature (0002h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0002 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports Operational Change Request/Nofitication Class Events of GET EVENT/STATUS NOTIFICATION - public bool OCEvent; - /// Supports asynchronous GET EVENT/STATUS NOTIFICATION - public bool Async; - } +/// Morphing Feature (0002h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0002 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports Operational Change Request/Nofitication Class Events of GET EVENT/STATUS NOTIFICATION + public bool OCEvent; + /// Supports asynchronous GET EVENT/STATUS NOTIFICATION + public bool Async; +} - /// Removable Medium Feature (0003h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0003 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Mechanism type - public byte LoadingMechanismType; - /// Drive is able to load the medium - public bool Load; - /// Device can eject medium - public bool Eject; - /// Device starts in medium ejection/insertion allow - public bool PreventJumper; - /// Reports Device Busy Class events during medium loading/unloading - public bool DBML; - /// Medium is currently locked - public bool Lock; - } +/// Removable Medium Feature (0003h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0003 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Mechanism type + public byte LoadingMechanismType; + /// Drive is able to load the medium + public bool Load; + /// Device can eject medium + public bool Eject; + /// Device starts in medium ejection/insertion allow + public bool PreventJumper; + /// Reports Device Busy Class events during medium loading/unloading + public bool DBML; + /// Medium is currently locked + public bool Lock; +} - /// Write Protect Feature (0004h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0004 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Drive can read/write Disc Write Protect PAC on BD-R/-RE media - public bool DWP; - /// Supports reading/writing Write Inhibit DCB on DVD+RW media. - public bool WDCB; - /// Supports PWP status - public bool SPWP; - /// Supports SWPP bit of mode page 1Dh - public bool SSWPP; - } +/// Write Protect Feature (0004h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0004 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Drive can read/write Disc Write Protect PAC on BD-R/-RE media + public bool DWP; + /// Supports reading/writing Write Inhibit DCB on DVD+RW media. + public bool WDCB; + /// Supports PWP status + public bool SPWP; + /// Supports SWPP bit of mode page 1Dh + public bool SSWPP; +} - /// Random Readable Feature (0010h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0010 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Bytes per logical block - public uint LogicalBlockSize; - /// Number of logical blocks per device readable unit - public ushort Blocking; - /// Read/Write Error Recovery page is present - public bool PP; - } +/// Random Readable Feature (0010h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0010 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bytes per logical block + public uint LogicalBlockSize; + /// Number of logical blocks per device readable unit + public ushort Blocking; + /// Read/Write Error Recovery page is present + public bool PP; +} - /// Multi-Read Feature (001Dh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_001D - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// Multi-Read Feature (001Dh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_001D +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// CD Read Feature (001Eh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_001E - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports DAP bit in READ CD and READ CD MSF - public bool DAP; - /// Supports C2 Error Pointers - public bool C2; - /// Can read CD-Text with READ TOC/PMA/ATIP - public bool CDText; - } +/// CD Read Feature (001Eh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_001E +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports DAP bit in READ CD and READ CD MSF + public bool DAP; + /// Supports C2 Error Pointers + public bool C2; + /// Can read CD-Text with READ TOC/PMA/ATIP + public bool CDText; +} - /// DVD Read Feature (001Fh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_001F - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Compliant with DVD Multi Drive Read-only specifications - public bool MULTI110; - /// Supports reading all DVD-RW DL - public bool DualRW; - /// Supports reading all DVD-R DL including remapping - public bool DualR; - } +/// DVD Read Feature (001Fh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_001F +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Compliant with DVD Multi Drive Read-only specifications + public bool MULTI110; + /// Supports reading all DVD-RW DL + public bool DualRW; + /// Supports reading all DVD-R DL including remapping + public bool DualR; +} - /// Random Writable Feature (0020h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0020 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Last logical block address - public uint LastLBA; - /// Bytes per logical block - public uint LogicalBlockSize; - /// Number of logical blocks per device readable unit - public ushort Blocking; - /// Read/Write Error Recovery page is present - public bool PP; - } +/// Random Writable Feature (0020h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0020 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Last logical block address + public uint LastLBA; + /// Bytes per logical block + public uint LogicalBlockSize; + /// Number of logical blocks per device readable unit + public ushort Blocking; + /// Read/Write Error Recovery page is present + public bool PP; +} - /// Incremental Streaming Writable Feature (0021h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0021 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Bitmask of supported data types - public ushort DataTypeSupported; - /// Can report Track Resources Information of READ DISC INFORMATION - public bool TRIO; - /// Supports Address Mode in RESERVE TRACK - public bool ARSV; - /// Zero loss linking - public bool BUF; - /// Logical blocks per link - public byte[] LinkSizes; - } +/// Incremental Streaming Writable Feature (0021h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0021 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bitmask of supported data types + public ushort DataTypeSupported; + /// Can report Track Resources Information of READ DISC INFORMATION + public bool TRIO; + /// Supports Address Mode in RESERVE TRACK + public bool ARSV; + /// Zero loss linking + public bool BUF; + /// Logical blocks per link + public byte[] LinkSizes; +} - /// Sector Erasable Feature (0022h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0022 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// Sector Erasable Feature (0022h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0022 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// Formattable Feature (0023h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0023 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports formatting BD-RE without spare area - public bool RENoSA; - /// Supports expansion of the spare area on BD-RE - public bool Expand; - /// Supports FORMAT type 30h sub-type 11b - public bool QCert; - /// Supports FORMAT type 30h sub-type 10b - public bool Cert; - /// Supports FORMAT type 18h - public bool FRF; - /// Supports FORMAT type 00h/32h sub-type 10b on BD-R - public bool RRM; - } +/// Formattable Feature (0023h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0023 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports formatting BD-RE without spare area + public bool RENoSA; + /// Supports expansion of the spare area on BD-RE + public bool Expand; + /// Supports FORMAT type 30h sub-type 11b + public bool QCert; + /// Supports FORMAT type 30h sub-type 10b + public bool Cert; + /// Supports FORMAT type 18h + public bool FRF; + /// Supports FORMAT type 00h/32h sub-type 10b on BD-R + public bool RRM; +} - /// Hardware Defect Management Feature (0024h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0024 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports READ DISC STRUCTURE with Format Code 0Ah (Spare Area Information) - public bool SSA; - } +/// Hardware Defect Management Feature (0024h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0024 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports READ DISC STRUCTURE with Format Code 0Ah (Spare Area Information) + public bool SSA; +} - /// Write Once Feature (0025h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0025 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Bytes per logical block - public uint LogicalBlockSize; - /// Number of logical blocks per device readable unit - public ushort Blocking; - /// Read/Write Error Recovery page is present - public bool PP; - } +/// Write Once Feature (0025h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0025 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bytes per logical block + public uint LogicalBlockSize; + /// Number of logical blocks per device readable unit + public ushort Blocking; + /// Read/Write Error Recovery page is present + public bool PP; +} - /// Restricted Overwrite Feature (0026h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0026 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// Restricted Overwrite Feature (0026h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0026 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// CD-RW CAV Write Feature (0027h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0027 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// CD-RW CAV Write Feature (0027h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0027 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// MRW Feature (0028h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0028 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can read DVD+MRW discs - public bool DVDPRead; - /// Can write DVD+MRW discs - public bool DVDPWrite; - /// Can format and write to CD-MRW discs - public bool Write; - } +/// MRW Feature (0028h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0028 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can read DVD+MRW discs + public bool DVDPRead; + /// Can write DVD+MRW discs + public bool DVDPWrite; + /// Can format and write to CD-MRW discs + public bool Write; +} - /// Enhanced Defect Reporting Feature (0029h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0029 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports DRT-DM - public bool DRTDM; - /// Maximum number of DBI cache zones device can handle separately - public byte DBICacheZones; - /// Number of entries in worst case to case DBI overflow - public ushort Entries; - } +/// Enhanced Defect Reporting Feature (0029h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0029 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports DRT-DM + public bool DRTDM; + /// Maximum number of DBI cache zones device can handle separately + public byte DBICacheZones; + /// Number of entries in worst case to case DBI overflow + public ushort Entries; +} - /// DVD+RW Feature (002Ah) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_002A - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can format DVD+RW discs - public bool Write; - /// FORMAT UNIT supports quick start formatting - public bool QuickStart; - /// Drive only supports read compatibility stop - public bool CloseOnly; - } +/// DVD+RW Feature (002Ah) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_002A +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can format DVD+RW discs + public bool Write; + /// FORMAT UNIT supports quick start formatting + public bool QuickStart; + /// Drive only supports read compatibility stop + public bool CloseOnly; +} - /// DVD+R Feature (002Bh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_002B - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can write DVD+R - public bool Write; - } +/// DVD+R Feature (002Bh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_002B +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can write DVD+R + public bool Write; +} - /// Rigid Restricted Overwrite Feature (002Ch) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_002C - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can generate Defect Status Data during formatting - public bool DSDG; - /// Can read Defect Status Data recorded on medium - public bool DSDR; - /// Supports writing on an intermediate state Session and quick formatting - public bool Intermediate; - /// Supports BLANK command types 00h and 01h - public bool Blank; - } +/// Rigid Restricted Overwrite Feature (002Ch) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_002C +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can generate Defect Status Data during formatting + public bool DSDG; + /// Can read Defect Status Data recorded on medium + public bool DSDR; + /// Supports writing on an intermediate state Session and quick formatting + public bool Intermediate; + /// Supports BLANK command types 00h and 01h + public bool Blank; +} - /// CD Track at Once Feature (002Dh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_002D - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports zero loss linking - public bool BUF; - /// Supports writing R-W subchannels in raw mode - public bool RWRaw; - /// Supports writing R-W subchannels in packed mode - public bool RWPack; - /// Can perform test writes - public bool TestWrite; - /// Supports overwriting a TAO track with another - public bool CDRW; - /// Can write R-W subchannels with user provided data - public bool RWSubchannel; - /// Bitmask of supported data types - public ushort DataTypeSupported; - } +/// CD Track at Once Feature (002Dh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_002D +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports zero loss linking + public bool BUF; + /// Supports writing R-W subchannels in raw mode + public bool RWRaw; + /// Supports writing R-W subchannels in packed mode + public bool RWPack; + /// Can perform test writes + public bool TestWrite; + /// Supports overwriting a TAO track with another + public bool CDRW; + /// Can write R-W subchannels with user provided data + public bool RWSubchannel; + /// Bitmask of supported data types + public ushort DataTypeSupported; +} - /// CD Mastering (Session at Once) Feature (002Eh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_002E - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports zero loss linking - public bool BUF; - /// Can write in Session at Once - public bool SAO; - /// Can write multi-session in RAW - public bool RAWMS; - /// Can write in RAW - public bool RAW; - /// Can perform test writes - public bool TestWrite; - /// Can overwrite previously recorded data - public bool CDRW; - /// Can write R-W subchannels with user provided data - public bool RW; - /// Maximum length of a Cue Sheet for Session at Once - public uint MaxCueSheet; - } +/// CD Mastering (Session at Once) Feature (002Eh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_002E +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports zero loss linking + public bool BUF; + /// Can write in Session at Once + public bool SAO; + /// Can write multi-session in RAW + public bool RAWMS; + /// Can write in RAW + public bool RAW; + /// Can perform test writes + public bool TestWrite; + /// Can overwrite previously recorded data + public bool CDRW; + /// Can write R-W subchannels with user provided data + public bool RW; + /// Maximum length of a Cue Sheet for Session at Once + public uint MaxCueSheet; +} - /// DVD-R/-RW Write Feature (002Fh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_002F - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Buffer Under-run protection - public bool BUF; - /// Supports writing DVD-R DL - public bool RDL; - /// Test write - public bool TestWrite; - /// Can write and erase DVD-RW - public bool DVDRW; - } +/// DVD-R/-RW Write Feature (002Fh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_002F +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Buffer Under-run protection + public bool BUF; + /// Supports writing DVD-R DL + public bool RDL; + /// Test write + public bool TestWrite; + /// Can write and erase DVD-RW + public bool DVDRW; +} - /// Double Density CD Read Feature (0030h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0030 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// Double Density CD Read Feature (0030h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0030 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// Double Density CD-R Write Feature (0031h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0031 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Test write - public bool TestWrite; - } +/// Double Density CD-R Write Feature (0031h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0031 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Test write + public bool TestWrite; +} - /// Double Density CD-RW Write Feature (0032h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0032 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports quick formatting - public bool Intermediate; - /// Supports BLANK command - public bool Blank; - } +/// Double Density CD-RW Write Feature (0032h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0032 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports quick formatting + public bool Intermediate; + /// Supports BLANK command + public bool Blank; +} - /// Layer Jump Recording Feature (0033h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0033 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - public byte[] LinkSizes; - } +/// Layer Jump Recording Feature (0033h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0033 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + public byte[] LinkSizes; +} - /// Stop Long Operation Feature (0035h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0035 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// Stop Long Operation Feature (0035h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0035 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// CD-RW Media Write Support Feature (0037h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0037 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Bitmask of supported CD-RW media sub-types - public byte SubtypeSupport; - } +/// CD-RW Media Write Support Feature (0037h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0037 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Bitmask of supported CD-RW media sub-types + public byte SubtypeSupport; +} - /// BD-R Pseudo-Overwrite (POW) Feature (0038h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0038 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// BD-R Pseudo-Overwrite (POW) Feature (0038h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0038 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// DVD+RW Dual Layer Feature (003Ah) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_003A - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can format DVD+RW DL discs - public bool Write; - /// FORMAT UNIT supports quick start formatting - public bool QuickStart; - /// Drive only supports read compatibility stop - public bool CloseOnly; - } +/// DVD+RW Dual Layer Feature (003Ah) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_003A +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can format DVD+RW DL discs + public bool Write; + /// FORMAT UNIT supports quick start formatting + public bool QuickStart; + /// Drive only supports read compatibility stop + public bool CloseOnly; +} - /// DVD+R Dual Layer Feature (003Bh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_003B - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can format DVD+R DL discs - public bool Write; - /// FORMAT UNIT supports quick start formatting - public bool QuickStart; - /// Drive only supports read compatibility stop - public bool CloseOnly; - } +/// DVD+R Dual Layer Feature (003Bh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_003B +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can format DVD+R DL discs + public bool Write; + /// FORMAT UNIT supports quick start formatting + public bool QuickStart; + /// Drive only supports read compatibility stop + public bool CloseOnly; +} - /// BD Read Feature (0040h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0040 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can read BCA - public bool BCA; - /// Supports reading BD-RE Ver.2 - public bool RE2; - /// Supports reading BD-RE Ver.1 - public bool RE1; - /// Obsolete - public bool OldRE; - /// Supports reading BD-R Ver.1 - public bool R; - /// Obsolete - public bool OldR; - /// Supports reading BD-ROM Ver.1 - public bool ROM; - /// Obsolete - public bool OldROM; - } +/// BD Read Feature (0040h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0040 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can read BCA + public bool BCA; + /// Supports reading BD-RE Ver.2 + public bool RE2; + /// Supports reading BD-RE Ver.1 + public bool RE1; + /// Obsolete + public bool OldRE; + /// Supports reading BD-R Ver.1 + public bool R; + /// Obsolete + public bool OldR; + /// Supports reading BD-ROM Ver.1 + public bool ROM; + /// Obsolete + public bool OldROM; +} - /// BD Write Feature (0041h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0041 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports verify not required - public bool SVNR; - /// Supports writing BD-RE Ver.2 - public bool RE2; - /// Supports writing BD-RE Ver.1 - public bool RE1; - /// Obsolete - public bool OldRE; - /// Supports writing BD-R Ver.1 - public bool R; - /// Obsolete - public bool OldR; - } +/// BD Write Feature (0041h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0041 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports verify not required + public bool SVNR; + /// Supports writing BD-RE Ver.2 + public bool RE2; + /// Supports writing BD-RE Ver.1 + public bool RE1; + /// Obsolete + public bool OldRE; + /// Supports writing BD-R Ver.1 + public bool R; + /// Obsolete + public bool OldR; +} - /// TSR Feature (0042h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0042 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// TSR Feature (0042h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0042 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// HD DVD Read Feature (0050h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0050 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can read HD DVD-R - public bool HDDVDR; - /// Can read HD DVD-RAM - public bool HDDVDRAM; - } +/// HD DVD Read Feature (0050h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0050 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can read HD DVD-R + public bool HDDVDR; + /// Can read HD DVD-RAM + public bool HDDVDRAM; +} - /// HD DVD Write Feature (0051h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0051 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Can write HD DVD-R - public bool HDDVDR; - /// Can write HD DVD-RAM - public bool HDDVDRAM; - } +/// HD DVD Write Feature (0051h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0051 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Can write HD DVD-R + public bool HDDVDR; + /// Can write HD DVD-RAM + public bool HDDVDRAM; +} - /// Hybrid Disc Feature (0080h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0080 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Reset immunity - public bool RI; - } +/// Hybrid Disc Feature (0080h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0080 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Reset immunity + public bool RI; +} - /// Power Management Feature (0100h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0100 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// Power Management Feature (0100h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0100 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// S.M.A.R.T. Feature (0101h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0101 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Mode Page 1Ch is present - public bool PP; - } +/// S.M.A.R.T. Feature (0101h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0101 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Mode Page 1Ch is present + public bool PP; +} - /// Embedded Changer Feature (0102h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0102 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Side change capable - public bool SCC; - /// Supports Disc Present - public bool SDP; - /// Number of slots - 1 - public byte HighestSlotNumber; - } +/// Embedded Changer Feature (0102h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0102 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Side change capable + public bool SCC; + /// Supports Disc Present + public bool SDP; + /// Number of slots - 1 + public byte HighestSlotNumber; +} - /// CD Audio External Play Feature (0103h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0103 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports SCAN command - public bool Scan; - /// Separate Channel Mute - public bool SCM; - /// Separate Volume - public bool SV; - /// Number of volume levels - public ushort VolumeLevels; - } +/// CD Audio External Play Feature (0103h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0103 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports SCAN command + public bool Scan; + /// Separate Channel Mute + public bool SCM; + /// Separate Volume + public bool SV; + /// Number of volume levels + public ushort VolumeLevels; +} - /// Microcode Upgrade Feature (0104h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0104 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports validating 5-bit mode field of READ BUFFER and WRITE BUFFER commands. - public bool M5; - } +/// Microcode Upgrade Feature (0104h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0104 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports validating 5-bit mode field of READ BUFFER and WRITE BUFFER commands. + public bool M5; +} - /// Time-Out Feature (0105h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0105 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports G3Enable bit and Group3 Timeout field in Mode Page 1Dh - public bool Group3; - /// Indicates a unit of block length, in sectors, corresponding to increase a unit of Group 3 time unit - public ushort UnitLength; - } +/// Time-Out Feature (0105h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0105 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports G3Enable bit and Group3 Timeout field in Mode Page 1Dh + public bool Group3; + /// Indicates a unit of block length, in sectors, corresponding to increase a unit of Group 3 time unit + public ushort UnitLength; +} - /// DVD-CSS Feature (0106h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0106 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// CSS version - public byte CSSVersion; - } +/// DVD-CSS Feature (0106h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0106 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// CSS version + public byte CSSVersion; +} - /// Real Time Streaming Feature (0107h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0107 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports Set Minimum Performance bit in SET STREAMING - public bool SMP; - /// Supports READ BUFFER CAPACITY with block bit set - public bool RBCB; - /// Supports SET CD SPEED - public bool SCS; - /// Has Mode Page 2Ah with Speed Performance Descriptors - public bool MP2A; - /// Supports type 03h of GET PERFORMANCE - public bool WSPD; - /// Supports stream recording - public bool SW; - } +/// Real Time Streaming Feature (0107h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0107 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports Set Minimum Performance bit in SET STREAMING + public bool SMP; + /// Supports READ BUFFER CAPACITY with block bit set + public bool RBCB; + /// Supports SET CD SPEED + public bool SCS; + /// Has Mode Page 2Ah with Speed Performance Descriptors + public bool MP2A; + /// Supports type 03h of GET PERFORMANCE + public bool WSPD; + /// Supports stream recording + public bool SW; +} - /// Drive serial number (0108h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0108 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Drive serial number - public string Serial; - } +/// Drive serial number (0108h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0108 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Drive serial number + public string Serial; +} - /// Media Serial Number Feature (0109h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0109 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// Media Serial Number Feature (0109h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0109 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// Disc Control Blocks Feature (010Ah) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_010A - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - public uint[] DCBs; - } +/// Disc Control Blocks Feature (010Ah) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_010A +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + public uint[] DCBs; +} - /// DVD CPRM Feature (010Bh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_010B - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// CPRM version - public byte CPRMVersion; - } +/// DVD CPRM Feature (010Bh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_010B +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// CPRM version + public byte CPRMVersion; +} - /// Firmware Information Feature (010Ch) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_010C - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - public ushort Century; - public ushort Year; - public ushort Month; - public ushort Day; - public ushort Hour; - public ushort Minute; - public ushort Second; - } +/// Firmware Information Feature (010Ch) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_010C +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + public ushort Century; + public ushort Year; + public ushort Month; + public ushort Day; + public ushort Hour; + public ushort Minute; + public ushort Second; +} - /// AACS Feature (010Dh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_010D - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Drive supports reading drive certificate - public bool RDC; - /// Drive can read media key block of CPRM - public bool RMC; - /// Drive can write bus encrypted blocks - public bool WBE; - /// Drive supports bus encryption - public bool BEC; - /// Drive supports generating the binding nonce - public bool BNG; - /// Blocks required to store the binding nonce for the media - public byte BindNonceBlocks; - /// Maximum number of AGIDs supported concurrently - public byte AGIDs; - /// AACS version - public byte AACSVersion; - } +/// AACS Feature (010Dh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_010D +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Drive supports reading drive certificate + public bool RDC; + /// Drive can read media key block of CPRM + public bool RMC; + /// Drive can write bus encrypted blocks + public bool WBE; + /// Drive supports bus encryption + public bool BEC; + /// Drive supports generating the binding nonce + public bool BNG; + /// Blocks required to store the binding nonce for the media + public byte BindNonceBlocks; + /// Maximum number of AGIDs supported concurrently + public byte AGIDs; + /// AACS version + public byte AACSVersion; +} - /// DVD CSS Managed Recording Feature (010Eh) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_010E - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Maximum number of Scramble Extent information entries in a single SEND DISC STRUCTURE - public byte MaxScrambleExtent; - } +/// DVD CSS Managed Recording Feature (010Eh) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_010E +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Maximum number of Scramble Extent information entries in a single SEND DISC STRUCTURE + public byte MaxScrambleExtent; +} - /// SecurDisc Feature (0113h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0113 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// SecurDisc Feature (0113h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0113 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - /// OSSC Feature (0142h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0142 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - /// Supports PSA updates on write-once media - public bool PSAU; - /// Supports linked OSPBs - public bool LOSPB; - /// Restricted to recording only OSSC disc format - public bool ME; - public ushort[] Profiles; - } +/// OSSC Feature (0142h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0142 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; + /// Supports PSA updates on write-once media + public bool PSAU; + /// Supports linked OSPBs + public bool LOSPB; + /// Restricted to recording only OSSC disc format + public bool ME; + public ushort[] Profiles; +} - /// VCPS Feature (0110h) - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct Feature_0110 - { - /// Feature version - public byte Version; - /// Feature is persistent - public bool Persistent; - /// Feature is currently in use - public bool Current; - } +/// VCPS Feature (0110h) +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct Feature_0110 +{ + /// Feature version + public byte Version; + /// Feature is persistent + public bool Persistent; + /// Feature is currently in use + public bool Current; +} - public static class Features +public static class Features +{ + public static Feature_0000? Decode_0000(byte[] feature) { - public static Feature_0000? Decode_0000(byte[] feature) + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0000) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0000(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + int offset = 4; + List listProfiles = new List(); + + while(offset < feature.Length) { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0000) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0000(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - int offset = 4; - List listProfiles = new List(); - - while(offset < feature.Length) + var prof = new Profile { - var prof = new Profile - { - Number = (ProfileNumber)((feature[offset] << 8) + feature[offset + 1]) - }; + Number = (ProfileNumber)((feature[offset] << 8) + feature[offset + 1]) + }; - prof.Current |= (feature[offset + 2] & 0x01) == 0x01; - listProfiles.Add(prof); - offset += 4; - } - - decoded.Profiles = listProfiles.ToArray(); - - return decoded; + prof.Current |= (feature[offset + 2] & 0x01) == 0x01; + listProfiles.Add(prof); + offset += 4; } - public static Feature_0001? Decode_0001(byte[] feature) - { - if(feature == null) - return null; + decoded.Profiles = listProfiles.ToArray(); - if(feature.Length < 8) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0001? Decode_0001(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x0001) - return null; + if(feature.Length < 8) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_0001(); + if(number != 0x0001) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - decoded.PhysicalInterfaceStandard = - (PhysicalInterfaces)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + var decoded = new Feature_0001(); - if(decoded.Version >= 1 && - feature.Length >= 12) - decoded.DBE |= (feature[8] & 0x01) == 0x01; + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - if(decoded.Version >= 2 && - feature.Length >= 12) - decoded.INQ2 |= (feature[8] & 0x02) == 0x02; + decoded.PhysicalInterfaceStandard = + (PhysicalInterfaces)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + if(decoded.Version >= 1 && + feature.Length >= 12) + decoded.DBE |= (feature[8] & 0x01) == 0x01; + + if(decoded.Version >= 2 && + feature.Length >= 12) + decoded.INQ2 |= (feature[8] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0002? Decode_0002(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0002) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0002(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Async |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version >= 1) + decoded.OCEvent |= (feature[4] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0003? Decode_0003(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0003) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0003(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.LoadingMechanismType = (byte)((feature[4] & 0xE0) >> 5); + decoded.Eject |= (feature[4] & 0x08) == 0x08; + decoded.PreventJumper |= (feature[4] & 0x04) == 0x04; + decoded.Lock |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version < 2) return decoded; + + decoded.Load |= (feature[4] & 0x10) == 0x10; + decoded.DBML |= (feature[4] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0004? Decode_0004(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0004) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0004(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SPWP |= (feature[4] & 0x02) == 0x02; + decoded.SSWPP |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version >= 1) + decoded.WDCB |= (feature[4] & 0x04) == 0x04; + + if(decoded.Version >= 2) + decoded.DWP |= (feature[4] & 0x08) == 0x08; + + return decoded; + } + + public static Feature_0010? Decode_0010(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 12) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0010) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0010(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.LogicalBlockSize = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + + decoded.Blocking = (ushort)((feature[8] << 8) + feature[9]); + + decoded.PP |= (feature[10] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_001D? Decode_001D(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x001D) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_001D(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_001E? Decode_001E(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x001E) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_001E(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1) + { + decoded.C2 |= (feature[4] & 0x02) == 0x02; + decoded.CDText |= (feature[4] & 0x01) == 0x01; } - public static Feature_0002? Decode_0002(byte[] feature) + if(decoded.Version >= 2) + decoded.DAP |= (feature[4] & 0x80) == 0x80; + + return decoded; + } + + public static Feature_001F? Decode_001F(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x001F) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_001F(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 2 && + feature.Length >= 8) { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0002) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0002(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Async |= (feature[4] & 0x01) == 0x01; - - if(decoded.Version >= 1) - decoded.OCEvent |= (feature[4] & 0x02) == 0x02; - - return decoded; + decoded.MULTI110 |= (feature[4] & 0x01) == 0x01; + decoded.DualR |= (feature[6] & 0x01) == 0x01; } - public static Feature_0003? Decode_0003(byte[] feature) - { - if(feature == null) - return null; + // TODO: Check this + if(decoded.Version >= 2 && + feature.Length >= 8) + decoded.DualRW |= (feature[6] & 0x02) == 0x02; - if(feature.Length < 8) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0020? Decode_0020(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x0003) - return null; + if(feature.Length < 16) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_0003(); + if(number != 0x0020) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - decoded.LoadingMechanismType = (byte)((feature[4] & 0xE0) >> 5); - decoded.Eject |= (feature[4] & 0x08) == 0x08; - decoded.PreventJumper |= (feature[4] & 0x04) == 0x04; - decoded.Lock |= (feature[4] & 0x01) == 0x01; + var decoded = new Feature_0020(); - if(decoded.Version < 2) - return decoded; - - decoded.Load |= (feature[4] & 0x10) == 0x10; - decoded.DBML |= (feature[4] & 0x02) == 0x02; + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(decoded.Version < 1) return decoded; + + decoded.LastLBA = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + + decoded.LogicalBlockSize = + (uint)((feature[8] << 24) + (feature[9] << 16) + (feature[10] << 8) + feature[11]); + + decoded.Blocking = (ushort)((feature[12] << 8) + feature[13]); + decoded.PP |= (feature[14] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0021? Decode_0021(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0021) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0021(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1) + { + decoded.DataTypeSupported = (ushort)((feature[4] << 8) + feature[5]); + decoded.BUF |= (feature[6] & 0x01) == 0x01; + decoded.LinkSizes = new byte[feature[7]]; + + if(feature.Length > feature[7] + 8) + Array.Copy(feature, 8, decoded.LinkSizes, 0, feature[7]); } - public static Feature_0004? Decode_0004(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0004) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0004(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.SPWP |= (feature[4] & 0x02) == 0x02; - decoded.SSWPP |= (feature[4] & 0x01) == 0x01; - - if(decoded.Version >= 1) - decoded.WDCB |= (feature[4] & 0x04) == 0x04; - - if(decoded.Version >= 2) - decoded.DWP |= (feature[4] & 0x08) == 0x08; - + if(decoded.Version < 3) return decoded; + + decoded.TRIO |= (feature[6] & 0x04) == 0x04; + decoded.ARSV |= (feature[6] & 0x02) == 0x02; + + return decoded; + } + + public static Feature_0022? Decode_0022(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0022) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0022(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0023? Decode_0023(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0023) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0023(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1 && + feature.Length >= 12) + { + decoded.RENoSA |= (feature[4] & 0x08) == 0x08; + decoded.Expand |= (feature[4] & 0x04) == 0x04; + decoded.QCert |= (feature[4] & 0x02) == 0x02; + decoded.Cert |= (feature[4] & 0x01) == 0x01; + decoded.RRM |= (feature[8] & 0x01) == 0x01; } - public static Feature_0010? Decode_0010(byte[] feature) - { - if(feature == null) - return null; + if(decoded.Version >= 2 && + feature.Length >= 12) + decoded.FRF |= (feature[4] & 0x80) == 0x80; - if(feature.Length < 12) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0024? Decode_0024(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x0010) - return null; + if(feature.Length < 4) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_0010(); + if(number != 0x0024) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - decoded.LogicalBlockSize = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + var decoded = new Feature_0024(); - decoded.Blocking = (ushort)((feature[8] << 8) + feature[9]); + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - decoded.PP |= (feature[10] & 0x01) == 0x01; + if(decoded.Version >= 1 && + feature.Length >= 8) + decoded.SSA |= (feature[4] & 0x80) == 0x80; + return decoded; + } + + public static Feature_0025? Decode_0025(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 12) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0025) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0025(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.LogicalBlockSize = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); + + decoded.Blocking = (ushort)((feature[8] << 8) + feature[9]); + + decoded.PP |= (feature[10] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0026? Decode_0026(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0026) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0026(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0027? Decode_0027(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0027) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0027(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0028? Decode_0028(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0028) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0028(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + + if(decoded.Version < 1) return decoded; - } - public static Feature_001D? Decode_001D(byte[] feature) - { - if(feature == null) - return null; + decoded.DVDPWrite |= (feature[4] & 0x04) == 0x04; + decoded.DVDPRead |= (feature[4] & 0x02) == 0x02; - if(feature.Length < 4) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0029? Decode_0029(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x001D) - return null; + if(feature.Length < 8) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_001D(); + if(number != 0x0029) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - return decoded; - } + var decoded = new Feature_0029(); - public static Feature_001E? Decode_001E(byte[] feature) - { - if(feature == null) - return null; + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - if(feature.Length < 8) - return null; + decoded.DRTDM |= (feature[4] & 0x01) == 0x01; + decoded.DBICacheZones = feature[5]; + decoded.Entries = (ushort)((feature[6] << 8) + feature[7]); - ushort number = (ushort)((feature[0] << 8) + feature[1]); + return decoded; + } - if(number != 0x001E) - return null; + public static Feature_002A? Decode_002A(byte[] feature) + { + if(feature == null) + return null; - if(feature[3] + 4 != feature.Length) - return null; + if(feature.Length < 8) + return null; - var decoded = new Feature_001E(); + ushort number = (ushort)((feature[0] << 8) + feature[1]); - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(number != 0x002A) + return null; - if(decoded.Version >= 1) - { - decoded.C2 |= (feature[4] & 0x02) == 0x02; - decoded.CDText |= (feature[4] & 0x01) == 0x01; - } + if(feature[3] + 4 != feature.Length) + return null; - if(decoded.Version >= 2) - decoded.DAP |= (feature[4] & 0x80) == 0x80; + var decoded = new Feature_002A(); - return decoded; - } + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - public static Feature_001F? Decode_001F(byte[] feature) - { - if(feature == null) - return null; + decoded.Write |= (feature[4] & 0x01) == 0x01; + decoded.CloseOnly |= (feature[5] & 0x01) == 0x01; - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x001F) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_001F(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version >= 2 && - feature.Length >= 8) - { - decoded.MULTI110 |= (feature[4] & 0x01) == 0x01; - decoded.DualR |= (feature[6] & 0x01) == 0x01; - } - - // TODO: Check this - if(decoded.Version >= 2 && - feature.Length >= 8) - decoded.DualRW |= (feature[6] & 0x02) == 0x02; - - return decoded; - } - - public static Feature_0020? Decode_0020(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 16) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0020) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0020(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version < 1) - return decoded; - - decoded.LastLBA = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); - - decoded.LogicalBlockSize = - (uint)((feature[8] << 24) + (feature[9] << 16) + (feature[10] << 8) + feature[11]); - - decoded.Blocking = (ushort)((feature[12] << 8) + feature[13]); - decoded.PP |= (feature[14] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0021? Decode_0021(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0021) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0021(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version >= 1) - { - decoded.DataTypeSupported = (ushort)((feature[4] << 8) + feature[5]); - decoded.BUF |= (feature[6] & 0x01) == 0x01; - decoded.LinkSizes = new byte[feature[7]]; - - if(feature.Length > feature[7] + 8) - Array.Copy(feature, 8, decoded.LinkSizes, 0, feature[7]); - } - - if(decoded.Version < 3) - return decoded; - - decoded.TRIO |= (feature[6] & 0x04) == 0x04; - decoded.ARSV |= (feature[6] & 0x02) == 0x02; - - return decoded; - } - - public static Feature_0022? Decode_0022(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0022) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0022(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0023? Decode_0023(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0023) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0023(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version >= 1 && - feature.Length >= 12) - { - decoded.RENoSA |= (feature[4] & 0x08) == 0x08; - decoded.Expand |= (feature[4] & 0x04) == 0x04; - decoded.QCert |= (feature[4] & 0x02) == 0x02; - decoded.Cert |= (feature[4] & 0x01) == 0x01; - decoded.RRM |= (feature[8] & 0x01) == 0x01; - } - - if(decoded.Version >= 2 && - feature.Length >= 12) - decoded.FRF |= (feature[4] & 0x80) == 0x80; - - return decoded; - } - - public static Feature_0024? Decode_0024(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0024) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0024(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version >= 1 && - feature.Length >= 8) - decoded.SSA |= (feature[4] & 0x80) == 0x80; - - return decoded; - } - - public static Feature_0025? Decode_0025(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 12) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0025) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0025(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.LogicalBlockSize = (uint)((feature[4] << 24) + (feature[5] << 16) + (feature[6] << 8) + feature[7]); - - decoded.Blocking = (ushort)((feature[8] << 8) + feature[9]); - - decoded.PP |= (feature[10] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0026? Decode_0026(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0026) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0026(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0027? Decode_0027(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0027) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0027(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0028? Decode_0028(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0028) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0028(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Write |= (feature[4] & 0x01) == 0x01; - - if(decoded.Version < 1) - return decoded; - - decoded.DVDPWrite |= (feature[4] & 0x04) == 0x04; - decoded.DVDPRead |= (feature[4] & 0x02) == 0x02; - - return decoded; - } - - public static Feature_0029? Decode_0029(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0029) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0029(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.DRTDM |= (feature[4] & 0x01) == 0x01; - decoded.DBICacheZones = feature[5]; - decoded.Entries = (ushort)((feature[6] << 8) + feature[7]); - - return decoded; - } - - public static Feature_002A? Decode_002A(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x002A) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_002A(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Write |= (feature[4] & 0x01) == 0x01; - decoded.CloseOnly |= (feature[5] & 0x01) == 0x01; - - if(decoded.Version >= 1) - decoded.QuickStart |= (feature[5] & 0x02) == 0x02; - - return decoded; - } - - public static Feature_002B? Decode_002B(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x002B) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_002B(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Write |= (feature[4] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_002C? Decode_002C(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x002C) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_002C(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.DSDG |= (feature[4] & 0x08) == 0x08; - decoded.DSDR |= (feature[4] & 0x04) == 0x04; - decoded.Intermediate |= (feature[4] & 0x02) == 0x02; - decoded.Blank |= (feature[4] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_002D? Decode_002D(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x002D) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_002D(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.TestWrite |= (feature[4] & 0x04) == 0x04; - decoded.CDRW |= (feature[4] & 0x02) == 0x02; - decoded.RWSubchannel |= (feature[4] & 0x01) == 0x01; - decoded.DataTypeSupported = (ushort)((feature[6] << 8) + feature[7]); - - if(decoded.Version < 2) - return decoded; - - decoded.BUF |= (feature[4] & 0x40) == 0x40; - decoded.RWRaw |= (feature[4] & 0x10) == 0x10; - decoded.RWPack |= (feature[4] & 0x08) == 0x08; - - return decoded; - } - - public static Feature_002E? Decode_002E(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x002E) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_002E(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.SAO |= (feature[4] & 0x20) == 0x20; - decoded.RAWMS |= (feature[4] & 0x10) == 0x10; - decoded.RAW |= (feature[4] & 0x08) == 0x08; - decoded.TestWrite |= (feature[4] & 0x04) == 0x04; - decoded.CDRW |= (feature[4] & 0x02) == 0x02; - decoded.RW |= (feature[4] & 0x01) == 0x01; - decoded.MaxCueSheet = (uint)((feature[5] << 16) + (feature[6] << 8) + feature[7]); - - if(decoded.Version >= 1) - decoded.BUF |= (feature[4] & 0x40) == 0x40; - - return decoded; - } - - public static Feature_002F? Decode_002F(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x002F) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_002F(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.BUF |= (feature[4] & 0x40) == 0x40; - decoded.TestWrite |= (feature[4] & 0x04) == 0x04; - - if(decoded.Version >= 1) - decoded.DVDRW |= (feature[4] & 0x02) == 0x02; - - if(decoded.Version >= 2) - decoded.RDL |= (feature[4] & 0x08) == 0x08; - - return decoded; - } - - public static Feature_0030? Decode_0030(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0030) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0030(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0031? Decode_0031(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0031) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0031(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.TestWrite |= (feature[4] & 0x04) == 0x04; - - return decoded; - } - - public static Feature_0032? Decode_0032(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0032) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0032(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Intermediate |= (feature[4] & 0x02) == 0x02; - decoded.Blank |= (feature[4] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0033? Decode_0033(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0033) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0033(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(feature[7] <= 0 || - feature.Length <= feature[7] + 8) - return decoded; - - decoded.LinkSizes = new byte[feature[7]]; - Array.Copy(feature, 8, decoded.LinkSizes, 0, feature[7]); - - return decoded; - } - - public static Feature_0035? Decode_0035(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0035) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0035(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0037? Decode_0037(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0037) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0037(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.SubtypeSupport = feature[5]; - - return decoded; - } - - public static Feature_0038? Decode_0038(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0038) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0038(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_003A? Decode_003A(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x003A) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_003A(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Write |= (feature[4] & 0x01) == 0x01; + if(decoded.Version >= 1) decoded.QuickStart |= (feature[5] & 0x02) == 0x02; - decoded.CloseOnly |= (feature[5] & 0x01) == 0x01; + return decoded; + } + + public static Feature_002B? Decode_002B(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002B) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_002B(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_002C? Decode_002C(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002C) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_002C(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.DSDG |= (feature[4] & 0x08) == 0x08; + decoded.DSDR |= (feature[4] & 0x04) == 0x04; + decoded.Intermediate |= (feature[4] & 0x02) == 0x02; + decoded.Blank |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_002D? Decode_002D(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002D) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_002D(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + decoded.CDRW |= (feature[4] & 0x02) == 0x02; + decoded.RWSubchannel |= (feature[4] & 0x01) == 0x01; + decoded.DataTypeSupported = (ushort)((feature[6] << 8) + feature[7]); + + if(decoded.Version < 2) return decoded; - } - public static Feature_003B? Decode_003B(byte[] feature) - { - if(feature == null) - return null; + decoded.BUF |= (feature[4] & 0x40) == 0x40; + decoded.RWRaw |= (feature[4] & 0x10) == 0x10; + decoded.RWPack |= (feature[4] & 0x08) == 0x08; - if(feature.Length < 8) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_002E? Decode_002E(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x003B) - return null; + if(feature.Length < 8) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_003B(); + if(number != 0x002E) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - decoded.Write |= (feature[4] & 0x01) == 0x01; + var decoded = new Feature_002E(); + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SAO |= (feature[4] & 0x20) == 0x20; + decoded.RAWMS |= (feature[4] & 0x10) == 0x10; + decoded.RAW |= (feature[4] & 0x08) == 0x08; + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + decoded.CDRW |= (feature[4] & 0x02) == 0x02; + decoded.RW |= (feature[4] & 0x01) == 0x01; + decoded.MaxCueSheet = (uint)((feature[5] << 16) + (feature[6] << 8) + feature[7]); + + if(decoded.Version >= 1) + decoded.BUF |= (feature[4] & 0x40) == 0x40; + + return decoded; + } + + public static Feature_002F? Decode_002F(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x002F) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_002F(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.BUF |= (feature[4] & 0x40) == 0x40; + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + + if(decoded.Version >= 1) + decoded.DVDRW |= (feature[4] & 0x02) == 0x02; + + if(decoded.Version >= 2) + decoded.RDL |= (feature[4] & 0x08) == 0x08; + + return decoded; + } + + public static Feature_0030? Decode_0030(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0030) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0030(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0031? Decode_0031(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0031) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0031(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.TestWrite |= (feature[4] & 0x04) == 0x04; + + return decoded; + } + + public static Feature_0032? Decode_0032(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0032) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0032(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Intermediate |= (feature[4] & 0x02) == 0x02; + decoded.Blank |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0033? Decode_0033(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0033) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0033(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(feature[7] <= 0 || + feature.Length <= feature[7] + 8) return decoded; - } - public static Feature_0040? Decode_0040(byte[] feature) - { - if(feature == null) - return null; + decoded.LinkSizes = new byte[feature[7]]; + Array.Copy(feature, 8, decoded.LinkSizes, 0, feature[7]); - if(feature.Length < 32) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0035? Decode_0035(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x0040) - return null; + if(feature.Length < 4) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_0040(); + if(number != 0x0035) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - decoded.OldRE |= (feature[9] & 0x01) == 0x01; - decoded.OldR |= (feature[17] & 0x01) == 0x01; - decoded.OldROM |= (feature[25] & 0x01) == 0x01; + var decoded = new Feature_0035(); - if(decoded.Version < 1) - return decoded; + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - decoded.BCA |= (feature[4] & 0x01) == 0x01; - decoded.RE2 |= (feature[9] & 0x04) == 0x04; - decoded.RE1 |= (feature[9] & 0x02) == 0x02; - decoded.R |= (feature[17] & 0x02) == 0x02; - decoded.ROM |= (feature[25] & 0x02) == 0x02; + return decoded; + } + public static Feature_0037? Decode_0037(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0037) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0037(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SubtypeSupport = feature[5]; + + return decoded; + } + + public static Feature_0038? Decode_0038(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0038) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0038(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_003A? Decode_003A(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x003A) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_003A(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + decoded.QuickStart |= (feature[5] & 0x02) == 0x02; + decoded.CloseOnly |= (feature[5] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_003B? Decode_003B(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x003B) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_003B(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Write |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0040? Decode_0040(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 32) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0040) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0040(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.OldRE |= (feature[9] & 0x01) == 0x01; + decoded.OldR |= (feature[17] & 0x01) == 0x01; + decoded.OldROM |= (feature[25] & 0x01) == 0x01; + + if(decoded.Version < 1) return decoded; - } - public static Feature_0041? Decode_0041(byte[] feature) - { - if(feature == null) - return null; + decoded.BCA |= (feature[4] & 0x01) == 0x01; + decoded.RE2 |= (feature[9] & 0x04) == 0x04; + decoded.RE1 |= (feature[9] & 0x02) == 0x02; + decoded.R |= (feature[17] & 0x02) == 0x02; + decoded.ROM |= (feature[25] & 0x02) == 0x02; - if(feature.Length < 24) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0041? Decode_0041(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x0041) - return null; + if(feature.Length < 24) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_0041(); + if(number != 0x0041) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - decoded.SVNR |= (feature[4] & 0x01) == 0x01; - decoded.OldRE |= (feature[9] & 0x01) == 0x01; - decoded.OldR |= (feature[17] & 0x01) == 0x01; + var decoded = new Feature_0041(); - if(decoded.Version < 1) - return decoded; + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - decoded.RE2 |= (feature[9] & 0x04) == 0x04; - decoded.RE1 |= (feature[9] & 0x02) == 0x02; - decoded.R |= (feature[17] & 0x02) == 0x02; + decoded.SVNR |= (feature[4] & 0x01) == 0x01; + decoded.OldRE |= (feature[9] & 0x01) == 0x01; + decoded.OldR |= (feature[17] & 0x01) == 0x01; + if(decoded.Version < 1) return decoded; - } - public static Feature_0042? Decode_0042(byte[] feature) - { - if(feature == null) - return null; + decoded.RE2 |= (feature[9] & 0x04) == 0x04; + decoded.RE1 |= (feature[9] & 0x02) == 0x02; + decoded.R |= (feature[17] & 0x02) == 0x02; - if(feature.Length < 4) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0042? Decode_0042(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x0042) - return null; + if(feature.Length < 4) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_0042(); + if(number != 0x0042) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; + var decoded = new Feature_0042(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0050? Decode_0050(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0050) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0050(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.HDDVDR |= (feature[4] & 0x01) == 0x01; + decoded.HDDVDRAM |= (feature[6] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0051? Decode_0051(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0051) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0051(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.HDDVDR |= (feature[4] & 0x01) == 0x01; + decoded.HDDVDRAM |= (feature[6] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0080? Decode_0080(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0080) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0080(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.RI |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0100? Decode_0100(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0100) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0100(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0101? Decode_0101(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0101) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0101(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.PP |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0102? Decode_0102(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0102) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0102(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.SCC |= (feature[4] & 0x10) == 0x10; + decoded.SDP |= (feature[4] & 0x04) == 0x04; + decoded.HighestSlotNumber = (byte)(feature[7] & 0x1F); + + return decoded; + } + + public static Feature_0103? Decode_0103(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0103) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0103(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Scan |= (feature[4] & 0x04) == 0x04; + decoded.SCM |= (feature[4] & 0x02) == 0x02; + decoded.SV |= (feature[4] & 0x01) == 0x01; + decoded.VolumeLevels = (ushort)((feature[6] << 8) + feature[7]); + + return decoded; + } + + public static Feature_0104? Decode_0104(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0104) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0104(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 1 && + feature.Length >= 8) + decoded.M5 |= (feature[4] & 0x01) == 0x01; + + return decoded; + } + + public static Feature_0105? Decode_0105(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0105) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0105(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version < 1 || + feature.Length < 8) return decoded; - } - public static Feature_0050? Decode_0050(byte[] feature) + decoded.Group3 |= (feature[4] & 0x01) == 0x01; + decoded.UnitLength = (ushort)((feature[6] << 8) + feature[7]); + + return decoded; + } + + public static Feature_0106? Decode_0106(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0106) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0106(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.CSSVersion = feature[7]; + + return decoded; + } + + public static Feature_0107? Decode_0107(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0107) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0107(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + if(decoded.Version >= 3 && + feature.Length >= 8) { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0050) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0050(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.HDDVDR |= (feature[4] & 0x01) == 0x01; - decoded.HDDVDRAM |= (feature[6] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0051? Decode_0051(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0051) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0051(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.HDDVDR |= (feature[4] & 0x01) == 0x01; - decoded.HDDVDRAM |= (feature[6] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0080? Decode_0080(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0080) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0080(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.RI |= (feature[4] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0100? Decode_0100(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0100) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0100(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0101? Decode_0101(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0101) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0101(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.PP |= (feature[4] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0102? Decode_0102(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0102) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0102(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.SCC |= (feature[4] & 0x10) == 0x10; - decoded.SDP |= (feature[4] & 0x04) == 0x04; - decoded.HighestSlotNumber = (byte)(feature[7] & 0x1F); - - return decoded; - } - - public static Feature_0103? Decode_0103(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0103) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0103(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Scan |= (feature[4] & 0x04) == 0x04; - decoded.SCM |= (feature[4] & 0x02) == 0x02; - decoded.SV |= (feature[4] & 0x01) == 0x01; - decoded.VolumeLevels = (ushort)((feature[6] << 8) + feature[7]); - - return decoded; - } - - public static Feature_0104? Decode_0104(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0104) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0104(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version >= 1 && - feature.Length >= 8) - decoded.M5 |= (feature[4] & 0x01) == 0x01; - - return decoded; - } - - public static Feature_0105? Decode_0105(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0105) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0105(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version < 1 || - feature.Length < 8) - return decoded; - - decoded.Group3 |= (feature[4] & 0x01) == 0x01; - decoded.UnitLength = (ushort)((feature[6] << 8) + feature[7]); - - return decoded; - } - - public static Feature_0106? Decode_0106(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0106) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0106(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.CSSVersion = feature[7]; - - return decoded; - } - - public static Feature_0107? Decode_0107(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0107) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0107(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - if(decoded.Version >= 3 && - feature.Length >= 8) - { - decoded.RBCB |= (feature[4] & 0x10) == 0x10; - decoded.SCS |= (feature[4] & 0x08) == 0x08; - decoded.MP2A |= (feature[4] & 0x04) == 0x04; - decoded.WSPD |= (feature[4] & 0x02) == 0x02; - decoded.SW |= (feature[4] & 0x01) == 0x01; - } - - if(decoded.Version < 5 || - feature.Length < 8) - return decoded; - - decoded.SMP |= (feature[4] & 0x20) == 0x20; decoded.RBCB |= (feature[4] & 0x10) == 0x10; - - return decoded; + decoded.SCS |= (feature[4] & 0x08) == 0x08; + decoded.MP2A |= (feature[4] & 0x04) == 0x04; + decoded.WSPD |= (feature[4] & 0x02) == 0x02; + decoded.SW |= (feature[4] & 0x01) == 0x01; } - public static Feature_0108? Decode_0108(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0108) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0108(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - byte[] serial = new byte[feature.Length]; - Array.Copy(feature, 4, serial, 0, feature.Length - 4); - decoded.Serial = StringHandlers.CToString(serial).Trim(); - + if(decoded.Version < 5 || + feature.Length < 8) return decoded; - } - public static Feature_0109? Decode_0109(byte[] feature) - { - if(feature == null) - return null; + decoded.SMP |= (feature[4] & 0x20) == 0x20; + decoded.RBCB |= (feature[4] & 0x10) == 0x10; - if(feature.Length < 4) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_0108? Decode_0108(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x0109) - return null; + if(feature.Length < 4) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_0109(); + if(number != 0x0108) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; + var decoded = new Feature_0108(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + byte[] serial = new byte[feature.Length]; + Array.Copy(feature, 4, serial, 0, feature.Length - 4); + decoded.Serial = StringHandlers.CToString(serial).Trim(); + + return decoded; + } + + public static Feature_0109? Decode_0109(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0109) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0109(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_010A? Decode_010A(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010A) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_010A(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.DCBs = new uint[feature[3] / 4]; + + for(int i = 0; i < decoded.DCBs.Length; i++) + decoded.DCBs[i] = (uint)((feature[0 + 4 + (i * 4)] << 24) + (feature[1 + 4 + (i * 4)] << 16) + + (feature[2 + 4 + (i * 4)] << 8) + feature[3 + 4 + (i * 4)]); + + return decoded; + } + + public static Feature_010B? Decode_010B(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010B) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_010B(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.CPRMVersion = feature[7]; + + return decoded; + } + + public static Feature_010C? Decode_010C(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 20) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010C) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_010C(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.Century = (ushort)((feature[4] << 8) + feature[5]); + decoded.Year = (ushort)((feature[6] << 8) + feature[7]); + decoded.Month = (ushort)((feature[8] << 8) + feature[9]); + decoded.Day = (ushort)((feature[10] << 8) + feature[11]); + decoded.Hour = (ushort)((feature[12] << 8) + feature[13]); + decoded.Minute = (ushort)((feature[14] << 8) + feature[15]); + decoded.Second = (ushort)((feature[16] << 8) + feature[17]); + + return decoded; + } + + public static Feature_010D? Decode_010D(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x010D) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_010D(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.BNG |= (feature[4] & 0x01) == 0x01; + decoded.BindNonceBlocks = feature[5]; + decoded.AGIDs = (byte)(feature[6] & 0x0F); + decoded.AACSVersion = feature[7]; + + if(decoded.Version < 2) return decoded; - } - public static Feature_010A? Decode_010A(byte[] feature) - { - if(feature == null) - return null; + decoded.RDC |= (feature[4] & 0x10) == 0x10; + decoded.RMC |= (feature[4] & 0x08) == 0x08; + decoded.WBE |= (feature[4] & 0x04) == 0x04; + decoded.BEC |= (feature[4] & 0x02) == 0x02; - if(feature.Length < 8) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static Feature_010E? Decode_010E(byte[] feature) + { + if(feature == null) + return null; - if(number != 0x010A) - return null; + if(feature.Length < 8) + return null; - if(feature[3] + 4 != feature.Length) - return null; + ushort number = (ushort)((feature[0] << 8) + feature[1]); - var decoded = new Feature_010A(); + if(number != 0x010E) + return null; - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + if(feature[3] + 4 != feature.Length) + return null; - decoded.DCBs = new uint[feature[3] / 4]; + var decoded = new Feature_010E(); - for(int i = 0; i < decoded.DCBs.Length; i++) - decoded.DCBs[i] = (uint)((feature[0 + 4 + (i * 4)] << 24) + (feature[1 + 4 + (i * 4)] << 16) + - (feature[2 + 4 + (i * 4)] << 8) + feature[3 + 4 + (i * 4)]); + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + decoded.MaxScrambleExtent = feature[4]; + + return decoded; + } + + public static Feature_0110? Decode_0110(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 8) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0110) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0110(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0113? Decode_0113(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 4) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0113) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0113(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + return decoded; + } + + public static Feature_0142? Decode_0142(byte[] feature) + { + if(feature == null) + return null; + + if(feature.Length < 6) + return null; + + ushort number = (ushort)((feature[0] << 8) + feature[1]); + + if(number != 0x0142) + return null; + + if(feature[3] + 4 != feature.Length) + return null; + + var decoded = new Feature_0142(); + + decoded.Current |= (feature[2] & 0x01) == 0x01; + decoded.Persistent |= (feature[2] & 0x02) == 0x02; + decoded.Version = (byte)((feature[2] & 0x3C) >> 2); + + decoded.PSAU |= (feature[4] & 0x80) == 0x80; + decoded.LOSPB |= (feature[4] & 0x40) == 0x40; + decoded.ME |= (feature[4] & 0x01) == 0x01; + decoded.Profiles = new ushort[feature[5]]; + + if((feature[5] * 2) + 6 != feature.Length) return decoded; - } - public static Feature_010B? Decode_010B(byte[] feature) - { - if(feature == null) - return null; + for(int i = 0; i < feature[5]; i++) + decoded.Profiles[i] = (ushort)((feature[0 + 6 + (2 * i)] << 8) + feature[1 + 6 + (2 * i)]); - if(feature.Length < 4) - return null; + return decoded; + } - ushort number = (ushort)((feature[0] << 8) + feature[1]); + public static string Prettify_0000(Feature_0000? feature) + { + if(!feature.HasValue) + return null; - if(number != 0x010B) - return null; + Feature_0000 ftr = feature.Value; + var sb = new StringBuilder(); - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_010B(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.CPRMVersion = feature[7]; - - return decoded; - } - - public static Feature_010C? Decode_010C(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 20) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x010C) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_010C(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.Century = (ushort)((feature[4] << 8) + feature[5]); - decoded.Year = (ushort)((feature[6] << 8) + feature[7]); - decoded.Month = (ushort)((feature[8] << 8) + feature[9]); - decoded.Day = (ushort)((feature[10] << 8) + feature[11]); - decoded.Hour = (ushort)((feature[12] << 8) + feature[13]); - decoded.Minute = (ushort)((feature[14] << 8) + feature[15]); - decoded.Second = (ushort)((feature[16] << 8) + feature[17]); - - return decoded; - } - - public static Feature_010D? Decode_010D(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x010D) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_010D(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.BNG |= (feature[4] & 0x01) == 0x01; - decoded.BindNonceBlocks = feature[5]; - decoded.AGIDs = (byte)(feature[6] & 0x0F); - decoded.AACSVersion = feature[7]; - - if(decoded.Version < 2) - return decoded; - - decoded.RDC |= (feature[4] & 0x10) == 0x10; - decoded.RMC |= (feature[4] & 0x08) == 0x08; - decoded.WBE |= (feature[4] & 0x04) == 0x04; - decoded.BEC |= (feature[4] & 0x02) == 0x02; - - return decoded; - } - - public static Feature_010E? Decode_010E(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x010E) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_010E(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.MaxScrambleExtent = feature[4]; - - return decoded; - } - - public static Feature_0110? Decode_0110(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 8) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0110) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0110(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0113? Decode_0113(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 4) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0113) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0113(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - return decoded; - } - - public static Feature_0142? Decode_0142(byte[] feature) - { - if(feature == null) - return null; - - if(feature.Length < 6) - return null; - - ushort number = (ushort)((feature[0] << 8) + feature[1]); - - if(number != 0x0142) - return null; - - if(feature[3] + 4 != feature.Length) - return null; - - var decoded = new Feature_0142(); - - decoded.Current |= (feature[2] & 0x01) == 0x01; - decoded.Persistent |= (feature[2] & 0x02) == 0x02; - decoded.Version = (byte)((feature[2] & 0x3C) >> 2); - - decoded.PSAU |= (feature[4] & 0x80) == 0x80; - decoded.LOSPB |= (feature[4] & 0x40) == 0x40; - decoded.ME |= (feature[4] & 0x01) == 0x01; - decoded.Profiles = new ushort[feature[5]]; - - if((feature[5] * 2) + 6 != feature.Length) - return decoded; - - for(int i = 0; i < feature[5]; i++) - decoded.Profiles[i] = (ushort)((feature[0 + 6 + (2 * i)] << 8) + feature[1 + 6 + (2 * i)]); - - return decoded; - } - - public static string Prettify_0000(Feature_0000? feature) - { - if(!feature.HasValue) - return null; - - Feature_0000 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Supported Profiles:"); - - if(ftr.Profiles == null) - return sb.ToString(); - - foreach(Profile prof in ftr.Profiles) - { - switch(prof.Number) - { - case ProfileNumber.Reserved: - sb.Append("\tDrive reported a reserved profile number"); - - break; - case ProfileNumber.NonRemovable: - sb.Append("\tDrive supports non-removable changeable media"); - - break; - case ProfileNumber.Removable: - sb.Append("\tDrive supports rewritable and removable media"); - - break; - case ProfileNumber.MOErasable: - sb.Append("\tDrive supports Magnet-Optical media"); - - break; - case ProfileNumber.OpticalWORM: - sb.Append("\tDrive supports optical write-once media"); - - break; - case ProfileNumber.ASMO: - sb.Append("\tDrive supports Advanced Storage - Magneto-Optical"); - - break; - case ProfileNumber.CDROM: - sb.Append("\tDrive supports CD-ROM"); - - break; - case ProfileNumber.CDR: - sb.Append("\tDrive supports CD-R"); - - break; - case ProfileNumber.CDRW: - sb.Append("\tDrive supports CD-RW"); - - break; - case ProfileNumber.DVDROM: - sb.Append("\tDrive supports DVD-ROM"); - - break; - case ProfileNumber.DVDRSeq: - sb.Append("\tDrive supports DVD-R"); - - break; - case ProfileNumber.DVDRAM: - sb.Append("\tDrive supports DVD-RAM"); - - break; - case ProfileNumber.DVDRWRes: - sb.Append("\tDrive supports restricted overwrite DVD-RW"); - - break; - case ProfileNumber.DVDRWSeq: - sb.Append("\tDrive supports sequentially recorded DVD-RW"); - - break; - case ProfileNumber.DVDRDLSeq: - sb.Append("\tDrive supports sequentially recorded DVD-R DL"); - - break; - case ProfileNumber.DVDRDLJump: - sb.Append("\tDrive supports layer jump recorded DVD-R DL"); - - break; - case ProfileNumber.DVDRWDL: - sb.Append("\tDrive supports DVD-RW DL"); - - break; - case ProfileNumber.DVDDownload: - sb.Append("\tDrive supports DVD-Download"); - - break; - case ProfileNumber.DVDRWPlus: - sb.Append("\tDrive supports DVD+RW"); - - break; - case ProfileNumber.DVDRPlus: - sb.Append("\tDrive supports DVD+R"); - - break; - case ProfileNumber.DDCDROM: - sb.Append("\tDrive supports DDCD-ROM"); - - break; - case ProfileNumber.DDCDR: - sb.Append("\tDrive supports DDCD-R"); - - break; - case ProfileNumber.DDCDRW: - sb.Append("\tDrive supports DDCD-RW"); - - break; - case ProfileNumber.DVDRWDLPlus: - sb.Append("\tDrive supports DVD+RW DL"); - - break; - case ProfileNumber.DVDRDLPlus: - sb.Append("\tDrive supports DVD+R DL"); - - break; - case ProfileNumber.BDROM: - sb.Append("\tDrive supports BD-ROM"); - - break; - case ProfileNumber.BDRSeq: - sb.Append("\tDrive supports BD-R SRM"); - - break; - case ProfileNumber.BDRRdm: - sb.Append("\tDrive supports BD-R RRM"); - - break; - case ProfileNumber.BDRE: - sb.Append("\tDrive supports BD-RE"); - - break; - case ProfileNumber.HDDVDROM: - sb.Append("\tDrive supports HD DVD-ROM"); - - break; - case ProfileNumber.HDDVDR: - sb.Append("\tDrive supports HD DVD-R"); - - break; - case ProfileNumber.HDDVDRAM: - sb.Append("\tDrive supports HD DVD-RAM"); - - break; - case ProfileNumber.HDDVDRW: - sb.Append("\tDrive supports HD DVD-RW"); - - break; - case ProfileNumber.HDDVDRDL: - sb.Append("\tDrive supports HD DVD-R DL"); - - break; - case ProfileNumber.HDDVDRWDL: - sb.Append("\tDrive supports HD DVD-RW DL"); - - break; - case ProfileNumber.HDBURNROM: - sb.Append("\tDrive supports HDBurn CD-ROM"); - - break; - case ProfileNumber.HDBURNR: - sb.Append("\tDrive supports HDBurn CD-R"); - - break; - case ProfileNumber.HDBURNRW: - sb.Append("\tDrive supports HDBurn CD-RW"); - - break; - case ProfileNumber.Unconforming: - sb.Append("\tDrive is not conforming to any profile"); - - break; - default: - sb.AppendFormat("\tDrive informs of unknown profile 0x{0:X4}", (ushort)prof.Number); - - break; - } - - if(prof.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - } + sb.AppendLine("MMC Supported Profiles:"); + if(ftr.Profiles == null) return sb.ToString(); - } - public static string Prettify_0001(Feature_0001? feature) + foreach(Profile prof in ftr.Profiles) { - if(!feature.HasValue) - return null; - - Feature_0001 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Core Feature:"); - sb.Append("\tDrive uses "); - - switch(ftr.PhysicalInterfaceStandard) + switch(prof.Number) { - case PhysicalInterfaces.Unspecified: - sb.AppendLine("an unspecified physical interface"); + case ProfileNumber.Reserved: + sb.Append("\tDrive reported a reserved profile number"); break; - case PhysicalInterfaces.SCSI: - sb.AppendLine("SCSI interface"); + case ProfileNumber.NonRemovable: + sb.Append("\tDrive supports non-removable changeable media"); break; - case PhysicalInterfaces.ATAPI: - sb.AppendLine("ATAPI interface"); + case ProfileNumber.Removable: + sb.Append("\tDrive supports rewritable and removable media"); break; - case PhysicalInterfaces.IEEE1394: - sb.AppendLine("IEEE-1394 interface"); + case ProfileNumber.MOErasable: + sb.Append("\tDrive supports Magnet-Optical media"); break; - case PhysicalInterfaces.IEEE1394A: - sb.AppendLine("IEEE-1394A interface"); + case ProfileNumber.OpticalWORM: + sb.Append("\tDrive supports optical write-once media"); break; - case PhysicalInterfaces.FC: - sb.AppendLine("Fibre Channel interface"); + case ProfileNumber.ASMO: + sb.Append("\tDrive supports Advanced Storage - Magneto-Optical"); break; - case PhysicalInterfaces.IEEE1394B: - sb.AppendLine("IEEE-1394B interface"); + case ProfileNumber.CDROM: + sb.Append("\tDrive supports CD-ROM"); break; - case PhysicalInterfaces.SerialATAPI: - sb.AppendLine("Serial ATAPI interface"); + case ProfileNumber.CDR: + sb.Append("\tDrive supports CD-R"); break; - case PhysicalInterfaces.USB: - sb.AppendLine("USB interface"); + case ProfileNumber.CDRW: + sb.Append("\tDrive supports CD-RW"); break; - case PhysicalInterfaces.Vendor: - sb.AppendLine("a vendor unique interface"); + case ProfileNumber.DVDROM: + sb.Append("\tDrive supports DVD-ROM"); + + break; + case ProfileNumber.DVDRSeq: + sb.Append("\tDrive supports DVD-R"); + + break; + case ProfileNumber.DVDRAM: + sb.Append("\tDrive supports DVD-RAM"); + + break; + case ProfileNumber.DVDRWRes: + sb.Append("\tDrive supports restricted overwrite DVD-RW"); + + break; + case ProfileNumber.DVDRWSeq: + sb.Append("\tDrive supports sequentially recorded DVD-RW"); + + break; + case ProfileNumber.DVDRDLSeq: + sb.Append("\tDrive supports sequentially recorded DVD-R DL"); + + break; + case ProfileNumber.DVDRDLJump: + sb.Append("\tDrive supports layer jump recorded DVD-R DL"); + + break; + case ProfileNumber.DVDRWDL: + sb.Append("\tDrive supports DVD-RW DL"); + + break; + case ProfileNumber.DVDDownload: + sb.Append("\tDrive supports DVD-Download"); + + break; + case ProfileNumber.DVDRWPlus: + sb.Append("\tDrive supports DVD+RW"); + + break; + case ProfileNumber.DVDRPlus: + sb.Append("\tDrive supports DVD+R"); + + break; + case ProfileNumber.DDCDROM: + sb.Append("\tDrive supports DDCD-ROM"); + + break; + case ProfileNumber.DDCDR: + sb.Append("\tDrive supports DDCD-R"); + + break; + case ProfileNumber.DDCDRW: + sb.Append("\tDrive supports DDCD-RW"); + + break; + case ProfileNumber.DVDRWDLPlus: + sb.Append("\tDrive supports DVD+RW DL"); + + break; + case ProfileNumber.DVDRDLPlus: + sb.Append("\tDrive supports DVD+R DL"); + + break; + case ProfileNumber.BDROM: + sb.Append("\tDrive supports BD-ROM"); + + break; + case ProfileNumber.BDRSeq: + sb.Append("\tDrive supports BD-R SRM"); + + break; + case ProfileNumber.BDRRdm: + sb.Append("\tDrive supports BD-R RRM"); + + break; + case ProfileNumber.BDRE: + sb.Append("\tDrive supports BD-RE"); + + break; + case ProfileNumber.HDDVDROM: + sb.Append("\tDrive supports HD DVD-ROM"); + + break; + case ProfileNumber.HDDVDR: + sb.Append("\tDrive supports HD DVD-R"); + + break; + case ProfileNumber.HDDVDRAM: + sb.Append("\tDrive supports HD DVD-RAM"); + + break; + case ProfileNumber.HDDVDRW: + sb.Append("\tDrive supports HD DVD-RW"); + + break; + case ProfileNumber.HDDVDRDL: + sb.Append("\tDrive supports HD DVD-R DL"); + + break; + case ProfileNumber.HDDVDRWDL: + sb.Append("\tDrive supports HD DVD-RW DL"); + + break; + case ProfileNumber.HDBURNROM: + sb.Append("\tDrive supports HDBurn CD-ROM"); + + break; + case ProfileNumber.HDBURNR: + sb.Append("\tDrive supports HDBurn CD-R"); + + break; + case ProfileNumber.HDBURNRW: + sb.Append("\tDrive supports HDBurn CD-RW"); + + break; + case ProfileNumber.Unconforming: + sb.Append("\tDrive is not conforming to any profile"); break; default: - sb.AppendFormat("an unknown interface with code {0}", (uint)ftr.PhysicalInterfaceStandard). - AppendLine(); + sb.AppendFormat("\tDrive informs of unknown profile 0x{0:X4}", (ushort)prof.Number); break; } - if(ftr.DBE) - sb.AppendLine("\tDrive supports Device Busy events"); - - if(ftr.INQ2) - sb.AppendLine("\tDrive supports EVPD, Page Code and 16-bit Allocation Length as described in SPC-3"); - - return sb.ToString(); - } - - public static string Prettify_0002(Feature_0002? feature) - { - if(!feature.HasValue) - return null; - - Feature_0002 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Morphing:"); - - sb.AppendLine(ftr.Async ? "\tDrive supports polling and asynchronous GET EVENT STATUS NOTIFICATION" - : "\tDrive supports only polling GET EVENT STATUS NOTIFICATION"); - - if(ftr.OCEvent) - sb.AppendLine("\tDrive supports operational change request / notification class events"); - - return sb.ToString(); - } - - public static string Prettify_0003(Feature_0003? feature) - { - if(!feature.HasValue) - return null; - - Feature_0003 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Removable Medium:"); - - switch(ftr.LoadingMechanismType) - { - 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}", ftr.LoadingMechanismType). - AppendLine(); - - break; - } - - if(ftr.Lock) - sb.AppendLine("\tDrive can lock media"); - - if(ftr.PreventJumper) - sb.AppendLine("\tDrive power ups locked"); - - if(ftr.Eject) - sb.AppendLine("\tDrive can eject media"); - - if(ftr.Load) - sb.AppendLine("\tDrive can load media"); - - if(ftr.DBML) - sb.AppendLine("\tDrive reports Device Busy Class events during medium loading/unloading"); - - return sb.ToString(); - } - - public static string Prettify_0004(Feature_0004? feature) - { - if(!feature.HasValue) - return null; - - Feature_0004 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Write Protect:"); - - if(ftr.DWP) - sb.AppendLine("\tDrive supports reading/writing the Disc Write Protect PAC on BD-R/-RE media"); - - if(ftr.WDCB) - sb.AppendLine("\tDrive supports writing the Write Inhibit DCB on DVD+RW media"); - - if(ftr.SPWP) - sb.AppendLine("\tDrive supports set/release of PWP status"); - - if(ftr.SSWPP) - sb.AppendLine("\tDrive supports the SWPP bit of the Timeout and Protect mode page"); - - return sb.ToString(); - } - - public static string Prettify_0010(Feature_0010? feature) - { - if(!feature.HasValue) - return null; - - Feature_0010 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC Random Readable"); - - if(ftr.Current) - sb.Append(" (current)"); - - sb.AppendLine(":"); - - if(ftr.PP) - sb.AppendLine("\tDrive shall report Read/Write Error Recovery mode page"); - - if(ftr.LogicalBlockSize > 0) - sb.AppendFormat("\t{0} bytes per logical block", ftr.LogicalBlockSize).AppendLine(); - - if(ftr.Blocking > 1) - sb.AppendFormat("\t{0} logical blocks per media readable unit", ftr.Blocking).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_001D(Feature_001D? feature) => - !feature.HasValue ? null - : "Drive claims capability to read all CD formats according to OSTA Multi-Read Specification\n"; - - public static string Prettify_001E(Feature_001E? feature) - { - if(!feature.HasValue) - return null; - - Feature_001E ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC CD Read"); - - if(ftr.Current) - sb.Append(" (current)"); - - sb.AppendLine(":"); - - if(ftr.DAP) - sb.AppendLine("\tDrive supports the DAP bit in the READ CD and READ CD MSF commands"); - - if(ftr.C2) - sb.AppendLine("\tDrive supports C2 Error Pointers"); - - if(ftr.CDText) - sb.AppendLine("\tDrive can return CD-Text from Lead-In"); - - return sb.ToString(); - } - - public static string Prettify_001F(Feature_001F? feature) - { - if(!feature.HasValue) - return null; - - Feature_001F ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC DVD Read"); - - if(ftr.Current) - sb.Append(" (current)"); - - sb.AppendLine(":"); - sb.AppendLine("\tDrive can read DVD media"); - - if(ftr.DualR) - sb.AppendLine("\tDrive can read DVD-R DL from all recording modes"); - - if(ftr.DualRW) - sb.AppendLine("\tDrive can read DVD-RW DL from all recording modes"); - - if(ftr.MULTI110) - sb.AppendLine("\tDrive conforms to DVD Multi Drive Read-only Specifications"); - - return sb.ToString(); - } - - public static string Prettify_0020(Feature_0020? feature) - { - if(!feature.HasValue) - return null; - - Feature_0020 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC Random Writable:"); - - if(ftr.Current) - sb.Append(" (current)"); - - sb.AppendLine(":"); - - if(ftr.PP) - sb.AppendLine("\tDrive shall report Read/Write Error Recovery mode page"); - - if(ftr.LogicalBlockSize > 0) - sb.AppendFormat("\t{0} bytes per logical block", ftr.LogicalBlockSize).AppendLine(); - - if(ftr.Blocking > 1) - sb.AppendFormat("\t{0} logical blocks per media writable unit", ftr.Blocking).AppendLine(); - - if(ftr.LastLBA > 0) - sb.AppendFormat("\tLast adressable logical block is {0}", ftr.LastLBA).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0021(Feature_0021? feature) - { - if(!feature.HasValue) - return null; - - Feature_0021 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Incremental Streaming Writable:"); - - if(ftr.DataTypeSupported > 0) - { - sb.Append("\tDrive supports data block types:"); - - if((ftr.DataTypeSupported & 0x0001) == 0x0001) - sb.Append(" 0"); - - if((ftr.DataTypeSupported & 0x0002) == 0x0002) - sb.Append(" 1"); - - if((ftr.DataTypeSupported & 0x0004) == 0x0004) - sb.Append(" 2"); - - if((ftr.DataTypeSupported & 0x0008) == 0x0008) - sb.Append(" 3"); - - if((ftr.DataTypeSupported & 0x0010) == 0x0010) - sb.Append(" 4"); - - if((ftr.DataTypeSupported & 0x0020) == 0x0020) - sb.Append(" 5"); - - if((ftr.DataTypeSupported & 0x0040) == 0x0040) - sb.Append(" 6"); - - if((ftr.DataTypeSupported & 0x0080) == 0x0080) - sb.Append(" 7"); - - if((ftr.DataTypeSupported & 0x0100) == 0x0100) - sb.Append(" 8"); - - if((ftr.DataTypeSupported & 0x0200) == 0x0200) - sb.Append(" 9"); - - if((ftr.DataTypeSupported & 0x0400) == 0x0400) - sb.Append(" 10"); - - if((ftr.DataTypeSupported & 0x0800) == 0x0800) - sb.Append(" 11"); - - if((ftr.DataTypeSupported & 0x1000) == 0x1000) - sb.Append(" 12"); - - if((ftr.DataTypeSupported & 0x2000) == 0x2000) - sb.Append(" 13"); - - if((ftr.DataTypeSupported & 0x4000) == 0x4000) - sb.Append(" 14"); - - if((ftr.DataTypeSupported & 0x8000) == 0x8000) - sb.Append(" 15"); - - sb.AppendLine(); - } - - if(ftr.TRIO) - sb.AppendLine("\tDrive claims support to report Track Resources Information"); - - if(ftr.ARSV) - sb.AppendLine("\tDrive supports address mode reservation on the RESERVE TRACK command"); - - if(ftr.BUF) - sb.AppendLine("\tDrive is capable of zero loss linking"); - - return sb.ToString(); - } - - public static string Prettify_0022(Feature_0022? feature) => - !feature.HasValue ? null : "Drive supports media that require erasing before writing\n"; - - public static string Prettify_0023(Feature_0023? feature) - { - if(!feature.HasValue) - return null; - - Feature_0023 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Formattable:"); - sb.AppendLine("\tDrive can format media into logical blocks"); - - if(ftr.RENoSA) - sb.AppendLine("\tDrive can format BD-RE with no spares allocated"); - - if(ftr.Expand) - sb.AppendLine("\tDrive can expand the spare area on a formatted BD-RE disc"); - - if(ftr.QCert) - sb.AppendLine("\tDrive can format BD-RE discs with quick certification"); - - if(ftr.Cert) - sb.AppendLine("\tDrive can format BD-RE discs with full certification"); - - if(ftr.FRF) - sb.AppendLine("\tDrive can fast re-format BD-RE discs"); - - if(ftr.RRM) - sb.AppendLine("\tDrive can format BD-R discs with RRM format"); - - return sb.ToString(); - } - - public static string Prettify_0024(Feature_0024? feature) - { - if(!feature.HasValue) - return null; - - Feature_0024 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Hardware Defect Management:"); - sb.AppendLine("\tDrive shall be able to provide a defect-free contiguous address space"); - - if(ftr.SSA) - sb.AppendLine("\tDrive can return Spare Area Information"); - - return sb.ToString(); - } - - public static string Prettify_0025(Feature_0025? feature) - { - if(!feature.HasValue) - return null; - - Feature_0025 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC Write Once"); - - if(ftr.Current) - sb.Append(" (current)"); - - sb.AppendLine(":"); - - if(ftr.PP) - sb.AppendLine("\tDrive shall report Read/Write Error Recovery mode page"); - - if(ftr.LogicalBlockSize > 0) - sb.AppendFormat("\t{0} bytes per logical block", ftr.LogicalBlockSize).AppendLine(); - - if(ftr.Blocking > 1) - sb.AppendFormat("\t{0} logical blocks per media writable unit", ftr.Blocking).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0026(Feature_0026? feature) => - !feature.HasValue ? null - : "Drive shall have the ability to overwrite logical blocks only in fixed sets at a time\n"; - - public static string Prettify_0027(Feature_0027? feature) - { - if(!feature.HasValue) - return null; - - Feature_0027 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("Drive can write High-Speed CD-RW"); - - if(ftr.Current) + if(prof.Current) sb.AppendLine(" (current)"); else sb.AppendLine(); - - return sb.ToString(); } - public static string Prettify_0028(Feature_0028? feature) + return sb.ToString(); + } + + public static string Prettify_0001(Feature_0001? feature) + { + if(!feature.HasValue) + return null; + + Feature_0001 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Core Feature:"); + sb.Append("\tDrive uses "); + + switch(ftr.PhysicalInterfaceStandard) { - if(!feature.HasValue) - return null; + case PhysicalInterfaces.Unspecified: + sb.AppendLine("an unspecified physical interface"); - Feature_0028 ftr = feature.Value; - var sb = new StringBuilder(); + break; + case PhysicalInterfaces.SCSI: + sb.AppendLine("SCSI interface"); - if(ftr.Write && - ftr.DVDPRead && - ftr.DVDPWrite) - sb.Append("Drive can read and write CD-MRW and DVD+MRW"); - else if(ftr.DVDPRead && - ftr.DVDPWrite) - sb.Append("Drive can read and write DVD+MRW"); - else if(ftr.Write && - ftr.DVDPRead) - sb.Append("Drive and read DVD+MRW and read and write CD-MRW"); - else if(ftr.Write) - sb.Append("Drive can read and write CD-MRW"); - else if(ftr.DVDPRead) - sb.Append("Drive can read CD-MRW and DVD+MRW"); - else - sb.Append("Drive can read CD-MRW"); + break; + case PhysicalInterfaces.ATAPI: + sb.AppendLine("ATAPI interface"); - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); + break; + case PhysicalInterfaces.IEEE1394: + sb.AppendLine("IEEE-1394 interface"); - return sb.ToString(); + break; + case PhysicalInterfaces.IEEE1394A: + sb.AppendLine("IEEE-1394A interface"); + + break; + case PhysicalInterfaces.FC: + sb.AppendLine("Fibre Channel interface"); + + break; + case PhysicalInterfaces.IEEE1394B: + sb.AppendLine("IEEE-1394B interface"); + + break; + case PhysicalInterfaces.SerialATAPI: + sb.AppendLine("Serial ATAPI interface"); + + break; + case PhysicalInterfaces.USB: + sb.AppendLine("USB interface"); + + break; + case PhysicalInterfaces.Vendor: + sb.AppendLine("a vendor unique interface"); + + break; + default: + sb.AppendFormat("an unknown interface with code {0}", (uint)ftr.PhysicalInterfaceStandard). + AppendLine(); + + break; } - public static string Prettify_0029(Feature_0029? feature) + if(ftr.DBE) + sb.AppendLine("\tDrive supports Device Busy events"); + + if(ftr.INQ2) + sb.AppendLine("\tDrive supports EVPD, Page Code and 16-bit Allocation Length as described in SPC-3"); + + return sb.ToString(); + } + + public static string Prettify_0002(Feature_0002? feature) + { + if(!feature.HasValue) + return null; + + Feature_0002 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Morphing:"); + + sb.AppendLine(ftr.Async ? "\tDrive supports polling and asynchronous GET EVENT STATUS NOTIFICATION" + : "\tDrive supports only polling GET EVENT STATUS NOTIFICATION"); + + if(ftr.OCEvent) + sb.AppendLine("\tDrive supports operational change request / notification class events"); + + return sb.ToString(); + } + + public static string Prettify_0003(Feature_0003? feature) + { + if(!feature.HasValue) + return null; + + Feature_0003 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Removable Medium:"); + + switch(ftr.LoadingMechanismType) { - if(!feature.HasValue) - return null; + case 0: + sb.AppendLine("\tDrive uses media caddy"); - Feature_0029 ftr = feature.Value; - var sb = new StringBuilder(); + break; + case 1: + sb.AppendLine("\tDrive uses a tray"); - sb.AppendLine("MMC Enhanced Defect Reporting Feature:"); + break; + case 2: + sb.AppendLine("\tDrive is pop-up"); - sb.AppendLine(ftr.DRTDM ? "\tDrive supports DRT-DM mode" : "\tDrive supports Persistent-DM mode"); + break; + case 4: + sb.AppendLine("\tDrive is a changer with individually changeable discs"); - if(ftr.DBICacheZones > 0) - sb.AppendFormat("\tDrive has {0} DBI cache zones", ftr.DBICacheZones).AppendLine(); + break; + case 5: + sb.AppendLine("\tDrive is a changer using cartridges"); - if(ftr.Entries > 0) - sb.AppendFormat("\tDrive has {0} DBI entries", ftr.Entries).AppendLine(); + break; + default: + sb.AppendFormat("\tDrive uses unknown loading mechanism type {0}", ftr.LoadingMechanismType). + AppendLine(); - return sb.ToString(); + break; } - public static string Prettify_002A(Feature_002A? feature) + if(ftr.Lock) + sb.AppendLine("\tDrive can lock media"); + + if(ftr.PreventJumper) + sb.AppendLine("\tDrive power ups locked"); + + if(ftr.Eject) + sb.AppendLine("\tDrive can eject media"); + + if(ftr.Load) + sb.AppendLine("\tDrive can load media"); + + if(ftr.DBML) + sb.AppendLine("\tDrive reports Device Busy Class events during medium loading/unloading"); + + return sb.ToString(); + } + + public static string Prettify_0004(Feature_0004? feature) + { + if(!feature.HasValue) + return null; + + Feature_0004 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Write Protect:"); + + if(ftr.DWP) + sb.AppendLine("\tDrive supports reading/writing the Disc Write Protect PAC on BD-R/-RE media"); + + if(ftr.WDCB) + sb.AppendLine("\tDrive supports writing the Write Inhibit DCB on DVD+RW media"); + + if(ftr.SPWP) + sb.AppendLine("\tDrive supports set/release of PWP status"); + + if(ftr.SSWPP) + sb.AppendLine("\tDrive supports the SWPP bit of the Timeout and Protect mode page"); + + return sb.ToString(); + } + + public static string Prettify_0010(Feature_0010? feature) + { + if(!feature.HasValue) + return null; + + Feature_0010 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("MMC Random Readable"); + + if(ftr.Current) + sb.Append(" (current)"); + + sb.AppendLine(":"); + + if(ftr.PP) + sb.AppendLine("\tDrive shall report Read/Write Error Recovery mode page"); + + if(ftr.LogicalBlockSize > 0) + sb.AppendFormat("\t{0} bytes per logical block", ftr.LogicalBlockSize).AppendLine(); + + if(ftr.Blocking > 1) + sb.AppendFormat("\t{0} logical blocks per media readable unit", ftr.Blocking).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_001D(Feature_001D? feature) => + !feature.HasValue ? null + : "Drive claims capability to read all CD formats according to OSTA Multi-Read Specification\n"; + + public static string Prettify_001E(Feature_001E? feature) + { + if(!feature.HasValue) + return null; + + Feature_001E ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("MMC CD Read"); + + if(ftr.Current) + sb.Append(" (current)"); + + sb.AppendLine(":"); + + if(ftr.DAP) + sb.AppendLine("\tDrive supports the DAP bit in the READ CD and READ CD MSF commands"); + + if(ftr.C2) + sb.AppendLine("\tDrive supports C2 Error Pointers"); + + if(ftr.CDText) + sb.AppendLine("\tDrive can return CD-Text from Lead-In"); + + return sb.ToString(); + } + + public static string Prettify_001F(Feature_001F? feature) + { + if(!feature.HasValue) + return null; + + Feature_001F ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("MMC DVD Read"); + + if(ftr.Current) + sb.Append(" (current)"); + + sb.AppendLine(":"); + sb.AppendLine("\tDrive can read DVD media"); + + if(ftr.DualR) + sb.AppendLine("\tDrive can read DVD-R DL from all recording modes"); + + if(ftr.DualRW) + sb.AppendLine("\tDrive can read DVD-RW DL from all recording modes"); + + if(ftr.MULTI110) + sb.AppendLine("\tDrive conforms to DVD Multi Drive Read-only Specifications"); + + return sb.ToString(); + } + + public static string Prettify_0020(Feature_0020? feature) + { + if(!feature.HasValue) + return null; + + Feature_0020 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("MMC Random Writable:"); + + if(ftr.Current) + sb.Append(" (current)"); + + sb.AppendLine(":"); + + if(ftr.PP) + sb.AppendLine("\tDrive shall report Read/Write Error Recovery mode page"); + + if(ftr.LogicalBlockSize > 0) + sb.AppendFormat("\t{0} bytes per logical block", ftr.LogicalBlockSize).AppendLine(); + + if(ftr.Blocking > 1) + sb.AppendFormat("\t{0} logical blocks per media writable unit", ftr.Blocking).AppendLine(); + + if(ftr.LastLBA > 0) + sb.AppendFormat("\tLast adressable logical block is {0}", ftr.LastLBA).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0021(Feature_0021? feature) + { + if(!feature.HasValue) + return null; + + Feature_0021 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Incremental Streaming Writable:"); + + if(ftr.DataTypeSupported > 0) { - if(!feature.HasValue) - return null; - - Feature_002A ftr = feature.Value; - var sb = new StringBuilder(); - - if(ftr.Write) - { - sb.Append("Drive can read and write DVD+RW"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - - sb.AppendLine(ftr.CloseOnly ? "\tDrive supports only the read compatibility stop" - : "\tDrive supports both forms of background format stopping"); - - if(ftr.QuickStart) - sb.AppendLine("\tDrive can do a quick start formatting"); - } - else - { - sb.Append("Drive can read DVD+RW"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - } - - return sb.ToString(); - } - - public static string Prettify_002B(Feature_002B? feature) - { - if(!feature.HasValue) - return null; - - Feature_002B ftr = feature.Value; - var sb = new StringBuilder(); - - if(ftr.Write) - { - sb.Append("Drive can read and write DVD+R"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - } - else - { - sb.Append("Drive can read DVD+R"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - } - - return sb.ToString(); - } - - public static string Prettify_002C(Feature_002C? feature) - { - if(!feature.HasValue) - return null; - - Feature_002C ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC Rigid Restricted Overwrite"); - sb.AppendLine(ftr.Current ? " (current):" : ":"); - - if(ftr.Blank) - sb.AppendLine("\tDrive supports the BLANK command"); - - if(ftr.Intermediate) - sb.AppendLine("\tDrive supports writing on an intermediate state session and quick formatting"); - - if(ftr.DSDR) - sb.AppendLine("\tDrive can read Defect Status data recorded on the medium"); - - if(ftr.DSDG) - sb.AppendLine("\tDrive can generate Defect Status data during formatting"); - - return sb.ToString(); - } - - public static string Prettify_002D(Feature_002D? feature) - { - if(!feature.HasValue) - return null; - - Feature_002D ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Drive can write CDs in Track at Once Mode:"); - - if(ftr.RWSubchannel) - { - sb.AppendLine("\tDrive can write user provided data in the R-W subchannels"); - - if(ftr.RWRaw) - sb.AppendLine("\tDrive accepts RAW R-W subchannel data"); - - if(ftr.RWPack) - sb.AppendLine("\tDrive accepts Packed R-W subchannel data"); - } - - if(ftr.CDRW) - sb.AppendLine("\tDrive can overwrite a TAO track with another in CD-RWs"); - - if(ftr.TestWrite) - sb.AppendLine("\tDrive can do a test writing"); - - if(ftr.BUF) - sb.AppendLine("\tDrive supports zero loss linking"); - - if(ftr.DataTypeSupported <= 0) - return sb.ToString(); - sb.Append("\tDrive supports data block types:"); if((ftr.DataTypeSupported & 0x0001) == 0x0001) @@ -3958,936 +3613,1280 @@ namespace Aaru.Decoders.SCSI.MMC sb.Append(" 15"); sb.AppendLine(); - - return sb.ToString(); } - public static string Prettify_002E(Feature_002E? feature) - { - if(!feature.HasValue) - return null; + if(ftr.TRIO) + sb.AppendLine("\tDrive claims support to report Track Resources Information"); - Feature_002E ftr = feature.Value; - var sb = new StringBuilder(); + if(ftr.ARSV) + sb.AppendLine("\tDrive supports address mode reservation on the RESERVE TRACK command"); - if(ftr.SAO && - !ftr.RAW) - sb.AppendLine("Drive can write CDs in Session at Once Mode:"); - else if(!ftr.SAO && - ftr.RAW) - sb.AppendLine("Drive can write CDs in raw Mode:"); - else - sb.AppendLine("Drive can write CDs in Session at Once and in Raw Modes:"); + if(ftr.BUF) + sb.AppendLine("\tDrive is capable of zero loss linking"); - if(ftr.RAW && - ftr.RAWMS) - sb.AppendLine("\tDrive can write multi-session CDs in raw mode"); + return sb.ToString(); + } - if(ftr.RW) - sb.AppendLine("\tDrive can write user provided data in the R-W subchannels"); + public static string Prettify_0022(Feature_0022? feature) => + !feature.HasValue ? null : "Drive supports media that require erasing before writing\n"; - if(ftr.CDRW) - sb.AppendLine("\tDrive can write CD-RWs"); + public static string Prettify_0023(Feature_0023? feature) + { + if(!feature.HasValue) + return null; - if(ftr.TestWrite) - sb.AppendLine("\tDrive can do a test writing"); + Feature_0023 ftr = feature.Value; + var sb = new StringBuilder(); - if(ftr.BUF) - sb.AppendLine("\tDrive supports zero loss linking"); + sb.AppendLine("MMC Formattable:"); + sb.AppendLine("\tDrive can format media into logical blocks"); - if(ftr.MaxCueSheet > 0) - sb.AppendFormat("\tDrive supports a maximum of {0} bytes in a single cue sheet", ftr.MaxCueSheet). - AppendLine(); + if(ftr.RENoSA) + sb.AppendLine("\tDrive can format BD-RE with no spares allocated"); - return sb.ToString(); - } + if(ftr.Expand) + sb.AppendLine("\tDrive can expand the spare area on a formatted BD-RE disc"); - public static string Prettify_002F(Feature_002F? feature) - { - if(!feature.HasValue) - return null; + if(ftr.QCert) + sb.AppendLine("\tDrive can format BD-RE discs with quick certification"); - Feature_002F ftr = feature.Value; - var sb = new StringBuilder(); + if(ftr.Cert) + sb.AppendLine("\tDrive can format BD-RE discs with full certification"); - if(ftr.DVDRW && - ftr.RDL) - sb.AppendLine("Drive supports writing DVD-R, DVD-RW and DVD-R DL"); - else if(ftr.RDL) - sb.AppendLine("Drive supports writing DVD-R and DVD-R DL"); - else if(ftr.DVDRW) - sb.AppendLine("Drive supports writing DVD-R and DVD-RW"); - else - sb.AppendLine("Drive supports writing DVD-R"); + if(ftr.FRF) + sb.AppendLine("\tDrive can fast re-format BD-RE discs"); - if(ftr.TestWrite) - sb.AppendLine("\tDrive can do a test writing"); + if(ftr.RRM) + sb.AppendLine("\tDrive can format BD-R discs with RRM format"); - if(ftr.BUF) - sb.AppendLine("\tDrive supports zero loss linking"); + return sb.ToString(); + } - return sb.ToString(); - } + public static string Prettify_0024(Feature_0024? feature) + { + if(!feature.HasValue) + return null; - public static string Prettify_0030(Feature_0030? feature) => - !feature.HasValue ? null : "Drive can read DDCDs\n"; + Feature_0024 ftr = feature.Value; + var sb = new StringBuilder(); - public static string Prettify_0031(Feature_0031? feature) - { - if(!feature.HasValue) - return null; + sb.AppendLine("MMC Hardware Defect Management:"); + sb.AppendLine("\tDrive shall be able to provide a defect-free contiguous address space"); - Feature_0031 ftr = feature.Value; - var sb = new StringBuilder(); + if(ftr.SSA) + sb.AppendLine("\tDrive can return Spare Area Information"); - sb.AppendLine("Drive supports writing DDCD-R"); + return sb.ToString(); + } - if(ftr.TestWrite) - sb.AppendLine("\tDrive can do a test writing"); + public static string Prettify_0025(Feature_0025? feature) + { + if(!feature.HasValue) + return null; - return sb.ToString(); - } + Feature_0025 ftr = feature.Value; + var sb = new StringBuilder(); - public static string Prettify_0032(Feature_0032? feature) - { - if(!feature.HasValue) - return null; + sb.Append("MMC Write Once"); - Feature_0032 ftr = feature.Value; - var sb = new StringBuilder(); + if(ftr.Current) + sb.Append(" (current)"); - sb.AppendLine("Drive supports writing DDCD-RW"); + sb.AppendLine(":"); - if(ftr.Blank) - sb.AppendLine("\tDrive supports the BLANK command"); + if(ftr.PP) + sb.AppendLine("\tDrive shall report Read/Write Error Recovery mode page"); - if(ftr.Intermediate) - sb.AppendLine("\tDrive supports quick formatting"); + if(ftr.LogicalBlockSize > 0) + sb.AppendFormat("\t{0} bytes per logical block", ftr.LogicalBlockSize).AppendLine(); - return sb.ToString(); - } + if(ftr.Blocking > 1) + sb.AppendFormat("\t{0} logical blocks per media writable unit", ftr.Blocking).AppendLine(); - public static string Prettify_0033(Feature_0033? feature) - { - if(!feature.HasValue) - return null; + return sb.ToString(); + } - Feature_0033 ftr = feature.Value; - var sb = new StringBuilder(); + public static string Prettify_0026(Feature_0026? feature) => + !feature.HasValue ? null + : "Drive shall have the ability to overwrite logical blocks only in fixed sets at a time\n"; - sb.AppendLine("MMC Layer Jump Recording:"); + public static string Prettify_0027(Feature_0027? feature) + { + if(!feature.HasValue) + return null; - if(ftr.LinkSizes == null) - return sb.ToString(); + Feature_0027 ftr = feature.Value; + var sb = new StringBuilder(); - foreach(byte link in ftr.LinkSizes) - sb.AppendFormat("\tCurrent media has a {0} bytes link available", link).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0035(Feature_0035? feature) => - !feature.HasValue ? null : "Drive can stop a long immediate operation\n"; - - public static string Prettify_0037(Feature_0037? feature) - { - if(!feature.HasValue) - return null; - - Feature_0037 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Drive can write CD-RW"); - - if(ftr.SubtypeSupport <= 0) - return sb.ToString(); - - sb.Append("\tDrive supports CD-RW subtypes"); - - if((ftr.SubtypeSupport & 0x01) == 0x01) - sb.Append(" 0"); - - if((ftr.SubtypeSupport & 0x02) == 0x02) - sb.Append(" 1"); - - if((ftr.SubtypeSupport & 0x04) == 0x04) - sb.Append(" 2"); - - if((ftr.SubtypeSupport & 0x08) == 0x08) - sb.Append(" 3"); - - if((ftr.SubtypeSupport & 0x10) == 0x10) - sb.Append(" 4"); - - if((ftr.SubtypeSupport & 0x20) == 0x20) - sb.Append(" 5"); - - if((ftr.SubtypeSupport & 0x40) == 0x40) - sb.Append(" 6"); - - if((ftr.SubtypeSupport & 0x80) == 0x80) - sb.Append(" 7"); + sb.Append("Drive can write High-Speed CD-RW"); + if(ftr.Current) + sb.AppendLine(" (current)"); + else sb.AppendLine(); - return sb.ToString(); - } + return sb.ToString(); + } - public static string Prettify_0038(Feature_0038? feature) => - !feature.HasValue ? null : "Drive can write BD-R on Pseudo-OVerwrite SRM mode\n"; + public static string Prettify_0028(Feature_0028? feature) + { + if(!feature.HasValue) + return null; - public static string Prettify_003A(Feature_003A? feature) + Feature_0028 ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write && + ftr.DVDPRead && + ftr.DVDPWrite) + sb.Append("Drive can read and write CD-MRW and DVD+MRW"); + else if(ftr.DVDPRead && + ftr.DVDPWrite) + sb.Append("Drive can read and write DVD+MRW"); + else if(ftr.Write && + ftr.DVDPRead) + sb.Append("Drive and read DVD+MRW and read and write CD-MRW"); + else if(ftr.Write) + sb.Append("Drive can read and write CD-MRW"); + else if(ftr.DVDPRead) + sb.Append("Drive can read CD-MRW and DVD+MRW"); + else + sb.Append("Drive can read CD-MRW"); + + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0029(Feature_0029? feature) + { + if(!feature.HasValue) + return null; + + Feature_0029 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Enhanced Defect Reporting Feature:"); + + sb.AppendLine(ftr.DRTDM ? "\tDrive supports DRT-DM mode" : "\tDrive supports Persistent-DM mode"); + + if(ftr.DBICacheZones > 0) + sb.AppendFormat("\tDrive has {0} DBI cache zones", ftr.DBICacheZones).AppendLine(); + + if(ftr.Entries > 0) + sb.AppendFormat("\tDrive has {0} DBI entries", ftr.Entries).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_002A(Feature_002A? feature) + { + if(!feature.HasValue) + return null; + + Feature_002A ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) { - if(!feature.HasValue) - return null; - - Feature_003A ftr = feature.Value; - var sb = new StringBuilder(); - - if(ftr.Write) - { - sb.Append("Drive can read and write DVD+RW DL"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - - sb.AppendLine(ftr.CloseOnly ? "\tDrive supports only the read compatibility stop" - : "\tDrive supports both forms of background format stopping"); - - if(ftr.QuickStart) - sb.AppendLine("\tDrive can do a quick start formatting"); - } - else - { - sb.Append("Drive can read DVD+RW DL"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - } - - return sb.ToString(); - } - - public static string Prettify_003B(Feature_003B? feature) - { - if(!feature.HasValue) - return null; - - Feature_003B ftr = feature.Value; - var sb = new StringBuilder(); - - if(ftr.Write) - { - sb.Append("Drive can read and write DVD+R DL"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - } - else - { - sb.Append("Drive can read DVD+R DL"); - - if(ftr.Current) - sb.AppendLine(" (current)"); - else - sb.AppendLine(); - } - - return sb.ToString(); - } - - public static string Prettify_0040(Feature_0040? feature) - { - if(!feature.HasValue) - return null; - - Feature_0040 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC BD Read"); - sb.AppendLine(ftr.Current ? " (current):" : ":"); - - if(ftr.OldROM) - sb.AppendLine("\tDrive can read BD-ROM pre-1.0"); - - if(ftr.ROM) - sb.AppendLine("\tDrive can read BD-ROM Ver.1"); - - if(ftr.OldR) - sb.AppendLine("\tDrive can read BD-R pre-1.0"); - - if(ftr.R) - sb.AppendLine("\tDrive can read BD-R Ver.1"); - - if(ftr.OldRE) - sb.AppendLine("\tDrive can read BD-RE pre-1.0"); - - if(ftr.RE1) - sb.AppendLine("\tDrive can read BD-RE Ver.1"); - - if(ftr.RE2) - sb.AppendLine("\tDrive can read BD-RE Ver.2"); - - if(ftr.BCA) - sb.AppendLine("\tDrive can read BD's Burst Cutting Area"); - - return sb.ToString(); - } - - public static string Prettify_0041(Feature_0041? feature) - { - if(!feature.HasValue) - return null; - - Feature_0041 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("MMC BD Write"); - sb.AppendLine(ftr.Current ? " (current):" : ":"); - - if(ftr.OldR) - sb.AppendLine("\tDrive can write BD-R pre-1.0"); - - if(ftr.R) - sb.AppendLine("\tDrive can write BD-R Ver.1"); - - if(ftr.OldRE) - sb.AppendLine("\tDrive can write BD-RE pre-1.0"); - - if(ftr.RE1) - sb.AppendLine("\tDrive can write BD-RE Ver.1"); - - if(ftr.RE2) - sb.AppendLine("\tDrive can write BD-RE Ver.2"); - - if(ftr.SVNR) - sb.AppendLine("\tDrive supports write without verify requirement"); - - return sb.ToString(); - } - - public static string Prettify_0042(Feature_0042? feature) => - !feature.HasValue ? null - : "Drive is able to detect and report defective writable unit and behave accordinly\n"; - - public static string Prettify_0050(Feature_0050? feature) - { - if(!feature.HasValue) - return null; - - Feature_0050 ftr = feature.Value; - var sb = new StringBuilder(); - - if(ftr.HDDVDR && - ftr.HDDVDRAM) - sb.Append("Drive can read HD DVD-ROM, HD DVD-RW, HD DVD-R and HD DVD-RAM"); - else if(ftr.HDDVDR) - sb.Append("Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-R"); - else if(ftr.HDDVDRAM) - sb.Append("Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-RAM"); - else - sb.Append("Drive can read HD DVD-ROM and HD DVD-RW"); + sb.Append("Drive can read and write DVD+RW"); if(ftr.Current) sb.AppendLine(" (current)"); else sb.AppendLine(); - return sb.ToString(); + sb.AppendLine(ftr.CloseOnly ? "\tDrive supports only the read compatibility stop" + : "\tDrive supports both forms of background format stopping"); + + if(ftr.QuickStart) + sb.AppendLine("\tDrive can do a quick start formatting"); + } + else + { + sb.Append("Drive can read DVD+RW"); + + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); } - public static string Prettify_0051(Feature_0051? feature) + return sb.ToString(); + } + + public static string Prettify_002B(Feature_002B? feature) + { + if(!feature.HasValue) + return null; + + Feature_002B ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) { - if(!feature.HasValue) - return null; + sb.Append("Drive can read and write DVD+R"); - Feature_0051 ftr = feature.Value; - var sb = new StringBuilder(); - - if(ftr.HDDVDR && - ftr.HDDVDRAM) - sb.Append("Drive can write HD DVD-RW, HD DVD-R and HD DVD-RAM"); - else if(ftr.HDDVDR) - sb.Append("Drive can write HD DVD-RW and HD DVD-R"); - else if(ftr.HDDVDRAM) - sb.Append("Drive can write HD DVD-RW and HD DVD-RAM"); + if(ftr.Current) + sb.AppendLine(" (current)"); else - sb.Append("Drive can write HD DVD-RW"); + sb.AppendLine(); + } + else + { + sb.Append("Drive can read DVD+R"); + + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_002C(Feature_002C? feature) + { + if(!feature.HasValue) + return null; + + Feature_002C ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("MMC Rigid Restricted Overwrite"); + sb.AppendLine(ftr.Current ? " (current):" : ":"); + + if(ftr.Blank) + sb.AppendLine("\tDrive supports the BLANK command"); + + if(ftr.Intermediate) + sb.AppendLine("\tDrive supports writing on an intermediate state session and quick formatting"); + + if(ftr.DSDR) + sb.AppendLine("\tDrive can read Defect Status data recorded on the medium"); + + if(ftr.DSDG) + sb.AppendLine("\tDrive can generate Defect Status data during formatting"); + + return sb.ToString(); + } + + public static string Prettify_002D(Feature_002D? feature) + { + if(!feature.HasValue) + return null; + + Feature_002D ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive can write CDs in Track at Once Mode:"); + + if(ftr.RWSubchannel) + { + sb.AppendLine("\tDrive can write user provided data in the R-W subchannels"); + + if(ftr.RWRaw) + sb.AppendLine("\tDrive accepts RAW R-W subchannel data"); + + if(ftr.RWPack) + sb.AppendLine("\tDrive accepts Packed R-W subchannel data"); + } + + if(ftr.CDRW) + sb.AppendLine("\tDrive can overwrite a TAO track with another in CD-RWs"); + + if(ftr.TestWrite) + sb.AppendLine("\tDrive can do a test writing"); + + if(ftr.BUF) + sb.AppendLine("\tDrive supports zero loss linking"); + + if(ftr.DataTypeSupported <= 0) + return sb.ToString(); + + sb.Append("\tDrive supports data block types:"); + + if((ftr.DataTypeSupported & 0x0001) == 0x0001) + sb.Append(" 0"); + + if((ftr.DataTypeSupported & 0x0002) == 0x0002) + sb.Append(" 1"); + + if((ftr.DataTypeSupported & 0x0004) == 0x0004) + sb.Append(" 2"); + + if((ftr.DataTypeSupported & 0x0008) == 0x0008) + sb.Append(" 3"); + + if((ftr.DataTypeSupported & 0x0010) == 0x0010) + sb.Append(" 4"); + + if((ftr.DataTypeSupported & 0x0020) == 0x0020) + sb.Append(" 5"); + + if((ftr.DataTypeSupported & 0x0040) == 0x0040) + sb.Append(" 6"); + + if((ftr.DataTypeSupported & 0x0080) == 0x0080) + sb.Append(" 7"); + + if((ftr.DataTypeSupported & 0x0100) == 0x0100) + sb.Append(" 8"); + + if((ftr.DataTypeSupported & 0x0200) == 0x0200) + sb.Append(" 9"); + + if((ftr.DataTypeSupported & 0x0400) == 0x0400) + sb.Append(" 10"); + + if((ftr.DataTypeSupported & 0x0800) == 0x0800) + sb.Append(" 11"); + + if((ftr.DataTypeSupported & 0x1000) == 0x1000) + sb.Append(" 12"); + + if((ftr.DataTypeSupported & 0x2000) == 0x2000) + sb.Append(" 13"); + + if((ftr.DataTypeSupported & 0x4000) == 0x4000) + sb.Append(" 14"); + + if((ftr.DataTypeSupported & 0x8000) == 0x8000) + sb.Append(" 15"); + + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_002E(Feature_002E? feature) + { + if(!feature.HasValue) + return null; + + Feature_002E ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.SAO && + !ftr.RAW) + sb.AppendLine("Drive can write CDs in Session at Once Mode:"); + else if(!ftr.SAO && + ftr.RAW) + sb.AppendLine("Drive can write CDs in raw Mode:"); + else + sb.AppendLine("Drive can write CDs in Session at Once and in Raw Modes:"); + + if(ftr.RAW && + ftr.RAWMS) + sb.AppendLine("\tDrive can write multi-session CDs in raw mode"); + + if(ftr.RW) + sb.AppendLine("\tDrive can write user provided data in the R-W subchannels"); + + if(ftr.CDRW) + sb.AppendLine("\tDrive can write CD-RWs"); + + if(ftr.TestWrite) + sb.AppendLine("\tDrive can do a test writing"); + + if(ftr.BUF) + sb.AppendLine("\tDrive supports zero loss linking"); + + if(ftr.MaxCueSheet > 0) + sb.AppendFormat("\tDrive supports a maximum of {0} bytes in a single cue sheet", ftr.MaxCueSheet). + AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_002F(Feature_002F? feature) + { + if(!feature.HasValue) + return null; + + Feature_002F ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.DVDRW && + ftr.RDL) + sb.AppendLine("Drive supports writing DVD-R, DVD-RW and DVD-R DL"); + else if(ftr.RDL) + sb.AppendLine("Drive supports writing DVD-R and DVD-R DL"); + else if(ftr.DVDRW) + sb.AppendLine("Drive supports writing DVD-R and DVD-RW"); + else + sb.AppendLine("Drive supports writing DVD-R"); + + if(ftr.TestWrite) + sb.AppendLine("\tDrive can do a test writing"); + + if(ftr.BUF) + sb.AppendLine("\tDrive supports zero loss linking"); + + return sb.ToString(); + } + + public static string Prettify_0030(Feature_0030? feature) => + !feature.HasValue ? null : "Drive can read DDCDs\n"; + + public static string Prettify_0031(Feature_0031? feature) + { + if(!feature.HasValue) + return null; + + Feature_0031 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive supports writing DDCD-R"); + + if(ftr.TestWrite) + sb.AppendLine("\tDrive can do a test writing"); + + return sb.ToString(); + } + + public static string Prettify_0032(Feature_0032? feature) + { + if(!feature.HasValue) + return null; + + Feature_0032 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive supports writing DDCD-RW"); + + if(ftr.Blank) + sb.AppendLine("\tDrive supports the BLANK command"); + + if(ftr.Intermediate) + sb.AppendLine("\tDrive supports quick formatting"); + + return sb.ToString(); + } + + public static string Prettify_0033(Feature_0033? feature) + { + if(!feature.HasValue) + return null; + + Feature_0033 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Layer Jump Recording:"); + + if(ftr.LinkSizes == null) + return sb.ToString(); + + foreach(byte link in ftr.LinkSizes) + sb.AppendFormat("\tCurrent media has a {0} bytes link available", link).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0035(Feature_0035? feature) => + !feature.HasValue ? null : "Drive can stop a long immediate operation\n"; + + public static string Prettify_0037(Feature_0037? feature) + { + if(!feature.HasValue) + return null; + + Feature_0037 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive can write CD-RW"); + + if(ftr.SubtypeSupport <= 0) + return sb.ToString(); + + sb.Append("\tDrive supports CD-RW subtypes"); + + if((ftr.SubtypeSupport & 0x01) == 0x01) + sb.Append(" 0"); + + if((ftr.SubtypeSupport & 0x02) == 0x02) + sb.Append(" 1"); + + if((ftr.SubtypeSupport & 0x04) == 0x04) + sb.Append(" 2"); + + if((ftr.SubtypeSupport & 0x08) == 0x08) + sb.Append(" 3"); + + if((ftr.SubtypeSupport & 0x10) == 0x10) + sb.Append(" 4"); + + if((ftr.SubtypeSupport & 0x20) == 0x20) + sb.Append(" 5"); + + if((ftr.SubtypeSupport & 0x40) == 0x40) + sb.Append(" 6"); + + if((ftr.SubtypeSupport & 0x80) == 0x80) + sb.Append(" 7"); + + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0038(Feature_0038? feature) => + !feature.HasValue ? null : "Drive can write BD-R on Pseudo-OVerwrite SRM mode\n"; + + public static string Prettify_003A(Feature_003A? feature) + { + if(!feature.HasValue) + return null; + + Feature_003A ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) + { + sb.Append("Drive can read and write DVD+RW DL"); if(ftr.Current) sb.AppendLine(" (current)"); else sb.AppendLine(); - return sb.ToString(); + sb.AppendLine(ftr.CloseOnly ? "\tDrive supports only the read compatibility stop" + : "\tDrive supports both forms of background format stopping"); + + if(ftr.QuickStart) + sb.AppendLine("\tDrive can do a quick start formatting"); } - - public static string Prettify_0080(Feature_0080? feature) + else { - if(!feature.HasValue) - return null; - - Feature_0080 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("Drive is able to access Hybrid discs"); + sb.Append("Drive can read DVD+RW DL"); if(ftr.Current) sb.AppendLine(" (current)"); else sb.AppendLine(); - - if(ftr.RI) - sb.AppendLine("\tDrive is able to maintain the online format layer through reset and power cycling"); - - return sb.ToString(); } - public static string Prettify_0100(Feature_0100? feature) => - !feature.HasValue ? null : "Drive is able to perform host and drive directed power management\n"; + return sb.ToString(); + } - public static string Prettify_0101(Feature_0101? feature) + public static string Prettify_003B(Feature_003B? feature) + { + if(!feature.HasValue) + return null; + + Feature_003B ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.Write) { - if(!feature.HasValue) - return null; - - Feature_0101 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Drive supports S.M.A.R.T."); - - if(ftr.PP) - sb.AppendLine("\tDrive supports the Informational Exceptions Control mode page 1Ch"); - - return sb.ToString(); - } - - public static string Prettify_0102(Feature_0102? feature) - { - if(!feature.HasValue) - return null; - - Feature_0102 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Embedded Changer:"); - - if(ftr.SCC) - sb.AppendLine("\tDrive can change disc side"); - - if(ftr.SDP) - sb.AppendLine("\tDrive is able to report slots contents after a reset or change"); - - sb.AppendFormat("\tDrive has {0} slots", ftr.HighestSlotNumber + 1).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0103(Feature_0103? feature) - { - if(!feature.HasValue) - return null; - - Feature_0103 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Drive has an analogue audio output"); - - if(ftr.Scan) - sb.AppendLine("\tDrive supports the SCAN command"); - - if(ftr.SCM) - sb.AppendLine("\tDrive is able to mute channels separately"); - - if(ftr.SV) - sb.AppendLine("\tDrive supports separate volume per channel"); - - sb.AppendFormat("\tDrive has {0} volume levels", ftr.VolumeLevels + 1).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0104(Feature_0104? feature) - { - if(!feature.HasValue) - return null; - - Feature_0104 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Drive supports Microcode Upgrade"); - - if(ftr.M5) - sb.AppendLine("Drive supports validating the 5-bit Mode of the READ BUFFER and WRITE BUFFER commands"); - - return sb.ToString(); - } - - public static string Prettify_0105(Feature_0105? feature) - { - if(!feature.HasValue) - return null; - - Feature_0105 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Drive supports Timeout & Protect mode page 1Dh"); - - if(!ftr.Group3) - return sb.ToString(); - - sb.AppendLine("\tDrive supports the Group3 in Timeout & Protect mode page 1Dh"); - - if(ftr.UnitLength > 0) - sb.AppendFormat("\tDrive has {0} increase of Group 3 time unit", ftr.UnitLength).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0106(Feature_0106? feature) - { - if(!feature.HasValue) - return null; - - Feature_0106 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendFormat("Drive supports DVD CSS/CPPM version {0}", ftr.CSSVersion); - - if(ftr.Current) - sb.AppendLine(" and current disc is encrypted"); - else - sb.AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0107(Feature_0107? feature) - { - if(!feature.HasValue) - return null; - - Feature_0107 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("MMC Real Time Streaming:"); - - if(ftr.SMP) - sb.AppendLine("\tDrive supports Set Minimum Performance with the SET STREAMING command"); - - if(ftr.RBCB) - sb.AppendLine("\tDrive supports the block bit in the READ BUFFER CAPACITY command"); - - if(ftr.SCS) - sb.AppendLine("\tDrive supports the SET CD SPEED command"); - - if(ftr.MP2A) - sb.AppendLine("\tDrive supports the Write Speed Performance Descriptor Blocks in the MMC mode page 2Ah"); - - if(ftr.WSPD) - sb.AppendLine("\tDrive supports the Write Speed data of GET PERFORMANCE and the WRC field of SET STREAMING"); - - if(ftr.SW) - sb.AppendLine("\tDrive supports stream recording"); - - return sb.ToString(); - } - - public static string Prettify_0108(Feature_0108? feature) - { - if(!feature.HasValue) - return null; - - Feature_0108 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendFormat("Drive serial number: {0}", ftr.Serial).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0109(Feature_0109? feature) => - !feature.HasValue ? null : "Drive is able to read media serial number\n"; - - public static string Prettify_010A(Feature_010A? feature) - { - if(!feature.HasValue) - return null; - - Feature_010A ftr = feature.Value; - var sb = new StringBuilder(); - - if(ftr.DCBs == null) - return sb.ToString(); - - foreach(uint dcb in ftr.DCBs) - sb.AppendFormat("Drive supports DCB {0:X8}h", dcb).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_010B(Feature_010B? feature) - { - if(!feature.HasValue) - return null; - - Feature_010B ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendFormat("Drive supports DVD CPRM version {0}", ftr.CPRMVersion); - - if(ftr.Current) - sb.AppendLine(" and current disc is or can be encrypted"); - else - sb.AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_010C(Feature_010C? feature) - { - if(!feature.HasValue) - return null; - - Feature_010C ftr = feature.Value; - var sb = new StringBuilder(); - - byte[] temp = new byte[4]; - temp[0] = (byte)((ftr.Century & 0xFF00) >> 8); - temp[1] = (byte)(ftr.Century & 0xFF); - temp[2] = (byte)((ftr.Year & 0xFF00) >> 8); - temp[3] = (byte)(ftr.Year & 0xFF); - string syear = Encoding.ASCII.GetString(temp); - temp = new byte[2]; - temp[0] = (byte)((ftr.Month & 0xFF00) >> 8); - temp[1] = (byte)(ftr.Month & 0xFF); - string smonth = Encoding.ASCII.GetString(temp); - temp = new byte[2]; - temp[0] = (byte)((ftr.Day & 0xFF00) >> 8); - temp[1] = (byte)(ftr.Day & 0xFF); - string sday = Encoding.ASCII.GetString(temp); - temp = new byte[2]; - temp[0] = (byte)((ftr.Hour & 0xFF00) >> 8); - temp[1] = (byte)(ftr.Hour & 0xFF); - string shour = Encoding.ASCII.GetString(temp); - temp = new byte[2]; - temp[0] = (byte)((ftr.Minute & 0xFF00) >> 8); - temp[1] = (byte)(ftr.Minute & 0xFF); - string sminute = Encoding.ASCII.GetString(temp); - temp = new byte[2]; - temp[0] = (byte)((ftr.Second & 0xFF00) >> 8); - temp[1] = (byte)(ftr.Second & 0xFF); - string ssecond = Encoding.ASCII.GetString(temp); - - try - { - var fwDate = new DateTime(int.Parse(syear), int.Parse(smonth), int.Parse(sday), int.Parse(shour), - int.Parse(sminute), int.Parse(ssecond), DateTimeKind.Utc); - - sb.AppendFormat("Drive firmware is dated {0}", fwDate).AppendLine(); - } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body - catch - { - // ignored - } - #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body - - return sb.ToString(); - } - - public static string Prettify_010D(Feature_010D? feature) - { - if(!feature.HasValue) - return null; - - Feature_010D ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendFormat("Drive supports AACS version {0}", ftr.AACSVersion); - - if(ftr.Current) - sb.AppendLine(" and current disc is encrypted"); - else - sb.AppendLine(); - - if(ftr.RDC) - sb.AppendLine("\tDrive supports reading the Drive Certificate"); - - if(ftr.RMC) - sb.AppendLine("\tDrive supports reading Media Key Block of CPRM"); - - if(ftr.WBE) - sb.AppendLine("\tDrive supports writing with bus encryption"); - - if(ftr.BEC) - sb.AppendLine("\tDrive supports bus encryption"); - - if(ftr.BNG) - { - sb.AppendLine("\tDrive supports generating the binding nonce"); - - if(ftr.BindNonceBlocks > 0) - sb.AppendFormat("\t{0} media blocks are required for the binding nonce", ftr.BindNonceBlocks). - AppendLine(); - } - - if(ftr.AGIDs > 0) - sb.AppendFormat("\tDrive supports {0} AGIDs concurrently", ftr.AGIDs).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_010E(Feature_010E? feature) - { - if(!feature.HasValue) - return null; - - Feature_010E ftr = feature.Value; - var sb = new StringBuilder(); - - sb.Append("Drive supports DVD-Download"); + sb.Append("Drive can read and write DVD+R DL"); if(ftr.Current) sb.AppendLine(" (current)"); else sb.AppendLine(); + } + else + { + sb.Append("Drive can read DVD+R DL"); - if(ftr.MaxScrambleExtent > 0) - sb.AppendFormat("\tMaximum {0} scranble extent information entries", ftr.MaxScrambleExtent). + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string Prettify_0040(Feature_0040? feature) + { + if(!feature.HasValue) + return null; + + Feature_0040 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("MMC BD Read"); + sb.AppendLine(ftr.Current ? " (current):" : ":"); + + if(ftr.OldROM) + sb.AppendLine("\tDrive can read BD-ROM pre-1.0"); + + if(ftr.ROM) + sb.AppendLine("\tDrive can read BD-ROM Ver.1"); + + if(ftr.OldR) + sb.AppendLine("\tDrive can read BD-R pre-1.0"); + + if(ftr.R) + sb.AppendLine("\tDrive can read BD-R Ver.1"); + + if(ftr.OldRE) + sb.AppendLine("\tDrive can read BD-RE pre-1.0"); + + if(ftr.RE1) + sb.AppendLine("\tDrive can read BD-RE Ver.1"); + + if(ftr.RE2) + sb.AppendLine("\tDrive can read BD-RE Ver.2"); + + if(ftr.BCA) + sb.AppendLine("\tDrive can read BD's Burst Cutting Area"); + + return sb.ToString(); + } + + public static string Prettify_0041(Feature_0041? feature) + { + if(!feature.HasValue) + return null; + + Feature_0041 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("MMC BD Write"); + sb.AppendLine(ftr.Current ? " (current):" : ":"); + + if(ftr.OldR) + sb.AppendLine("\tDrive can write BD-R pre-1.0"); + + if(ftr.R) + sb.AppendLine("\tDrive can write BD-R Ver.1"); + + if(ftr.OldRE) + sb.AppendLine("\tDrive can write BD-RE pre-1.0"); + + if(ftr.RE1) + sb.AppendLine("\tDrive can write BD-RE Ver.1"); + + if(ftr.RE2) + sb.AppendLine("\tDrive can write BD-RE Ver.2"); + + if(ftr.SVNR) + sb.AppendLine("\tDrive supports write without verify requirement"); + + return sb.ToString(); + } + + public static string Prettify_0042(Feature_0042? feature) => + !feature.HasValue ? null + : "Drive is able to detect and report defective writable unit and behave accordinly\n"; + + public static string Prettify_0050(Feature_0050? feature) + { + if(!feature.HasValue) + return null; + + Feature_0050 ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.HDDVDR && + ftr.HDDVDRAM) + sb.Append("Drive can read HD DVD-ROM, HD DVD-RW, HD DVD-R and HD DVD-RAM"); + else if(ftr.HDDVDR) + sb.Append("Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-R"); + else if(ftr.HDDVDRAM) + sb.Append("Drive can read HD DVD-ROM, HD DVD-RW and HD DVD-RAM"); + else + sb.Append("Drive can read HD DVD-ROM and HD DVD-RW"); + + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0051(Feature_0051? feature) + { + if(!feature.HasValue) + return null; + + Feature_0051 ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.HDDVDR && + ftr.HDDVDRAM) + sb.Append("Drive can write HD DVD-RW, HD DVD-R and HD DVD-RAM"); + else if(ftr.HDDVDR) + sb.Append("Drive can write HD DVD-RW and HD DVD-R"); + else if(ftr.HDDVDRAM) + sb.Append("Drive can write HD DVD-RW and HD DVD-RAM"); + else + sb.Append("Drive can write HD DVD-RW"); + + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0080(Feature_0080? feature) + { + if(!feature.HasValue) + return null; + + Feature_0080 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("Drive is able to access Hybrid discs"); + + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); + + if(ftr.RI) + sb.AppendLine("\tDrive is able to maintain the online format layer through reset and power cycling"); + + return sb.ToString(); + } + + public static string Prettify_0100(Feature_0100? feature) => + !feature.HasValue ? null : "Drive is able to perform host and drive directed power management\n"; + + public static string Prettify_0101(Feature_0101? feature) + { + if(!feature.HasValue) + return null; + + Feature_0101 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive supports S.M.A.R.T."); + + if(ftr.PP) + sb.AppendLine("\tDrive supports the Informational Exceptions Control mode page 1Ch"); + + return sb.ToString(); + } + + public static string Prettify_0102(Feature_0102? feature) + { + if(!feature.HasValue) + return null; + + Feature_0102 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Embedded Changer:"); + + if(ftr.SCC) + sb.AppendLine("\tDrive can change disc side"); + + if(ftr.SDP) + sb.AppendLine("\tDrive is able to report slots contents after a reset or change"); + + sb.AppendFormat("\tDrive has {0} slots", ftr.HighestSlotNumber + 1).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0103(Feature_0103? feature) + { + if(!feature.HasValue) + return null; + + Feature_0103 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive has an analogue audio output"); + + if(ftr.Scan) + sb.AppendLine("\tDrive supports the SCAN command"); + + if(ftr.SCM) + sb.AppendLine("\tDrive is able to mute channels separately"); + + if(ftr.SV) + sb.AppendLine("\tDrive supports separate volume per channel"); + + sb.AppendFormat("\tDrive has {0} volume levels", ftr.VolumeLevels + 1).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0104(Feature_0104? feature) + { + if(!feature.HasValue) + return null; + + Feature_0104 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive supports Microcode Upgrade"); + + if(ftr.M5) + sb.AppendLine("Drive supports validating the 5-bit Mode of the READ BUFFER and WRITE BUFFER commands"); + + return sb.ToString(); + } + + public static string Prettify_0105(Feature_0105? feature) + { + if(!feature.HasValue) + return null; + + Feature_0105 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive supports Timeout & Protect mode page 1Dh"); + + if(!ftr.Group3) + return sb.ToString(); + + sb.AppendLine("\tDrive supports the Group3 in Timeout & Protect mode page 1Dh"); + + if(ftr.UnitLength > 0) + sb.AppendFormat("\tDrive has {0} increase of Group 3 time unit", ftr.UnitLength).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0106(Feature_0106? feature) + { + if(!feature.HasValue) + return null; + + Feature_0106 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendFormat("Drive supports DVD CSS/CPPM version {0}", ftr.CSSVersion); + + if(ftr.Current) + sb.AppendLine(" and current disc is encrypted"); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0107(Feature_0107? feature) + { + if(!feature.HasValue) + return null; + + Feature_0107 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("MMC Real Time Streaming:"); + + if(ftr.SMP) + sb.AppendLine("\tDrive supports Set Minimum Performance with the SET STREAMING command"); + + if(ftr.RBCB) + sb.AppendLine("\tDrive supports the block bit in the READ BUFFER CAPACITY command"); + + if(ftr.SCS) + sb.AppendLine("\tDrive supports the SET CD SPEED command"); + + if(ftr.MP2A) + sb.AppendLine("\tDrive supports the Write Speed Performance Descriptor Blocks in the MMC mode page 2Ah"); + + if(ftr.WSPD) + sb.AppendLine("\tDrive supports the Write Speed data of GET PERFORMANCE and the WRC field of SET STREAMING"); + + if(ftr.SW) + sb.AppendLine("\tDrive supports stream recording"); + + return sb.ToString(); + } + + public static string Prettify_0108(Feature_0108? feature) + { + if(!feature.HasValue) + return null; + + Feature_0108 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendFormat("Drive serial number: {0}", ftr.Serial).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0109(Feature_0109? feature) => + !feature.HasValue ? null : "Drive is able to read media serial number\n"; + + public static string Prettify_010A(Feature_010A? feature) + { + if(!feature.HasValue) + return null; + + Feature_010A ftr = feature.Value; + var sb = new StringBuilder(); + + if(ftr.DCBs == null) + return sb.ToString(); + + foreach(uint dcb in ftr.DCBs) + sb.AppendFormat("Drive supports DCB {0:X8}h", dcb).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_010B(Feature_010B? feature) + { + if(!feature.HasValue) + return null; + + Feature_010B ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendFormat("Drive supports DVD CPRM version {0}", ftr.CPRMVersion); + + if(ftr.Current) + sb.AppendLine(" and current disc is or can be encrypted"); + else + sb.AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_010C(Feature_010C? feature) + { + if(!feature.HasValue) + return null; + + Feature_010C ftr = feature.Value; + var sb = new StringBuilder(); + + byte[] temp = new byte[4]; + temp[0] = (byte)((ftr.Century & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Century & 0xFF); + temp[2] = (byte)((ftr.Year & 0xFF00) >> 8); + temp[3] = (byte)(ftr.Year & 0xFF); + string syear = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Month & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Month & 0xFF); + string smonth = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Day & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Day & 0xFF); + string sday = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Hour & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Hour & 0xFF); + string shour = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Minute & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Minute & 0xFF); + string sminute = Encoding.ASCII.GetString(temp); + temp = new byte[2]; + temp[0] = (byte)((ftr.Second & 0xFF00) >> 8); + temp[1] = (byte)(ftr.Second & 0xFF); + string ssecond = Encoding.ASCII.GetString(temp); + + try + { + var fwDate = new DateTime(int.Parse(syear), int.Parse(smonth), int.Parse(sday), int.Parse(shour), + int.Parse(sminute), int.Parse(ssecond), DateTimeKind.Utc); + + sb.AppendFormat("Drive firmware is dated {0}", fwDate).AppendLine(); + } + #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body + catch + { + // ignored + } + #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body + + return sb.ToString(); + } + + public static string Prettify_010D(Feature_010D? feature) + { + if(!feature.HasValue) + return null; + + Feature_010D ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendFormat("Drive supports AACS version {0}", ftr.AACSVersion); + + if(ftr.Current) + sb.AppendLine(" and current disc is encrypted"); + else + sb.AppendLine(); + + if(ftr.RDC) + sb.AppendLine("\tDrive supports reading the Drive Certificate"); + + if(ftr.RMC) + sb.AppendLine("\tDrive supports reading Media Key Block of CPRM"); + + if(ftr.WBE) + sb.AppendLine("\tDrive supports writing with bus encryption"); + + if(ftr.BEC) + sb.AppendLine("\tDrive supports bus encryption"); + + if(ftr.BNG) + { + sb.AppendLine("\tDrive supports generating the binding nonce"); + + if(ftr.BindNonceBlocks > 0) + sb.AppendFormat("\t{0} media blocks are required for the binding nonce", ftr.BindNonceBlocks). AppendLine(); - - return sb.ToString(); } - public static string Prettify_0110(Feature_0110? feature) - { - if(!feature.HasValue) - return null; + if(ftr.AGIDs > 0) + sb.AppendFormat("\tDrive supports {0} AGIDs concurrently", ftr.AGIDs).AppendLine(); - Feature_0110 ftr = feature.Value; - var sb = new StringBuilder(); + return sb.ToString(); + } - sb.AppendLine(ftr.Current ? "Drive and currently inserted media support VCPS" : "Drive supports VCPS"); + public static string Prettify_010E(Feature_010E? feature) + { + if(!feature.HasValue) + return null; + Feature_010E ftr = feature.Value; + var sb = new StringBuilder(); + + sb.Append("Drive supports DVD-Download"); + + if(ftr.Current) + sb.AppendLine(" (current)"); + else + sb.AppendLine(); + + if(ftr.MaxScrambleExtent > 0) + sb.AppendFormat("\tMaximum {0} scranble extent information entries", ftr.MaxScrambleExtent). + AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0110(Feature_0110? feature) + { + if(!feature.HasValue) + return null; + + Feature_0110 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(ftr.Current ? "Drive and currently inserted media support VCPS" : "Drive supports VCPS"); + + return sb.ToString(); + } + + public static string Prettify_0113(Feature_0113? feature) + { + if(!feature.HasValue) + return null; + + Feature_0113 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine(ftr.Current ? "Drive and currently inserted media support SecurDisc" + : "Drive supports SecurDisc"); + + return sb.ToString(); + } + + public static string Prettify_0142(Feature_0142? feature) + { + if(!feature.HasValue) + return null; + + Feature_0142 ftr = feature.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Drive supports the Trusted Computing Group Optical Security Subsystem Class"); + + if(ftr.Current) + sb.AppendLine("\tCurrent media is initialized with TCG OSSC"); + + if(ftr.PSAU) + sb.AppendLine("\tDrive supports PSA updates on write-once media"); + + if(ftr.LOSPB) + sb.AppendLine("\tDrive supports linked OSPBs"); + + if(ftr.ME) + sb.AppendLine("\tDrive will only record on the OSSC Disc Format"); + + if(ftr.Profiles == null) return sb.ToString(); - } - public static string Prettify_0113(Feature_0113? feature) + for(int i = 0; i < ftr.Profiles.Length; i++) + sb.AppendFormat("\tProfile {0}: {1}", i, ftr.Profiles[i]).AppendLine(); + + return sb.ToString(); + } + + public static string Prettify_0000(byte[] feature) => Prettify_0000(Decode_0000(feature)); + + public static string Prettify_0001(byte[] feature) => Prettify_0001(Decode_0001(feature)); + + public static string Prettify_0002(byte[] feature) => Prettify_0002(Decode_0002(feature)); + + public static string Prettify_0003(byte[] feature) => Prettify_0003(Decode_0003(feature)); + + public static string Prettify_0004(byte[] feature) => Prettify_0004(Decode_0004(feature)); + + public static string Prettify_0010(byte[] feature) => Prettify_0010(Decode_0010(feature)); + + public static string Prettify_001D(byte[] feature) => Prettify_001D(Decode_001D(feature)); + + public static string Prettify_001E(byte[] feature) => Prettify_001E(Decode_001E(feature)); + + public static string Prettify_001F(byte[] feature) => Prettify_001F(Decode_001F(feature)); + + public static string Prettify_0020(byte[] feature) => Prettify_0020(Decode_0020(feature)); + + public static string Prettify_0021(byte[] feature) => Prettify_0021(Decode_0021(feature)); + + public static string Prettify_0022(byte[] feature) => Prettify_0022(Decode_0022(feature)); + + public static string Prettify_0023(byte[] feature) => Prettify_0023(Decode_0023(feature)); + + public static string Prettify_0024(byte[] feature) => Prettify_0024(Decode_0024(feature)); + + public static string Prettify_0025(byte[] feature) => Prettify_0025(Decode_0025(feature)); + + public static string Prettify_0026(byte[] feature) => Prettify_0026(Decode_0026(feature)); + + public static string Prettify_0027(byte[] feature) => Prettify_0027(Decode_0027(feature)); + + public static string Prettify_0028(byte[] feature) => Prettify_0028(Decode_0028(feature)); + + public static string Prettify_0029(byte[] feature) => Prettify_0029(Decode_0029(feature)); + + public static string Prettify_002A(byte[] feature) => Prettify_002A(Decode_002A(feature)); + + public static string Prettify_002B(byte[] feature) => Prettify_002B(Decode_002B(feature)); + + public static string Prettify_002C(byte[] feature) => Prettify_002C(Decode_002C(feature)); + + public static string Prettify_002D(byte[] feature) => Prettify_002D(Decode_002D(feature)); + + public static string Prettify_002E(byte[] feature) => Prettify_002E(Decode_002E(feature)); + + public static string Prettify_002F(byte[] feature) => Prettify_002F(Decode_002F(feature)); + + public static string Prettify_0030(byte[] feature) => Prettify_0030(Decode_0030(feature)); + + public static string Prettify_0031(byte[] feature) => Prettify_0031(Decode_0031(feature)); + + public static string Prettify_0032(byte[] feature) => Prettify_0032(Decode_0032(feature)); + + public static string Prettify_0033(byte[] feature) => Prettify_0033(Decode_0033(feature)); + + public static string Prettify_0035(byte[] feature) => Prettify_0035(Decode_0035(feature)); + + public static string Prettify_0037(byte[] feature) => Prettify_0037(Decode_0037(feature)); + + public static string Prettify_0038(byte[] feature) => Prettify_0038(Decode_0038(feature)); + + public static string Prettify_003A(byte[] feature) => Prettify_003A(Decode_003A(feature)); + + public static string Prettify_003B(byte[] feature) => Prettify_003B(Decode_003B(feature)); + + public static string Prettify_0040(byte[] feature) => Prettify_0040(Decode_0040(feature)); + + public static string Prettify_0041(byte[] feature) => Prettify_0041(Decode_0041(feature)); + + public static string Prettify_0042(byte[] feature) => Prettify_0042(Decode_0042(feature)); + + public static string Prettify_0050(byte[] feature) => Prettify_0050(Decode_0050(feature)); + + public static string Prettify_0051(byte[] feature) => Prettify_0051(Decode_0051(feature)); + + public static string Prettify_0080(byte[] feature) => Prettify_0080(Decode_0080(feature)); + + public static string Prettify_0100(byte[] feature) => Prettify_0100(Decode_0100(feature)); + + public static string Prettify_0101(byte[] feature) => Prettify_0101(Decode_0101(feature)); + + public static string Prettify_0102(byte[] feature) => Prettify_0102(Decode_0102(feature)); + + public static string Prettify_0103(byte[] feature) => Prettify_0103(Decode_0103(feature)); + + public static string Prettify_0104(byte[] feature) => Prettify_0104(Decode_0104(feature)); + + public static string Prettify_0105(byte[] feature) => Prettify_0105(Decode_0105(feature)); + + public static string Prettify_0106(byte[] feature) => Prettify_0106(Decode_0106(feature)); + + public static string Prettify_0107(byte[] feature) => Prettify_0107(Decode_0107(feature)); + + public static string Prettify_0108(byte[] feature) => Prettify_0108(Decode_0108(feature)); + + public static string Prettify_0109(byte[] feature) => Prettify_0109(Decode_0109(feature)); + + public static string Prettify_010A(byte[] feature) => Prettify_010A(Decode_010A(feature)); + + public static string Prettify_010B(byte[] feature) => Prettify_010B(Decode_010B(feature)); + + public static string Prettify_010C(byte[] feature) => Prettify_010C(Decode_010C(feature)); + + public static string Prettify_010D(byte[] feature) => Prettify_010D(Decode_010D(feature)); + + public static string Prettify_010E(byte[] feature) => Prettify_010E(Decode_010E(feature)); + + public static string Prettify_0110(byte[] feature) => Prettify_0110(Decode_0110(feature)); + + public static string Prettify_0113(byte[] feature) => Prettify_0113(Decode_0113(feature)); + + public static string Prettify_0142(byte[] feature) => Prettify_0142(Decode_0142(feature)); + + public static SeparatedFeatures Separate(byte[] response) + { + var dec = new SeparatedFeatures { - if(!feature.HasValue) - return null; + DataLength = (uint)((response[0] << 24) + (response[1] << 16) + (response[2] << 8) + response[4]), + CurrentProfile = (ushort)((response[6] << 8) + response[7]) + }; - Feature_0113 ftr = feature.Value; - var sb = new StringBuilder(); + uint offset = 8; + List descLst = new List(); - sb.AppendLine(ftr.Current ? "Drive and currently inserted media support SecurDisc" - : "Drive supports SecurDisc"); - - return sb.ToString(); - } - - public static string Prettify_0142(Feature_0142? feature) + while(offset + 4 < response.Length) { - if(!feature.HasValue) - return null; - - Feature_0142 ftr = feature.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Drive supports the Trusted Computing Group Optical Security Subsystem Class"); - - if(ftr.Current) - sb.AppendLine("\tCurrent media is initialized with TCG OSSC"); - - if(ftr.PSAU) - sb.AppendLine("\tDrive supports PSA updates on write-once media"); - - if(ftr.LOSPB) - sb.AppendLine("\tDrive supports linked OSPBs"); - - if(ftr.ME) - sb.AppendLine("\tDrive will only record on the OSSC Disc Format"); - - if(ftr.Profiles == null) - return sb.ToString(); - - for(int i = 0; i < ftr.Profiles.Length; i++) - sb.AppendFormat("\tProfile {0}: {1}", i, ftr.Profiles[i]).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify_0000(byte[] feature) => Prettify_0000(Decode_0000(feature)); - - public static string Prettify_0001(byte[] feature) => Prettify_0001(Decode_0001(feature)); - - public static string Prettify_0002(byte[] feature) => Prettify_0002(Decode_0002(feature)); - - public static string Prettify_0003(byte[] feature) => Prettify_0003(Decode_0003(feature)); - - public static string Prettify_0004(byte[] feature) => Prettify_0004(Decode_0004(feature)); - - public static string Prettify_0010(byte[] feature) => Prettify_0010(Decode_0010(feature)); - - public static string Prettify_001D(byte[] feature) => Prettify_001D(Decode_001D(feature)); - - public static string Prettify_001E(byte[] feature) => Prettify_001E(Decode_001E(feature)); - - public static string Prettify_001F(byte[] feature) => Prettify_001F(Decode_001F(feature)); - - public static string Prettify_0020(byte[] feature) => Prettify_0020(Decode_0020(feature)); - - public static string Prettify_0021(byte[] feature) => Prettify_0021(Decode_0021(feature)); - - public static string Prettify_0022(byte[] feature) => Prettify_0022(Decode_0022(feature)); - - public static string Prettify_0023(byte[] feature) => Prettify_0023(Decode_0023(feature)); - - public static string Prettify_0024(byte[] feature) => Prettify_0024(Decode_0024(feature)); - - public static string Prettify_0025(byte[] feature) => Prettify_0025(Decode_0025(feature)); - - public static string Prettify_0026(byte[] feature) => Prettify_0026(Decode_0026(feature)); - - public static string Prettify_0027(byte[] feature) => Prettify_0027(Decode_0027(feature)); - - public static string Prettify_0028(byte[] feature) => Prettify_0028(Decode_0028(feature)); - - public static string Prettify_0029(byte[] feature) => Prettify_0029(Decode_0029(feature)); - - public static string Prettify_002A(byte[] feature) => Prettify_002A(Decode_002A(feature)); - - public static string Prettify_002B(byte[] feature) => Prettify_002B(Decode_002B(feature)); - - public static string Prettify_002C(byte[] feature) => Prettify_002C(Decode_002C(feature)); - - public static string Prettify_002D(byte[] feature) => Prettify_002D(Decode_002D(feature)); - - public static string Prettify_002E(byte[] feature) => Prettify_002E(Decode_002E(feature)); - - public static string Prettify_002F(byte[] feature) => Prettify_002F(Decode_002F(feature)); - - public static string Prettify_0030(byte[] feature) => Prettify_0030(Decode_0030(feature)); - - public static string Prettify_0031(byte[] feature) => Prettify_0031(Decode_0031(feature)); - - public static string Prettify_0032(byte[] feature) => Prettify_0032(Decode_0032(feature)); - - public static string Prettify_0033(byte[] feature) => Prettify_0033(Decode_0033(feature)); - - public static string Prettify_0035(byte[] feature) => Prettify_0035(Decode_0035(feature)); - - public static string Prettify_0037(byte[] feature) => Prettify_0037(Decode_0037(feature)); - - public static string Prettify_0038(byte[] feature) => Prettify_0038(Decode_0038(feature)); - - public static string Prettify_003A(byte[] feature) => Prettify_003A(Decode_003A(feature)); - - public static string Prettify_003B(byte[] feature) => Prettify_003B(Decode_003B(feature)); - - public static string Prettify_0040(byte[] feature) => Prettify_0040(Decode_0040(feature)); - - public static string Prettify_0041(byte[] feature) => Prettify_0041(Decode_0041(feature)); - - public static string Prettify_0042(byte[] feature) => Prettify_0042(Decode_0042(feature)); - - public static string Prettify_0050(byte[] feature) => Prettify_0050(Decode_0050(feature)); - - public static string Prettify_0051(byte[] feature) => Prettify_0051(Decode_0051(feature)); - - public static string Prettify_0080(byte[] feature) => Prettify_0080(Decode_0080(feature)); - - public static string Prettify_0100(byte[] feature) => Prettify_0100(Decode_0100(feature)); - - public static string Prettify_0101(byte[] feature) => Prettify_0101(Decode_0101(feature)); - - public static string Prettify_0102(byte[] feature) => Prettify_0102(Decode_0102(feature)); - - public static string Prettify_0103(byte[] feature) => Prettify_0103(Decode_0103(feature)); - - public static string Prettify_0104(byte[] feature) => Prettify_0104(Decode_0104(feature)); - - public static string Prettify_0105(byte[] feature) => Prettify_0105(Decode_0105(feature)); - - public static string Prettify_0106(byte[] feature) => Prettify_0106(Decode_0106(feature)); - - public static string Prettify_0107(byte[] feature) => Prettify_0107(Decode_0107(feature)); - - public static string Prettify_0108(byte[] feature) => Prettify_0108(Decode_0108(feature)); - - public static string Prettify_0109(byte[] feature) => Prettify_0109(Decode_0109(feature)); - - public static string Prettify_010A(byte[] feature) => Prettify_010A(Decode_010A(feature)); - - public static string Prettify_010B(byte[] feature) => Prettify_010B(Decode_010B(feature)); - - public static string Prettify_010C(byte[] feature) => Prettify_010C(Decode_010C(feature)); - - public static string Prettify_010D(byte[] feature) => Prettify_010D(Decode_010D(feature)); - - public static string Prettify_010E(byte[] feature) => Prettify_010E(Decode_010E(feature)); - - public static string Prettify_0110(byte[] feature) => Prettify_0110(Decode_0110(feature)); - - public static string Prettify_0113(byte[] feature) => Prettify_0113(Decode_0113(feature)); - - public static string Prettify_0142(byte[] feature) => Prettify_0142(Decode_0142(feature)); - - public static SeparatedFeatures Separate(byte[] response) - { - var dec = new SeparatedFeatures + var desc = new FeatureDescriptor { - DataLength = (uint)((response[0] << 24) + (response[1] << 16) + (response[2] << 8) + response[4]), - CurrentProfile = (ushort)((response[6] << 8) + response[7]) + Code = (ushort)((response[offset + 0] << 8) + response[offset + 1]), + Data = new byte[response[offset + 3] + 4] }; - uint offset = 8; - List descLst = new List(); + if(desc.Data.Length + offset > response.Length) + desc.Data = new byte[response.Length - offset]; - while(offset + 4 < response.Length) - { - var desc = new FeatureDescriptor - { - Code = (ushort)((response[offset + 0] << 8) + response[offset + 1]), - Data = new byte[response[offset + 3] + 4] - }; + Array.Copy(response, offset, desc.Data, 0, desc.Data.Length); + offset += (uint)desc.Data.Length; - if(desc.Data.Length + offset > response.Length) - desc.Data = new byte[response.Length - offset]; - - Array.Copy(response, offset, desc.Data, 0, desc.Data.Length); - offset += (uint)desc.Data.Length; - - descLst.Add(desc); - } - - dec.Descriptors = descLst.ToArray(); - - return dec; + descLst.Add(desc); } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct FeatureDescriptor - { - public ushort Code; - public byte[] Data; - } + dec.Descriptors = descLst.ToArray(); - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct SeparatedFeatures - { - public uint DataLength; - public ushort CurrentProfile; - public FeatureDescriptor[] Descriptors; - } + return dec; + } + + [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] + public struct FeatureDescriptor + { + public ushort Code; + public byte[] Data; + } + + [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] + public struct SeparatedFeatures + { + public uint DataLength; + public ushort CurrentProfile; + public FeatureDescriptor[] Descriptors; } } \ No newline at end of file diff --git a/SCSI/MMC/Hybrid.cs b/SCSI/MMC/Hybrid.cs index be8aca6..6db9d60 100644 --- a/SCSI/MMC/Hybrid.cs +++ b/SCSI/MMC/Hybrid.cs @@ -34,163 +34,162 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class Hybrid { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class Hybrid + public static RecognizedFormatLayers? DecodeFormatLayers(byte[] FormatLayersResponse) { - public static RecognizedFormatLayers? DecodeFormatLayers(byte[] FormatLayersResponse) + if(FormatLayersResponse == null) + return null; + + if(FormatLayersResponse.Length < 8) + return null; + + var decoded = new RecognizedFormatLayers { - if(FormatLayersResponse == null) - return null; + 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), + OnlineFormatLayer = (byte)(FormatLayersResponse[5] & 0x03), + FormatLayers = new ushort[(FormatLayersResponse.Length - 6) / 2] + }; - if(FormatLayersResponse.Length < 8) - return null; + for(int i = 0; i < (FormatLayersResponse.Length - 6) / 2; i++) + decoded.FormatLayers[i] = BigEndianBitConverter.ToUInt16(FormatLayersResponse, (i * 2) + 6); - var decoded = new RecognizedFormatLayers + return decoded; + } + + public static string PrettifyFormatLayers(RecognizedFormatLayers? FormatLayersResponse) + { + if(FormatLayersResponse == null) + return null; + + RecognizedFormatLayers response = FormatLayersResponse.Value; + + 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]) { - 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), - OnlineFormatLayer = (byte)(FormatLayersResponse[5] & 0x03), - FormatLayers = new ushort[(FormatLayersResponse.Length - 6) / 2] - }; - - for(int i = 0; i < (FormatLayersResponse.Length - 6) / 2; i++) - decoded.FormatLayers[i] = BigEndianBitConverter.ToUInt16(FormatLayersResponse, (i * 2) + 6); - - return decoded; - } - - public static string PrettifyFormatLayers(RecognizedFormatLayers? FormatLayersResponse) - { - if(FormatLayersResponse == null) - return null; - - RecognizedFormatLayers response = FormatLayersResponse.Value; - - 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(); + sb.AppendFormat("Layer {0} is of type Blu-ray", i).AppendLine(); - if(response.DefaultFormatLayer == i) - sb.AppendLine("This is the default layer."); + 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.OnlineFormatLayer == i) + sb.AppendLine("This is the layer actually in use."); - break; - } - - 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."); - - break; - } - - 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."); - - break; - } - - 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."); - - 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."); - - break; - } + break; } - return sb.ToString(); - } + case (ushort)FormatLayerTypeCodes.CDLayer: + { + sb.AppendFormat("Layer {0} is of type CD", i).AppendLine(); - public static string PrettifyFormatLayers(byte[] FormatLayersResponse) - { - RecognizedFormatLayers? decoded = DecodeFormatLayers(FormatLayersResponse); + if(response.DefaultFormatLayer == i) + sb.AppendLine("This is the default layer."); - return PrettifyFormatLayers(decoded); - } + if(response.OnlineFormatLayer == i) + sb.AppendLine("This is the layer actually in use."); - public struct RecognizedFormatLayers - { - /// Bytes 0 to 1 Data Length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4 Number of format layers in hybrid disc identified by drive - public byte NumberOfLayers; - /// Byte 5, bits 7 to 6 Reserved - public byte Reserved3; - /// Byte 5, bits 5 to 4 Layer no. used when disc is inserted - public byte DefaultFormatLayer; - /// Byte 5, bits 3 to 2 Reserved - public byte Reserved4; - /// Byte 5, bits 1 to 0 Layer no. currently in use - public byte OnlineFormatLayer; - /// Bytes 6 to end Recognized format layers - public ushort[] FormatLayers; - } + break; + } + + 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."); + + break; + } + + 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."); + + 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."); + + break; + } + } + + return sb.ToString(); + } + + public static string PrettifyFormatLayers(byte[] FormatLayersResponse) + { + RecognizedFormatLayers? decoded = DecodeFormatLayers(FormatLayersResponse); + + return PrettifyFormatLayers(decoded); + } + + public struct RecognizedFormatLayers + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4 Number of format layers in hybrid disc identified by drive + public byte NumberOfLayers; + /// Byte 5, bits 7 to 6 Reserved + public byte Reserved3; + /// Byte 5, bits 5 to 4 Layer no. used when disc is inserted + public byte DefaultFormatLayer; + /// Byte 5, bits 3 to 2 Reserved + public byte Reserved4; + /// Byte 5, bits 1 to 0 Layer no. currently in use + public byte OnlineFormatLayer; + /// Bytes 6 to end Recognized format layers + public ushort[] FormatLayers; } } \ No newline at end of file diff --git a/SCSI/MMC/TrackInformation.cs b/SCSI/MMC/TrackInformation.cs index bfead5b..8a98bf7 100644 --- a/SCSI/MMC/TrackInformation.cs +++ b/SCSI/MMC/TrackInformation.cs @@ -26,85 +26,84 @@ // Copyright © 2011-2022 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +public class TrackInformation { - public class TrackInformation + public bool Blank; + public bool Copy; + public bool Damage; + public ushort DataLength; + public byte DataMode; + public uint FixedPacketSize; + public bool FP; + public uint FreeBlocks; + public uint LastLayerJumpAddress; + public uint LastRecordedAddress; + public LayerJumpRecordingStatus LayerJumpRecordingStatus; + public ushort LogicalTrackNumber; + public uint LogicalTrackSize; + public uint LogicalTrackStartAddress; + public bool LraV; + public uint NextLayerJumpAddress; + public uint NextWritableAddress; + public bool NwaV; + public bool Packet; + public uint ReadCompatibilityLba; + public bool RT; + public ushort SessionNumber; + public byte TrackMode; + + public static TrackInformation Decode(byte[] response) { - public bool Blank; - public bool Copy; - public bool Damage; - public ushort DataLength; - public byte DataMode; - public uint FixedPacketSize; - public bool FP; - public uint FreeBlocks; - public uint LastLayerJumpAddress; - public uint LastRecordedAddress; - public LayerJumpRecordingStatus LayerJumpRecordingStatus; - public ushort LogicalTrackNumber; - public uint LogicalTrackSize; - public uint LogicalTrackStartAddress; - public bool LraV; - public uint NextLayerJumpAddress; - public uint NextWritableAddress; - public bool NwaV; - public bool Packet; - public uint ReadCompatibilityLba; - public bool RT; - public ushort SessionNumber; - public byte TrackMode; + if(response.Length < 32) + return null; - public static TrackInformation Decode(byte[] response) + var decoded = new TrackInformation { - if(response.Length < 32) - return null; - - var decoded = new TrackInformation - { - DataLength = (ushort)((response[0] << 8) + response[1]), - LogicalTrackNumber = response[2], - SessionNumber = response[3], - LayerJumpRecordingStatus = (LayerJumpRecordingStatus)(response[5] >> 6), - Damage = (response[5] & 0x20) == 0x20, - Copy = (response[5] & 0x10) == 0x10, - TrackMode = (byte)(response[5] & 0xF), - RT = (response[6] & 0x80) == 0x80, - Blank = (response[6] & 0x40) == 0x40, - Packet = (response[6] & 0x20) == 0x20, - FP = (response[6] & 0x10) == 0x10, - DataMode = (byte)(response[6] & 0xF), - LraV = (response[7] & 0x02) == 0x02, - NwaV = (response[7] & 0x01) == 0x01, - LogicalTrackStartAddress = - (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), - NextWritableAddress = - (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]), - FreeBlocks = (uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]), - FixedPacketSize = - (uint)((response[20] << 24) + (response[21] << 16) + (response[22] << 8) + response[23]), - LogicalTrackSize = - (uint)((response[24] << 24) + (response[25] << 16) + (response[26] << 8) + response[27]), - LastRecordedAddress = - (uint)((response[28] << 24) + (response[29] << 16) + (response[30] << 8) + response[31]) - }; - - if(response.Length < 48) - return decoded; - - decoded.LogicalTrackNumber += (ushort)(response[32] << 8); - - decoded.SessionNumber += (ushort)(response[33] << 8); - - decoded.ReadCompatibilityLba = - (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); - - decoded.NextLayerJumpAddress = - (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); - - decoded.LastLayerJumpAddress = - (uint)((response[44] << 24) + (response[45] << 16) + (response[46] << 8) + response[47]); + DataLength = (ushort)((response[0] << 8) + response[1]), + LogicalTrackNumber = response[2], + SessionNumber = response[3], + LayerJumpRecordingStatus = (LayerJumpRecordingStatus)(response[5] >> 6), + Damage = (response[5] & 0x20) == 0x20, + Copy = (response[5] & 0x10) == 0x10, + TrackMode = (byte)(response[5] & 0xF), + RT = (response[6] & 0x80) == 0x80, + Blank = (response[6] & 0x40) == 0x40, + Packet = (response[6] & 0x20) == 0x20, + FP = (response[6] & 0x10) == 0x10, + DataMode = (byte)(response[6] & 0xF), + LraV = (response[7] & 0x02) == 0x02, + NwaV = (response[7] & 0x01) == 0x01, + LogicalTrackStartAddress = + (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), + NextWritableAddress = + (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]), + FreeBlocks = (uint)((response[16] << 24) + (response[17] << 16) + (response[18] << 8) + response[19]), + FixedPacketSize = + (uint)((response[20] << 24) + (response[21] << 16) + (response[22] << 8) + response[23]), + LogicalTrackSize = + (uint)((response[24] << 24) + (response[25] << 16) + (response[26] << 8) + response[27]), + LastRecordedAddress = + (uint)((response[28] << 24) + (response[29] << 16) + (response[30] << 8) + response[31]) + }; + if(response.Length < 48) return decoded; - } + + decoded.LogicalTrackNumber += (ushort)(response[32] << 8); + + decoded.SessionNumber += (ushort)(response[33] << 8); + + decoded.ReadCompatibilityLba = + (uint)((response[36] << 24) + (response[37] << 16) + (response[38] << 8) + response[39]); + + decoded.NextLayerJumpAddress = + (uint)((response[40] << 24) + (response[41] << 16) + (response[42] << 8) + response[43]); + + decoded.LastLayerJumpAddress = + (uint)((response[44] << 24) + (response[45] << 16) + (response[46] << 8) + response[47]); + + return decoded; } } \ No newline at end of file diff --git a/SCSI/MMC/WriteProtect.cs b/SCSI/MMC/WriteProtect.cs index 5945002..5e17318 100644 --- a/SCSI/MMC/WriteProtect.cs +++ b/SCSI/MMC/WriteProtect.cs @@ -35,123 +35,122 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI.MMC +namespace Aaru.Decoders.SCSI.MMC; + +// 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 +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class WriteProtect { - // 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 - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class WriteProtect + public static WriteProtectionStatus? DecodeWriteProtectionStatus(byte[] WPSResponse) { - public static WriteProtectionStatus? DecodeWriteProtectionStatus(byte[] WPSResponse) + if(WPSResponse == null) + return null; + + var decoded = new WriteProtectionStatus { - if(WPSResponse == null) - return null; + 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], + Reserved6 = WPSResponse[7] + }; - var decoded = new WriteProtectionStatus - { - 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], - Reserved6 = WPSResponse[7] - }; + return decoded; + } - return decoded; - } + public static string PrettifyWriteProtectionStatus(WriteProtectionStatus? WPSResponse) + { + if(WPSResponse == null) + return null; - public static string PrettifyWriteProtectionStatus(WriteProtectionStatus? WPSResponse) - { - if(WPSResponse == null) - return null; + WriteProtectionStatus response = WPSResponse.Value; - WriteProtectionStatus response = WPSResponse.Value; + var sb = new StringBuilder(); - var sb = new StringBuilder(); + if(response.MSWI) + sb.AppendLine("Writing inhibited by media specific reason"); - if(response.MSWI) - sb.AppendLine("Writing inhibited by media specific reason"); + if(response.CWP) + sb.AppendLine("Cartridge sets write protection"); - if(response.CWP) - sb.AppendLine("Cartridge sets write protection"); + if(response.PWP) + sb.AppendLine("Media surface 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.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 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.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.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.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.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.Reserved6 != 0) - sb.AppendFormat("Reserved6 = 0x{0:X2}", response.Reserved6).AppendLine(); - #endif + return sb.ToString(); + } - return sb.ToString(); - } + public static string PrettifyWriteProtectionStatus(byte[] WPSResponse) + { + WriteProtectionStatus? decoded = DecodeWriteProtectionStatus(WPSResponse); - public static string PrettifyWriteProtectionStatus(byte[] WPSResponse) - { - WriteProtectionStatus? decoded = DecodeWriteProtectionStatus(WPSResponse); + return PrettifyWriteProtectionStatus(decoded); + } - return PrettifyWriteProtectionStatus(decoded); - } - - public struct WriteProtectionStatus - { - /// Bytes 0 to 1 Data Length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - /// Byte 4, bits 7 to 4 Reserved - public byte Reserved3; - /// Byte 4, bit 3 Writing inhibited by media specific reason - public bool MSWI; - /// Byte 4, bit 2 Cartridge sets write protection - public bool CWP; - /// Byte 4, bit 1 Media surface sets write protection - public bool PWP; - /// Byte 4, bit 0 Software write protection until power down - public bool SWPP; - /// Byte 5 Reserved - public byte Reserved4; - /// Byte 6 Reserved - public byte Reserved5; - /// Byte 7 Reserved - public byte Reserved6; - } + public struct WriteProtectionStatus + { + /// Bytes 0 to 1 Data Length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; + /// Byte 4, bits 7 to 4 Reserved + public byte Reserved3; + /// Byte 4, bit 3 Writing inhibited by media specific reason + public bool MSWI; + /// Byte 4, bit 2 Cartridge sets write protection + public bool CWP; + /// Byte 4, bit 1 Media surface sets write protection + public bool PWP; + /// Byte 4, bit 0 Software write protection until power down + public bool SWPP; + /// Byte 5 Reserved + public byte Reserved4; + /// Byte 6 Reserved + public byte Reserved5; + /// Byte 7 Reserved + public byte Reserved6; } } \ No newline at end of file diff --git a/SCSI/Modes/00_SFF.cs b/SCSI/Modes/00_SFF.cs index fcf785c..06d0032 100644 --- a/SCSI/Modes/00_SFF.cs +++ b/SCSI/Modes/00_SFF.cs @@ -33,85 +33,84 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x00: Drive Operation Mode page + /// Drive Operation Mode page Page code 0x00 4 bytes in INF-8070 + public struct ModePage_00_SFF { - #region Mode Page 0x00: Drive Operation Mode page - /// Drive Operation Mode page Page code 0x00 4 bytes in INF-8070 - public struct ModePage_00_SFF - { - /// Parameters can be saved - public bool PS; - /// Select LUN Mode - public bool SLM; - /// Select LUN for rewritable - public bool SLR; - /// Disable verify for WRITE - public bool DVW; - /// Disable deferred error - public bool DDE; - } - - public static ModePage_00_SFF? DecodeModePage_00_SFF(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x00) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 4) - return null; - - var decoded = new ModePage_00_SFF(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.SLM |= (pageResponse[2] & 0x80) == 0x80; - decoded.SLR |= (pageResponse[2] & 0x40) == 0x40; - decoded.DVW |= (pageResponse[2] & 0x20) == 0x20; - - decoded.DDE |= (pageResponse[3] & 0x10) == 0x10; - - return decoded; - } - - public static string PrettifyModePage_00_SFF(byte[] pageResponse) => - PrettifyModePage_00_SFF(DecodeModePage_00_SFF(pageResponse)); - - public static string PrettifyModePage_00_SFF(ModePage_00_SFF? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_00_SFF page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Drive Operation Mode page:"); - - 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.SLM) - return sb.ToString(); - - sb.Append("\tDrive has two LUNs with rewritable being "); - sb.AppendLine(page.SLR ? "LUN 1" : "LUN 0"); - - return sb.ToString(); - } - #endregion Mode Page 0x00: Drive Operation Mode page + /// Parameters can be saved + public bool PS; + /// Select LUN Mode + public bool SLM; + /// Select LUN for rewritable + public bool SLR; + /// Disable verify for WRITE + public bool DVW; + /// Disable deferred error + public bool DDE; } + + public static ModePage_00_SFF? DecodeModePage_00_SFF(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x00) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 4) + return null; + + var decoded = new ModePage_00_SFF(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.SLM |= (pageResponse[2] & 0x80) == 0x80; + decoded.SLR |= (pageResponse[2] & 0x40) == 0x40; + decoded.DVW |= (pageResponse[2] & 0x20) == 0x20; + + decoded.DDE |= (pageResponse[3] & 0x10) == 0x10; + + return decoded; + } + + public static string PrettifyModePage_00_SFF(byte[] pageResponse) => + PrettifyModePage_00_SFF(DecodeModePage_00_SFF(pageResponse)); + + public static string PrettifyModePage_00_SFF(ModePage_00_SFF? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_00_SFF page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Drive Operation Mode page:"); + + 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.SLM) + return sb.ToString(); + + sb.Append("\tDrive has two LUNs with rewritable being "); + sb.AppendLine(page.SLR ? "LUN 1" : "LUN 0"); + + return sb.ToString(); + } + #endregion Mode Page 0x00: Drive Operation Mode page } \ No newline at end of file diff --git a/SCSI/Modes/01.cs b/SCSI/Modes/01.cs index 58a8522..2ca280b 100644 --- a/SCSI/Modes/01.cs +++ b/SCSI/Modes/01.cs @@ -33,197 +33,196 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + public static byte[] EncodeModePage_01(ModePage_01 page) { - public static byte[] EncodeModePage_01(ModePage_01 page) - { - byte[] pg = new byte[8]; + byte[] pg = new byte[8]; - pg[0] = 0x01; - pg[1] = 6; + pg[0] = 0x01; + pg[1] = 6; - if(page.PS) - pg[0] += 0x80; + if(page.PS) + pg[0] += 0x80; - if(page.AWRE) - pg[2] += 0x80; + if(page.AWRE) + pg[2] += 0x80; - if(page.ARRE) - pg[2] += 0x40; + if(page.ARRE) + pg[2] += 0x40; - if(page.TB) - pg[2] += 0x20; + if(page.TB) + pg[2] += 0x20; - if(page.RC) - pg[2] += 0x10; + if(page.RC) + pg[2] += 0x10; - if(page.EER) - pg[2] += 0x08; + if(page.EER) + pg[2] += 0x08; - if(page.PER) - pg[2] += 0x04; + if(page.PER) + pg[2] += 0x04; - if(page.DTE) - pg[2] += 0x02; + if(page.DTE) + pg[2] += 0x02; - if(page.DCR) - pg[2] += 0x01; + if(page.DCR) + pg[2] += 0x01; - pg[3] = page.ReadRetryCount; - pg[4] = page.CorrectionSpan; - pg[5] = (byte)page.HeadOffsetCount; - pg[6] = (byte)page.DataStrobeOffsetCount; + pg[3] = page.ReadRetryCount; + pg[4] = page.CorrectionSpan; + pg[5] = (byte)page.HeadOffsetCount; + pg[6] = (byte)page.DataStrobeOffsetCount; - // This is from a newer version of SCSI unknown what happen for drives expecting an 8 byte page - /* - pg[8] = page.WriteRetryCount; - if (page.LBPERE) - pg[7] += 0x80; - pg[10] = (byte)((page.RecoveryTimeLimit & 0xFF00) << 8); - pg[11] = (byte)(page.RecoveryTimeLimit & 0xFF);*/ + // This is from a newer version of SCSI unknown what happen for drives expecting an 8 byte page + /* + pg[8] = page.WriteRetryCount; + if (page.LBPERE) + pg[7] += 0x80; + pg[10] = (byte)((page.RecoveryTimeLimit & 0xFF00) << 8); + pg[11] = (byte)(page.RecoveryTimeLimit & 0xFF);*/ - return pg; - } - - #region Mode Page 0x01: Read-write error recovery page - /// Disconnect-reconnect page Page code 0x01 12 bytes in SCSI-2, SBC-1, SBC-2 - public struct ModePage_01 - { - /// Parameters can be saved - public bool PS; - /// Automatic Write Reallocation Enabled - public bool AWRE; - /// Automatic Read Reallocation Enabled - public bool ARRE; - /// Transfer block - public bool TB; - /// Read continuous - public bool RC; - /// Enable early recovery - public bool EER; - /// Post error reporting - public bool PER; - /// Disable transfer on error - public bool DTE; - /// Disable correction - public bool DCR; - /// How many times to retry a read operation - public byte ReadRetryCount; - /// How many bits of largest data burst error is maximum to apply error correction on it - public byte CorrectionSpan; - /// Offset to move the heads - public sbyte HeadOffsetCount; - /// Incremental position to which the recovered data strobe shall be adjusted - public sbyte DataStrobeOffsetCount; - /// How many times to retry a write operation - public byte WriteRetryCount; - /// Maximum time in ms to use in data error recovery procedures - public ushort RecoveryTimeLimit; - - /// Logical block provisioning error reporting is enabled - 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 + return pg; } + + #region Mode Page 0x01: Read-write error recovery page + /// Disconnect-reconnect page Page code 0x01 12 bytes in SCSI-2, SBC-1, SBC-2 + public struct ModePage_01 + { + /// Parameters can be saved + public bool PS; + /// Automatic Write Reallocation Enabled + public bool AWRE; + /// Automatic Read Reallocation Enabled + public bool ARRE; + /// Transfer block + public bool TB; + /// Read continuous + public bool RC; + /// Enable early recovery + public bool EER; + /// Post error reporting + public bool PER; + /// Disable transfer on error + public bool DTE; + /// Disable correction + public bool DCR; + /// How many times to retry a read operation + public byte ReadRetryCount; + /// How many bits of largest data burst error is maximum to apply error correction on it + public byte CorrectionSpan; + /// Offset to move the heads + public sbyte HeadOffsetCount; + /// Incremental position to which the recovered data strobe shall be adjusted + public sbyte DataStrobeOffsetCount; + /// How many times to retry a write operation + public byte WriteRetryCount; + /// Maximum time in ms to use in data error recovery procedures + public ushort RecoveryTimeLimit; + + /// Logical block provisioning error reporting is enabled + 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 } \ No newline at end of file diff --git a/SCSI/Modes/01_MMC.cs b/SCSI/Modes/01_MMC.cs index 213c0f5..a988cf3 100644 --- a/SCSI/Modes/01_MMC.cs +++ b/SCSI/Modes/01_MMC.cs @@ -33,202 +33,201 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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) { - public static byte[] EncodeModePage_01_MMC(ModePage_01_MMC page) - { - byte[] pg = new byte[12]; + byte[] pg = new byte[12]; - pg[0] = 0x01; - pg[1] = 10; + pg[0] = 0x01; + pg[1] = 10; - if(page.PS) - pg[0] += 0x80; + if(page.PS) + pg[0] += 0x80; - pg[2] = page.Parameter; - pg[3] = page.ReadRetryCount; + 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 + // 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); + 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 - /// - /// Read error recovery page for MultiMedia Devices Page code 0x01 8 bytes in SCSI-2, MMC-1 12 bytes in MMC-2, - /// MMC-3 - /// - public struct ModePage_01_MMC - { - /// Parameters can be saved - public bool PS; - /// Error recovery parameter - public byte Parameter; - /// How many times to retry a read operation - public byte ReadRetryCount; - /// How many times to retry a write operation - public byte WriteRetryCount; - /// Maximum time in ms to use in data error recovery procedures - public ushort RecoveryTimeLimit; - } - - public static ModePage_01_MMC? DecodeModePage_01_MMC(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_MMC(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.Parameter = pageResponse[2]; - decoded.ReadRetryCount = pageResponse[3]; - - if(pageResponse.Length < 12) - return decoded; - - decoded.WriteRetryCount = pageResponse[8]; - decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - - return decoded; - } - - public static string PrettifyModePage_01_MMC(byte[] pageResponse) => - PrettifyModePage_01_MMC(DecodeModePage_01_MMC(pageResponse)); - - public static string PrettifyModePage_01_MMC(ModePage_01_MMC? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_01_MMC page = modePage.Value; - 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.ReadRetryCount > 0) - sb.AppendFormat("\tDrive will repeat read operations {0} times", page.ReadRetryCount).AppendLine(); - - string AllUsed = "\tAll available recovery procedures will be used.\n"; - string CIRCRetriesUsed = "\tOnly retries and CIRC are used.\n"; - string RetriesUsed = "\tOnly retries are used.\n"; - string RecoveredNotReported = "\tRecovered errors will not be reported.\n"; - string RecoveredReported = "\tRecovered errors will be reported.\n"; - string RecoveredAbort = "\tRecovered errors will be reported and aborted with CHECK CONDITION.\n"; - string UnrecECCAbort = "\tUnrecovered ECC errors will return CHECK CONDITION."; - 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."; - - switch(page.Parameter) - { - 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; - case 0x34: goto case 0x14; - 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(); - - return sb.ToString(); - } - #endregion Mode Page 0x01: Read error recovery page for MultiMedia Devices + return pg; } + + #region Mode Page 0x01: Read error recovery page for MultiMedia Devices + /// + /// Read error recovery page for MultiMedia Devices Page code 0x01 8 bytes in SCSI-2, MMC-1 12 bytes in MMC-2, + /// MMC-3 + /// + public struct ModePage_01_MMC + { + /// Parameters can be saved + public bool PS; + /// Error recovery parameter + public byte Parameter; + /// How many times to retry a read operation + public byte ReadRetryCount; + /// How many times to retry a write operation + public byte WriteRetryCount; + /// Maximum time in ms to use in data error recovery procedures + public ushort RecoveryTimeLimit; + } + + public static ModePage_01_MMC? DecodeModePage_01_MMC(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_MMC(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.Parameter = pageResponse[2]; + decoded.ReadRetryCount = pageResponse[3]; + + if(pageResponse.Length < 12) + return decoded; + + decoded.WriteRetryCount = pageResponse[8]; + decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + return decoded; + } + + public static string PrettifyModePage_01_MMC(byte[] pageResponse) => + PrettifyModePage_01_MMC(DecodeModePage_01_MMC(pageResponse)); + + public static string PrettifyModePage_01_MMC(ModePage_01_MMC? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_01_MMC page = modePage.Value; + 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.ReadRetryCount > 0) + sb.AppendFormat("\tDrive will repeat read operations {0} times", page.ReadRetryCount).AppendLine(); + + string AllUsed = "\tAll available recovery procedures will be used.\n"; + string CIRCRetriesUsed = "\tOnly retries and CIRC are used.\n"; + string RetriesUsed = "\tOnly retries are used.\n"; + string RecoveredNotReported = "\tRecovered errors will not be reported.\n"; + string RecoveredReported = "\tRecovered errors will be reported.\n"; + string RecoveredAbort = "\tRecovered errors will be reported and aborted with CHECK CONDITION.\n"; + string UnrecECCAbort = "\tUnrecovered ECC errors will return CHECK CONDITION."; + 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."; + + switch(page.Parameter) + { + 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; + case 0x34: goto case 0x14; + 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(); + + return sb.ToString(); + } + #endregion Mode Page 0x01: Read error recovery page for MultiMedia Devices } \ No newline at end of file diff --git a/SCSI/Modes/02.cs b/SCSI/Modes/02.cs index 3c13a45..b9d9f6d 100644 --- a/SCSI/Modes/02.cs +++ b/SCSI/Modes/02.cs @@ -33,158 +33,157 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x02: Disconnect-reconnect page + /// Disconnect-reconnect page Page code 0x02 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 + public struct ModePage_02 { - #region Mode Page 0x02: Disconnect-reconnect page - /// Disconnect-reconnect page Page code 0x02 16 bytes in SCSI-2, SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 - public struct ModePage_02 - { - /// Parameters can be saved - public bool PS; - /// How full should be the buffer prior to attempting a reselection - public byte BufferFullRatio; - /// How empty should be the buffer prior to attempting a reselection - public byte BufferEmptyRatio; - /// Max. time in 100 µs increments that the target is permitted to assert BSY without a REQ/ACK - public ushort BusInactivityLimit; - /// Min. time in 100 µs increments to wait after releasing the bus before attempting reselection - public ushort DisconnectTimeLimit; - /// - /// Max. time in 100 µs increments allowed to use the bus before disconnecting, if granted the privilege and not - /// restricted by - /// - public ushort ConnectTimeLimit; - /// Maximum amount of data before disconnecting in 512 bytes increments - public ushort MaxBurstSize; - /// Data transfer disconnect control - public byte DTDC; + /// Parameters can be saved + public bool PS; + /// How full should be the buffer prior to attempting a reselection + public byte BufferFullRatio; + /// How empty should be the buffer prior to attempting a reselection + public byte BufferEmptyRatio; + /// Max. time in 100 µs increments that the target is permitted to assert BSY without a REQ/ACK + public ushort BusInactivityLimit; + /// Min. time in 100 µs increments to wait after releasing the bus before attempting reselection + public ushort DisconnectTimeLimit; + /// + /// Max. time in 100 µs increments allowed to use the bus before disconnecting, if granted the privilege and not + /// restricted by + /// + public ushort ConnectTimeLimit; + /// Maximum amount of data before disconnecting in 512 bytes increments + public ushort MaxBurstSize; + /// Data transfer disconnect control + public byte DTDC; - /// Target shall not transfer data for a command during the same interconnect tenancy - public bool DIMM; - /// Wether to use fair or unfair arbitration when requesting an interconnect tenancy - public byte FairArbitration; - /// Max. ammount of data in 512 bytes increments that may be transferred for a command along with the command - public ushort FirstBurstSize; - /// Target is allowed to re-order the data transfer - public bool EMDP; - } - - public static ModePage_02? DecodeModePage_02(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x02) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 12) - return null; - - var decoded = new ModePage_02(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.BufferFullRatio = pageResponse[2]; - decoded.BufferEmptyRatio = pageResponse[3]; - decoded.BusInactivityLimit = (ushort)((pageResponse[4] << 8) + pageResponse[5]); - decoded.DisconnectTimeLimit = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - decoded.ConnectTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]); - decoded.MaxBurstSize = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - - if(pageResponse.Length >= 13) - { - decoded.EMDP |= (pageResponse[12] & 0x80) == 0x80; - decoded.DIMM |= (pageResponse[12] & 0x08) == 0x08; - decoded.FairArbitration = (byte)((pageResponse[12] & 0x70) >> 4); - decoded.DTDC = (byte)(pageResponse[12] & 0x07); - } - - if(pageResponse.Length >= 16) - decoded.FirstBurstSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]); - - return decoded; - } - - public static string PrettifyModePage_02(byte[] pageResponse) => - PrettifyModePage_02(DecodeModePage_02(pageResponse)); - - public static string PrettifyModePage_02(ModePage_02? modePage) - { - if(!modePage.HasValue) - return null; - - 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.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", - page.ConnectTimeLimit * 100).AppendLine(); - - if(page.MaxBurstSize > 0) - 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", - 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"); - - 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; - } - - return sb.ToString(); - } - #endregion Mode Page 0x02: Disconnect-reconnect page + /// Target shall not transfer data for a command during the same interconnect tenancy + public bool DIMM; + /// Wether to use fair or unfair arbitration when requesting an interconnect tenancy + public byte FairArbitration; + /// Max. ammount of data in 512 bytes increments that may be transferred for a command along with the command + public ushort FirstBurstSize; + /// Target is allowed to re-order the data transfer + public bool EMDP; } + + public static ModePage_02? DecodeModePage_02(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x02) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 12) + return null; + + var decoded = new ModePage_02(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.BufferFullRatio = pageResponse[2]; + decoded.BufferEmptyRatio = pageResponse[3]; + decoded.BusInactivityLimit = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.DisconnectTimeLimit = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.ConnectTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.MaxBurstSize = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + if(pageResponse.Length >= 13) + { + decoded.EMDP |= (pageResponse[12] & 0x80) == 0x80; + decoded.DIMM |= (pageResponse[12] & 0x08) == 0x08; + decoded.FairArbitration = (byte)((pageResponse[12] & 0x70) >> 4); + decoded.DTDC = (byte)(pageResponse[12] & 0x07); + } + + if(pageResponse.Length >= 16) + decoded.FirstBurstSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + + return decoded; + } + + public static string PrettifyModePage_02(byte[] pageResponse) => + PrettifyModePage_02(DecodeModePage_02(pageResponse)); + + public static string PrettifyModePage_02(ModePage_02? modePage) + { + if(!modePage.HasValue) + return null; + + 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.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", + page.ConnectTimeLimit * 100).AppendLine(); + + if(page.MaxBurstSize > 0) + 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", + 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"); + + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x02: Disconnect-reconnect page } \ No newline at end of file diff --git a/SCSI/Modes/03.cs b/SCSI/Modes/03.cs index 6d790ef..0c5472d 100644 --- a/SCSI/Modes/03.cs +++ b/SCSI/Modes/03.cs @@ -33,137 +33,136 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x03: Format device page + /// Disconnect-reconnect page Page code 0x03 24 bytes in SCSI-2, SBC-1 + public struct ModePage_03 { - #region Mode Page 0x03: Format device page - /// Disconnect-reconnect page Page code 0x03 24 bytes in SCSI-2, SBC-1 - public struct ModePage_03 - { - /// Parameters can be saved - public bool PS; - /// Tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors - public ushort TracksPerZone; - /// Number of sectors per zone that shall be reserved for defect handling - public ushort AltSectorsPerZone; - /// Number of tracks per zone that shall be reserved for defect handling - public ushort AltTracksPerZone; - /// Number of tracks per LUN that shall be reserved for defect handling - public ushort AltTracksPerLun; - /// Number of physical sectors per track - public ushort SectorsPerTrack; - /// Bytes per physical sector - public ushort BytesPerSector; - /// Interleave value, target dependent - public ushort Interleave; - /// Sectors between last block of one track and first block of the next - public ushort TrackSkew; - /// Sectors between last block of a cylinder and first block of the next one - public ushort CylinderSkew; - /// Soft-sectored - public bool SSEC; - /// Hard-sectored - public bool HSEC; - /// Removable - public bool RMB; - /// - /// If set, address are allocated progressively in a surface before going to the next. Otherwise, it goes by - /// cylinders - /// - public bool SURF; - } - - public static ModePage_03? DecodeModePage_03(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x03) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 24) - return null; - - var decoded = new ModePage_03(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.TracksPerZone = (ushort)((pageResponse[2] << 8) + pageResponse[3]); - decoded.AltSectorsPerZone = (ushort)((pageResponse[4] << 8) + pageResponse[5]); - decoded.AltTracksPerZone = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - decoded.AltTracksPerLun = (ushort)((pageResponse[8] << 8) + pageResponse[9]); - decoded.SectorsPerTrack = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - decoded.BytesPerSector = (ushort)((pageResponse[12] << 8) + pageResponse[13]); - decoded.Interleave = (ushort)((pageResponse[14] << 8) + pageResponse[15]); - decoded.TrackSkew = (ushort)((pageResponse[16] << 8) + pageResponse[17]); - decoded.CylinderSkew = (ushort)((pageResponse[18] << 8) + pageResponse[19]); - decoded.SSEC |= (pageResponse[20] & 0x80) == 0x80; - decoded.HSEC |= (pageResponse[20] & 0x40) == 0x40; - decoded.RMB |= (pageResponse[20] & 0x20) == 0x20; - decoded.SURF |= (pageResponse[20] & 0x10) == 0x10; - - return decoded; - } - - public static string PrettifyModePage_03(byte[] pageResponse) => - PrettifyModePage_03(DecodeModePage_03(pageResponse)); - - public static string PrettifyModePage_03(ModePage_03? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_03 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Format device page:"); - - 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", - 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} 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 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"); - - 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"); - - return sb.ToString(); - } - #endregion Mode Page 0x03: Format device page + /// Parameters can be saved + public bool PS; + /// Tracks per zone to use in dividing the capacity for the purpose of allocating alternate sectors + public ushort TracksPerZone; + /// Number of sectors per zone that shall be reserved for defect handling + public ushort AltSectorsPerZone; + /// Number of tracks per zone that shall be reserved for defect handling + public ushort AltTracksPerZone; + /// Number of tracks per LUN that shall be reserved for defect handling + public ushort AltTracksPerLun; + /// Number of physical sectors per track + public ushort SectorsPerTrack; + /// Bytes per physical sector + public ushort BytesPerSector; + /// Interleave value, target dependent + public ushort Interleave; + /// Sectors between last block of one track and first block of the next + public ushort TrackSkew; + /// Sectors between last block of a cylinder and first block of the next one + public ushort CylinderSkew; + /// Soft-sectored + public bool SSEC; + /// Hard-sectored + public bool HSEC; + /// Removable + public bool RMB; + /// + /// If set, address are allocated progressively in a surface before going to the next. Otherwise, it goes by + /// cylinders + /// + public bool SURF; } + + public static ModePage_03? DecodeModePage_03(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x03) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 24) + return null; + + var decoded = new ModePage_03(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.TracksPerZone = (ushort)((pageResponse[2] << 8) + pageResponse[3]); + decoded.AltSectorsPerZone = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.AltTracksPerZone = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.AltTracksPerLun = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.SectorsPerTrack = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.BytesPerSector = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + decoded.Interleave = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + decoded.TrackSkew = (ushort)((pageResponse[16] << 8) + pageResponse[17]); + decoded.CylinderSkew = (ushort)((pageResponse[18] << 8) + pageResponse[19]); + decoded.SSEC |= (pageResponse[20] & 0x80) == 0x80; + decoded.HSEC |= (pageResponse[20] & 0x40) == 0x40; + decoded.RMB |= (pageResponse[20] & 0x20) == 0x20; + decoded.SURF |= (pageResponse[20] & 0x10) == 0x10; + + return decoded; + } + + public static string PrettifyModePage_03(byte[] pageResponse) => + PrettifyModePage_03(DecodeModePage_03(pageResponse)); + + public static string PrettifyModePage_03(ModePage_03? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_03 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Format device page:"); + + 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", + 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} 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 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"); + + 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"); + + return sb.ToString(); + } + #endregion Mode Page 0x03: Format device page } \ No newline at end of file diff --git a/SCSI/Modes/04.cs b/SCSI/Modes/04.cs index f9e6f90..d08c110 100644 --- a/SCSI/Modes/04.cs +++ b/SCSI/Modes/04.cs @@ -33,130 +33,129 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x04: Rigid disk drive geometry page + /// Disconnect-reconnect page Page code 0x04 24 bytes in SCSI-2, SBC-1 + public struct ModePage_04 { - #region Mode Page 0x04: Rigid disk drive geometry page - /// Disconnect-reconnect page Page code 0x04 24 bytes in SCSI-2, SBC-1 - public struct ModePage_04 - { - /// Parameters can be saved - public bool PS; - /// Cylinders used for data storage - public uint Cylinders; - /// Heads for reading and/or writing - public byte Heads; - /// Cylinder where write precompensation starts - public uint WritePrecompCylinder; - /// Cylinder where write current reduction starts - public uint WriteReduceCylinder; - /// Step rate in 100 ns units - public ushort DriveStepRate; - /// Cylinder where the heads park - public int LandingCylinder; - /// Rotational position locking - public byte RPL; - /// Rotational skew to apply when synchronized - public byte RotationalOffset; - /// Medium speed in rpm - public ushort MediumRotationRate; - } - - public static ModePage_04? DecodeModePage_04(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x04) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 20) - return null; - - 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]; - - if(pageResponse.Length >= 22) - decoded.MediumRotationRate = (ushort)((pageResponse[20] << 8) + pageResponse[21]); - - return decoded; - } - - public static string PrettifyModePage_04(byte[] pageResponse) => - PrettifyModePage_04(DecodeModePage_04(pageResponse)); - - public static string PrettifyModePage_04(ModePage_04? modePage) - { - if(!modePage.HasValue) - return null; - - 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"); - - 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(); - - if(page.WriteReduceCylinder < page.Cylinders) - 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(); - - sb.AppendFormat("\tHeads park in cylinder {0}", page.LandingCylinder).AppendLine(); - - if(page.MediumRotationRate > 0) - sb.AppendFormat("\tMedium rotates at {0} rpm", page.MediumRotationRate).AppendLine(); - - switch(page.RPL) - { - 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; - } - - return sb.ToString(); - } - #endregion Mode Page 0x04: Rigid disk drive geometry page + /// Parameters can be saved + public bool PS; + /// Cylinders used for data storage + public uint Cylinders; + /// Heads for reading and/or writing + public byte Heads; + /// Cylinder where write precompensation starts + public uint WritePrecompCylinder; + /// Cylinder where write current reduction starts + public uint WriteReduceCylinder; + /// Step rate in 100 ns units + public ushort DriveStepRate; + /// Cylinder where the heads park + public int LandingCylinder; + /// Rotational position locking + public byte RPL; + /// Rotational skew to apply when synchronized + public byte RotationalOffset; + /// Medium speed in rpm + public ushort MediumRotationRate; } + + public static ModePage_04? DecodeModePage_04(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x04) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 20) + return null; + + 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]; + + if(pageResponse.Length >= 22) + decoded.MediumRotationRate = (ushort)((pageResponse[20] << 8) + pageResponse[21]); + + return decoded; + } + + public static string PrettifyModePage_04(byte[] pageResponse) => + PrettifyModePage_04(DecodeModePage_04(pageResponse)); + + public static string PrettifyModePage_04(ModePage_04? modePage) + { + if(!modePage.HasValue) + return null; + + 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"); + + 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(); + + if(page.WriteReduceCylinder < page.Cylinders) + 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(); + + sb.AppendFormat("\tHeads park in cylinder {0}", page.LandingCylinder).AppendLine(); + + if(page.MediumRotationRate > 0) + sb.AppendFormat("\tMedium rotates at {0} rpm", page.MediumRotationRate).AppendLine(); + + switch(page.RPL) + { + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x04: Rigid disk drive geometry page } \ No newline at end of file diff --git a/SCSI/Modes/05.cs b/SCSI/Modes/05.cs index fd8a5d8..f419c3e 100644 --- a/SCSI/Modes/05.cs +++ b/SCSI/Modes/05.cs @@ -33,281 +33,280 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x05: Flexible disk page + /// Disconnect-reconnect page Page code 0x05 32 bytes in SCSI-2, SBC-1 + public struct ModePage_05 { - #region Mode Page 0x05: Flexible disk page - /// Disconnect-reconnect page Page code 0x05 32 bytes in SCSI-2, SBC-1 - public struct ModePage_05 - { - /// Parameters can be saved - public bool PS; - /// Data rate of peripheral device on kbit/s - public ushort TransferRate; - /// Heads for reading and/or writing - public byte Heads; - /// Sectors per revolution per head - public byte SectorsPerTrack; - /// Bytes of data per sector - public ushort BytesPerSector; - /// Cylinders used for data storage - public ushort Cylinders; - /// Cylinder where write precompensation starts - public ushort WritePrecompCylinder; - /// Cylinder where write current reduction starts - public ushort WriteReduceCylinder; - /// Step rate in 100 μs units - public ushort DriveStepRate; - /// Width of step pulse in μs - public byte DriveStepPulse; - /// Head settle time in 100 μs units - public ushort HeadSettleDelay; - /// - /// If is true, 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. - /// - public byte MotorOnDelay; - /// - /// 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 - /// - public byte MotorOffDelay; - /// Specifies if a signal indicates that the medium is ready to be accessed - public bool TRDY; - /// If true sectors start with one. Otherwise, they start with zero. - public bool SSN; - /// If true specifies that motor on shall remain released. - public bool MO; - /// Number of additional step pulses per cylinder. - public byte SPC; - /// Write compensation value - public byte WriteCompensation; - /// Head loading time in ms. - public byte HeadLoadDelay; - /// Head unloading time in ms. - public byte HeadUnloadDelay; - /// Description of shugart's bus pin 34 usage - public byte Pin34; - /// Description of shugart's bus pin 2 usage - public byte Pin2; - /// Description of shugart's bus pin 4 usage - public byte Pin4; - /// Description of shugart's bus pin 1 usage - public byte Pin1; - /// Medium speed in rpm - public ushort MediumRotationRate; - } - - public static ModePage_05? DecodeModePage_05(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x05) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 32) - return null; - - var decoded = new ModePage_05(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.TransferRate = (ushort)((pageResponse[2] << 8) + pageResponse[3]); - decoded.Heads = pageResponse[4]; - decoded.SectorsPerTrack = pageResponse[5]; - decoded.BytesPerSector = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - decoded.Cylinders = (ushort)((pageResponse[8] << 8) + pageResponse[9]); - decoded.WritePrecompCylinder = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - decoded.WriteReduceCylinder = (ushort)((pageResponse[12] << 8) + pageResponse[13]); - decoded.DriveStepRate = (ushort)((pageResponse[14] << 8) + pageResponse[15]); - decoded.DriveStepPulse = pageResponse[16]; - decoded.HeadSettleDelay = (ushort)((pageResponse[17] << 8) + pageResponse[18]); - decoded.MotorOnDelay = pageResponse[19]; - decoded.MotorOffDelay = pageResponse[20]; - decoded.TRDY |= (pageResponse[21] & 0x80) == 0x80; - decoded.SSN |= (pageResponse[21] & 0x40) == 0x40; - decoded.MO |= (pageResponse[21] & 0x20) == 0x20; - decoded.SPC = (byte)(pageResponse[22] & 0x0F); - decoded.WriteCompensation = pageResponse[23]; - decoded.HeadLoadDelay = pageResponse[24]; - decoded.HeadUnloadDelay = pageResponse[25]; - decoded.Pin34 = (byte)((pageResponse[26] & 0xF0) >> 4); - decoded.Pin2 = (byte)(pageResponse[26] & 0x0F); - decoded.Pin4 = (byte)((pageResponse[27] & 0xF0) >> 4); - decoded.Pin1 = (byte)(pageResponse[27] & 0x0F); - decoded.MediumRotationRate = (ushort)((pageResponse[28] << 8) + pageResponse[29]); - - return decoded; - } - - public static string PrettifyModePage_05(byte[] pageResponse) => - PrettifyModePage_05(DecodeModePage_05(pageResponse)); - - public static string PrettifyModePage_05(ModePage_05? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_05 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Flexible disk page:"); - - 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(); - - if(page.WriteReduceCylinder < page.Cylinders) - 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", - (double)page.MotorOnDelay * 10).AppendLine(); - else - 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", - (double)page.MotorOffDelay * 10).AppendLine(); - 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"); - - 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.HeadUnloadDelay > 0) - sb.AppendFormat("\tHead takes {0} ms to unload", page.HeadUnloadDelay).AppendLine(); - - if(page.MediumRotationRate > 0) - sb.AppendFormat("\tMedium rotates at {0} rpm", page.MediumRotationRate).AppendLine(); - - switch(page.Pin34 & 0x07) - { - 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; - } - - switch(page.Pin4 & 0x07) - { - 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; - } - - switch(page.Pin2 & 0x07) - { - 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; - } - - switch(page.Pin1 & 0x07) - { - 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; - } - - return sb.ToString(); - } - #endregion Mode Page 0x05: Flexible disk page + /// Parameters can be saved + public bool PS; + /// Data rate of peripheral device on kbit/s + public ushort TransferRate; + /// Heads for reading and/or writing + public byte Heads; + /// Sectors per revolution per head + public byte SectorsPerTrack; + /// Bytes of data per sector + public ushort BytesPerSector; + /// Cylinders used for data storage + public ushort Cylinders; + /// Cylinder where write precompensation starts + public ushort WritePrecompCylinder; + /// Cylinder where write current reduction starts + public ushort WriteReduceCylinder; + /// Step rate in 100 μs units + public ushort DriveStepRate; + /// Width of step pulse in μs + public byte DriveStepPulse; + /// Head settle time in 100 μs units + public ushort HeadSettleDelay; + /// + /// If is true, 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. + /// + public byte MotorOnDelay; + /// + /// 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 + /// + public byte MotorOffDelay; + /// Specifies if a signal indicates that the medium is ready to be accessed + public bool TRDY; + /// If true sectors start with one. Otherwise, they start with zero. + public bool SSN; + /// If true specifies that motor on shall remain released. + public bool MO; + /// Number of additional step pulses per cylinder. + public byte SPC; + /// Write compensation value + public byte WriteCompensation; + /// Head loading time in ms. + public byte HeadLoadDelay; + /// Head unloading time in ms. + public byte HeadUnloadDelay; + /// Description of shugart's bus pin 34 usage + public byte Pin34; + /// Description of shugart's bus pin 2 usage + public byte Pin2; + /// Description of shugart's bus pin 4 usage + public byte Pin4; + /// Description of shugart's bus pin 1 usage + public byte Pin1; + /// Medium speed in rpm + public ushort MediumRotationRate; } + + public static ModePage_05? DecodeModePage_05(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x05) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 32) + return null; + + var decoded = new ModePage_05(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.TransferRate = (ushort)((pageResponse[2] << 8) + pageResponse[3]); + decoded.Heads = pageResponse[4]; + decoded.SectorsPerTrack = pageResponse[5]; + decoded.BytesPerSector = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.Cylinders = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.WritePrecompCylinder = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.WriteReduceCylinder = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + decoded.DriveStepRate = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + decoded.DriveStepPulse = pageResponse[16]; + decoded.HeadSettleDelay = (ushort)((pageResponse[17] << 8) + pageResponse[18]); + decoded.MotorOnDelay = pageResponse[19]; + decoded.MotorOffDelay = pageResponse[20]; + decoded.TRDY |= (pageResponse[21] & 0x80) == 0x80; + decoded.SSN |= (pageResponse[21] & 0x40) == 0x40; + decoded.MO |= (pageResponse[21] & 0x20) == 0x20; + decoded.SPC = (byte)(pageResponse[22] & 0x0F); + decoded.WriteCompensation = pageResponse[23]; + decoded.HeadLoadDelay = pageResponse[24]; + decoded.HeadUnloadDelay = pageResponse[25]; + decoded.Pin34 = (byte)((pageResponse[26] & 0xF0) >> 4); + decoded.Pin2 = (byte)(pageResponse[26] & 0x0F); + decoded.Pin4 = (byte)((pageResponse[27] & 0xF0) >> 4); + decoded.Pin1 = (byte)(pageResponse[27] & 0x0F); + decoded.MediumRotationRate = (ushort)((pageResponse[28] << 8) + pageResponse[29]); + + return decoded; + } + + public static string PrettifyModePage_05(byte[] pageResponse) => + PrettifyModePage_05(DecodeModePage_05(pageResponse)); + + public static string PrettifyModePage_05(ModePage_05? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_05 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Flexible disk page:"); + + 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(); + + if(page.WriteReduceCylinder < page.Cylinders) + 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", + (double)page.MotorOnDelay * 10).AppendLine(); + else + 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", + (double)page.MotorOffDelay * 10).AppendLine(); + 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"); + + 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.HeadUnloadDelay > 0) + sb.AppendFormat("\tHead takes {0} ms to unload", page.HeadUnloadDelay).AppendLine(); + + if(page.MediumRotationRate > 0) + sb.AppendFormat("\tMedium rotates at {0} rpm", page.MediumRotationRate).AppendLine(); + + switch(page.Pin34 & 0x07) + { + 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; + } + + switch(page.Pin4 & 0x07) + { + 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; + } + + switch(page.Pin2 & 0x07) + { + 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; + } + + switch(page.Pin1 & 0x07) + { + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x05: Flexible disk page } \ No newline at end of file diff --git a/SCSI/Modes/06.cs b/SCSI/Modes/06.cs index 6998d49..bf233ae 100644 --- a/SCSI/Modes/06.cs +++ b/SCSI/Modes/06.cs @@ -33,65 +33,64 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x06: Optical memory page + /// Optical memory page Page code 0x06 4 bytes in SCSI-2 + public struct ModePage_06 { - #region Mode Page 0x06: Optical memory page - /// Optical memory page Page code 0x06 4 bytes in SCSI-2 - public struct ModePage_06 - { - /// Parameters can be saved - public bool PS; - /// Report updated block read - public bool RUBR; - } - - public static ModePage_06? DecodeModePage_06(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x06) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 4) - return null; - - var decoded = new ModePage_06(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.RUBR |= (pageResponse[2] & 0x01) == 0x01; - - return decoded; - } - - public static string PrettifyModePage_06(byte[] pageResponse) => - PrettifyModePage_06(DecodeModePage_06(pageResponse)); - - public static string PrettifyModePage_06(ModePage_06? modePage) - { - if(!modePage.HasValue) - return null; - - 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"); - - return sb.ToString(); - } - #endregion Mode Page 0x06: Optical memory page + /// Parameters can be saved + public bool PS; + /// Report updated block read + public bool RUBR; } + + public static ModePage_06? DecodeModePage_06(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x06) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 4) + return null; + + var decoded = new ModePage_06(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.RUBR |= (pageResponse[2] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyModePage_06(byte[] pageResponse) => + PrettifyModePage_06(DecodeModePage_06(pageResponse)); + + public static string PrettifyModePage_06(ModePage_06? modePage) + { + if(!modePage.HasValue) + return null; + + 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"); + + return sb.ToString(); + } + #endregion Mode Page 0x06: Optical memory page } \ No newline at end of file diff --git a/SCSI/Modes/07.cs b/SCSI/Modes/07.cs index 3544c11..b82f9e9 100644 --- a/SCSI/Modes/07.cs +++ b/SCSI/Modes/07.cs @@ -33,100 +33,99 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes { - [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 + /// Disconnect-reconnect page Page code 0x07 12 bytes in SCSI-2, SBC-1, SBC-2 + public struct ModePage_07 { - #region Mode Page 0x07: Verify error recovery page - /// Disconnect-reconnect page Page code 0x07 12 bytes in SCSI-2, SBC-1, SBC-2 - public struct ModePage_07 - { - /// Parameters can be saved - public bool PS; - /// Enable early recovery - public bool EER; - /// Post error reporting - public bool PER; - /// Disable transfer on error - public bool DTE; - /// Disable correction - public bool DCR; - /// How many times to retry a verify operation - public byte VerifyRetryCount; - /// How many bits of largest data burst error is maximum to apply error correction on it - public byte CorrectionSpan; - /// Maximum time in ms to use in data error recovery procedures - public ushort RecoveryTimeLimit; - } - - public static ModePage_07? DecodeModePage_07(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x07) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 12) - return null; - - var decoded = new ModePage_07(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - 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.VerifyRetryCount = pageResponse[3]; - decoded.CorrectionSpan = pageResponse[4]; - decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - - return decoded; - } - - public static string PrettifyModePage_07(byte[] pageResponse) => - PrettifyModePage_07(DecodeModePage_07(pageResponse)); - - public static string PrettifyModePage_07(ModePage_07? modePage) - { - if(!modePage.HasValue) - return null; - - 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.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(); - - return sb.ToString(); - } - #endregion Mode Page 0x07: Verify error recovery page + /// Parameters can be saved + public bool PS; + /// Enable early recovery + public bool EER; + /// Post error reporting + public bool PER; + /// Disable transfer on error + public bool DTE; + /// Disable correction + public bool DCR; + /// How many times to retry a verify operation + public byte VerifyRetryCount; + /// How many bits of largest data burst error is maximum to apply error correction on it + public byte CorrectionSpan; + /// Maximum time in ms to use in data error recovery procedures + public ushort RecoveryTimeLimit; } + + public static ModePage_07? DecodeModePage_07(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x07) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 12) + return null; + + var decoded = new ModePage_07(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + 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.VerifyRetryCount = pageResponse[3]; + decoded.CorrectionSpan = pageResponse[4]; + decoded.RecoveryTimeLimit = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + return decoded; + } + + public static string PrettifyModePage_07(byte[] pageResponse) => + PrettifyModePage_07(DecodeModePage_07(pageResponse)); + + public static string PrettifyModePage_07(ModePage_07? modePage) + { + if(!modePage.HasValue) + return null; + + 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.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(); + + return sb.ToString(); + } + #endregion Mode Page 0x07: Verify error recovery page } \ No newline at end of file diff --git a/SCSI/Modes/07_MMC.cs b/SCSI/Modes/07_MMC.cs index 8ea3a93..6b00178 100644 --- a/SCSI/Modes/07_MMC.cs +++ b/SCSI/Modes/07_MMC.cs @@ -33,160 +33,159 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 + /// Verify error recovery page for MultiMedia Devices Page code 0x07 8 bytes in SCSI-2, MMC-1 + public struct ModePage_07_MMC { - #region Mode Page 0x07: Verify error recovery page for MultiMedia Devices - /// Verify error recovery page for MultiMedia Devices Page code 0x07 8 bytes in SCSI-2, MMC-1 - public struct ModePage_07_MMC - { - /// Parameters can be saved - public bool PS; - /// Error recovery parameter - public byte Parameter; - /// How many times to retry a verify operation - public byte VerifyRetryCount; - } - - public static ModePage_07_MMC? DecodeModePage_07_MMC(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x07) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 8) - return null; - - var decoded = new ModePage_07_MMC(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.Parameter = pageResponse[2]; - decoded.VerifyRetryCount = pageResponse[3]; - - return decoded; - } - - public static string PrettifyModePage_07_MMC(byte[] pageResponse) => - PrettifyModePage_07_MMC(DecodeModePage_07_MMC(pageResponse)); - - public static string PrettifyModePage_07_MMC(ModePage_07_MMC? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_07_MMC page = modePage.Value; - 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.VerifyRetryCount > 0) - sb.AppendFormat("\tDrive will repeat verify operations {0} times", page.VerifyRetryCount).AppendLine(); - - string AllUsed = "\tAll available recovery procedures will be used.\n"; - string CIRCRetriesUsed = "\tOnly retries and CIRC are used.\n"; - string RetriesUsed = "\tOnly retries are used.\n"; - string RecoveredNotReported = "\tRecovered errors will not be reported.\n"; - string RecoveredReported = "\tRecovered errors will be reported.\n"; - string RecoveredAbort = "\tRecovered errors will be reported and aborted with CHECK CONDITION.\n"; - string UnrecECCAbort = "\tUnrecovered ECC errors will return CHECK CONDITION."; - 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."; - - switch(page.Parameter) - { - 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; - case 0x34: goto case 0x14; - case 0x35: goto case 0x15; - default: - sb.AppendFormat("Unknown recovery parameter 0x{0:X2}", page.Parameter).AppendLine(); - - break; - } - - return sb.ToString(); - } - #endregion Mode Page 0x07: Verify error recovery page for MultiMedia Devices + /// Parameters can be saved + public bool PS; + /// Error recovery parameter + public byte Parameter; + /// How many times to retry a verify operation + public byte VerifyRetryCount; } + + public static ModePage_07_MMC? DecodeModePage_07_MMC(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x07) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + var decoded = new ModePage_07_MMC(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.Parameter = pageResponse[2]; + decoded.VerifyRetryCount = pageResponse[3]; + + return decoded; + } + + public static string PrettifyModePage_07_MMC(byte[] pageResponse) => + PrettifyModePage_07_MMC(DecodeModePage_07_MMC(pageResponse)); + + public static string PrettifyModePage_07_MMC(ModePage_07_MMC? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_07_MMC page = modePage.Value; + 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.VerifyRetryCount > 0) + sb.AppendFormat("\tDrive will repeat verify operations {0} times", page.VerifyRetryCount).AppendLine(); + + string AllUsed = "\tAll available recovery procedures will be used.\n"; + string CIRCRetriesUsed = "\tOnly retries and CIRC are used.\n"; + string RetriesUsed = "\tOnly retries are used.\n"; + string RecoveredNotReported = "\tRecovered errors will not be reported.\n"; + string RecoveredReported = "\tRecovered errors will be reported.\n"; + string RecoveredAbort = "\tRecovered errors will be reported and aborted with CHECK CONDITION.\n"; + string UnrecECCAbort = "\tUnrecovered ECC errors will return CHECK CONDITION."; + 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."; + + switch(page.Parameter) + { + 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; + case 0x34: goto case 0x14; + case 0x35: goto case 0x15; + default: + sb.AppendFormat("Unknown recovery parameter 0x{0:X2}", page.Parameter).AppendLine(); + + break; + } + + return sb.ToString(); + } + #endregion Mode Page 0x07: Verify error recovery page for MultiMedia Devices } \ No newline at end of file diff --git a/SCSI/Modes/08.cs b/SCSI/Modes/08.cs index 09e250b..1015426 100644 --- a/SCSI/Modes/08.cs +++ b/SCSI/Modes/08.cs @@ -33,247 +33,246 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x08: Caching page + /// Disconnect-reconnect page Page code 0x08 12 bytes in SCSI-2 20 bytes in SBC-1, SBC-2, SBC-3 + public struct ModePage_08 { - #region Mode Page 0x08: Caching page - /// Disconnect-reconnect page Page code 0x08 12 bytes in SCSI-2 20 bytes in SBC-1, SBC-2, SBC-3 - public struct ModePage_08 - { - /// Parameters can be saved - public bool PS; - /// true if write cache is enabled - public bool WCE; - /// Multiplication factor - public bool MF; - /// true if read cache is enabled - public bool RCD; - /// Advices on reading-cache retention priority - public byte DemandReadRetentionPrio; - /// Advices on writing-cache retention priority - public byte WriteRetentionPriority; - /// If requested read blocks are more than this, no pre-fetch is done - public ushort DisablePreFetch; - /// Minimum pre-fetch - public ushort MinimumPreFetch; - /// Maximum pre-fetch - public ushort MaximumPreFetch; - /// Upper limit on maximum pre-fetch value - public ushort MaximumPreFetchCeiling; + /// Parameters can be saved + public bool PS; + /// true if write cache is enabled + public bool WCE; + /// Multiplication factor + public bool MF; + /// true if read cache is enabled + public bool RCD; + /// Advices on reading-cache retention priority + public byte DemandReadRetentionPrio; + /// Advices on writing-cache retention priority + public byte WriteRetentionPriority; + /// If requested read blocks are more than this, no pre-fetch is done + public ushort DisablePreFetch; + /// Minimum pre-fetch + public ushort MinimumPreFetch; + /// Maximum pre-fetch + public ushort MaximumPreFetch; + /// Upper limit on maximum pre-fetch value + public ushort MaximumPreFetchCeiling; - /// Manual cache controlling - public bool IC; - /// Abort pre-fetch - public bool ABPF; - /// Caching analysis permitted - public bool CAP; - /// Pre-fetch over discontinuities - public bool Disc; - /// is to be used to control caching segmentation - public bool Size; - /// Force sequential write - public bool FSW; - /// Logical block cache segment size - public bool LBCSS; - /// Disable read-ahead - public bool DRA; - /// How many segments should the cache be divided upon - public byte CacheSegments; - /// How many bytes should the cache be divided upon - public ushort CacheSegmentSize; - /// How many bytes should be used as a buffer when all other cached data cannot be evicted - public uint NonCacheSegmentSize; + /// Manual cache controlling + public bool IC; + /// Abort pre-fetch + public bool ABPF; + /// Caching analysis permitted + public bool CAP; + /// Pre-fetch over discontinuities + public bool Disc; + /// is to be used to control caching segmentation + public bool Size; + /// Force sequential write + public bool FSW; + /// Logical block cache segment size + public bool LBCSS; + /// Disable read-ahead + public bool DRA; + /// How many segments should the cache be divided upon + public byte CacheSegments; + /// How many bytes should the cache be divided upon + public ushort CacheSegmentSize; + /// How many bytes should be used as a buffer when all other cached data cannot be evicted + public uint NonCacheSegmentSize; - public bool NV_DIS; - } + public bool NV_DIS; + } - public static ModePage_08? DecodeModePage_08(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; + public static ModePage_08? DecodeModePage_08(byte[] pageResponse) + { + 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; - var decoded = new ModePage_08(); + var decoded = new ModePage_08(); - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.WCE |= (pageResponse[2] & 0x04) == 0x04; - decoded.MF |= (pageResponse[2] & 0x02) == 0x02; - decoded.RCD |= (pageResponse[2] & 0x01) == 0x01; + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.WCE |= (pageResponse[2] & 0x04) == 0x04; + decoded.MF |= (pageResponse[2] & 0x02) == 0x02; + decoded.RCD |= (pageResponse[2] & 0x01) == 0x01; - decoded.DemandReadRetentionPrio = (byte)((pageResponse[3] & 0xF0) >> 4); - decoded.WriteRetentionPriority = (byte)(pageResponse[3] & 0x0F); - decoded.DisablePreFetch = (ushort)((pageResponse[4] << 8) + pageResponse[5]); - decoded.MinimumPreFetch = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - decoded.MaximumPreFetch = (ushort)((pageResponse[8] << 8) + pageResponse[9]); - decoded.MaximumPreFetchCeiling = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - - if(pageResponse.Length < 20) - return decoded; - - decoded.IC |= (pageResponse[2] & 0x80) == 0x80; - decoded.ABPF |= (pageResponse[2] & 0x40) == 0x40; - decoded.CAP |= (pageResponse[2] & 0x20) == 0x20; - decoded.Disc |= (pageResponse[2] & 0x10) == 0x10; - decoded.Size |= (pageResponse[2] & 0x08) == 0x08; - - decoded.FSW |= (pageResponse[12] & 0x80) == 0x80; - decoded.LBCSS |= (pageResponse[12] & 0x40) == 0x40; - decoded.DRA |= (pageResponse[12] & 0x20) == 0x20; - - decoded.CacheSegments = pageResponse[13]; - decoded.CacheSegmentSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]); - decoded.NonCacheSegmentSize = (uint)((pageResponse[17] << 16) + (pageResponse[18] << 8) + pageResponse[19]); - - decoded.NV_DIS |= (pageResponse[12] & 0x01) == 0x01; + decoded.DemandReadRetentionPrio = (byte)((pageResponse[3] & 0xF0) >> 4); + decoded.WriteRetentionPriority = (byte)(pageResponse[3] & 0x0F); + decoded.DisablePreFetch = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.MinimumPreFetch = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.MaximumPreFetch = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.MaximumPreFetchCeiling = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + if(pageResponse.Length < 20) return decoded; + + decoded.IC |= (pageResponse[2] & 0x80) == 0x80; + decoded.ABPF |= (pageResponse[2] & 0x40) == 0x40; + decoded.CAP |= (pageResponse[2] & 0x20) == 0x20; + decoded.Disc |= (pageResponse[2] & 0x10) == 0x10; + decoded.Size |= (pageResponse[2] & 0x08) == 0x08; + + decoded.FSW |= (pageResponse[12] & 0x80) == 0x80; + decoded.LBCSS |= (pageResponse[12] & 0x40) == 0x40; + decoded.DRA |= (pageResponse[12] & 0x20) == 0x20; + + decoded.CacheSegments = pageResponse[13]; + decoded.CacheSegmentSize = (ushort)((pageResponse[14] << 8) + pageResponse[15]); + decoded.NonCacheSegmentSize = (uint)((pageResponse[17] << 16) + (pageResponse[18] << 8) + pageResponse[19]); + + decoded.NV_DIS |= (pageResponse[12] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyModePage_08(byte[] pageResponse) => + PrettifyModePage_08(DecodeModePage_08(pageResponse)); + + public static string PrettifyModePage_08(ModePage_08? modePage) + { + if(!modePage.HasValue) + return null; + + 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"); + + 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(); + + break; } - public static string PrettifyModePage_08(byte[] pageResponse) => - PrettifyModePage_08(DecodeModePage_08(pageResponse)); - - public static string PrettifyModePage_08(ModePage_08? modePage) + switch(page.WriteRetentionPriority) { - if(!modePage.HasValue) - return null; + case 0: + sb.AppendLine("\tDrive does not distinguish between cached write data"); - ModePage_08 page = modePage.Value; - var sb = new StringBuilder(); + 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"); - sb.AppendLine("SCSI Caching mode page:"); + 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"); - if(page.PS) - sb.AppendLine("\tParameters can be saved"); + break; + default: + sb.AppendFormat("\tUnknown demand write retention priority value {0}", + page.DemandReadRetentionPrio).AppendLine(); - if(page.RCD) - sb.AppendLine("\tRead-cache is enabled"); + break; + } - if(page.WCE) - sb.AppendLine("\tWrite-cache is enabled"); + if(page.DRA) + sb.AppendLine("\tRead-ahead is disabled"); + else + { + if(page.MF) + sb.AppendLine("\tPre-fetch values indicate a block multiplier"); - switch(page.DemandReadRetentionPrio) + if(page.DisablePreFetch == 0) + sb.AppendLine("\tNo pre-fetch will be done"); + else { - case 0: - sb.AppendLine("\tDrive does not distinguish between cached read data"); + sb.AppendFormat("\tPre-fetch will be done for READ commands of {0} blocks or less", + page.DisablePreFetch).AppendLine(); - 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). + if(page.MinimumPreFetch > 0) + sb.AppendFormat("At least {0} blocks will be always pre-fetched", page.MinimumPreFetch). AppendLine(); - break; + if(page.MaximumPreFetch > 0) + 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", + 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.Disc) + sb.AppendLine("\tPre-fetch can continue across discontinuities (such as cylinders or tracks)"); } - - switch(page.WriteRetentionPriority) - { - 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(); - - break; - } - - if(page.DRA) - sb.AppendLine("\tRead-ahead is disabled"); - else - { - if(page.MF) - sb.AppendLine("\tPre-fetch values indicate a block multiplier"); - - 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(); - - if(page.MaximumPreFetch > 0) - 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", - 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.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.Size) - { - if(page.CacheSegmentSize > 0) - if(page.LBCSS) - 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(); - } - else - { - if(page.CacheSegments > 0) - sb.AppendFormat("\tDrive should have {0} cache segments", page.CacheSegments).AppendLine(); - } - - if(page.NonCacheSegmentSize > 0) - 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"); - - return sb.ToString(); } - #endregion Mode Page 0x08: Caching page + + 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(); + else + sb.AppendFormat("\tDrive cache segments should be {0} bytes long", page.CacheSegmentSize). + AppendLine(); + } + else + { + if(page.CacheSegments > 0) + sb.AppendFormat("\tDrive should have {0} cache segments", page.CacheSegments).AppendLine(); + } + + if(page.NonCacheSegmentSize > 0) + 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"); + + return sb.ToString(); } + #endregion Mode Page 0x08: Caching page } \ No newline at end of file diff --git a/SCSI/Modes/0A.cs b/SCSI/Modes/0A.cs index 13cb1b4..34d4490 100644 --- a/SCSI/Modes/0A.cs +++ b/SCSI/Modes/0A.cs @@ -33,415 +33,414 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x0A: Control mode page + /// Control mode page Page code 0x0A 8 bytes in SCSI-2 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 + public struct ModePage_0A { - #region Mode Page 0x0A: Control mode page - /// Control mode page Page code 0x0A 8 bytes in SCSI-2 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4, SPC-5 - public struct ModePage_0A - { - /// Parameters can be saved - public bool PS; - /// If set, target shall report log exception conditions - public bool RLEC; - /// Queue algorithm modifier - public byte QueueAlgorithm; - /// - /// If set all remaining suspended I/O processes shall be aborted after the contingent allegiance condition or - /// extended contingent allegiance condition - /// - public byte QErr; - /// Tagged queuing is disabled - public bool DQue; - /// Extended Contingent Allegiance is enabled - public bool EECA; - /// Target may issue an asynchronous event notification upon completing its initialization - public bool RAENP; - /// Target may issue an asynchronous event notification instead of a unit attention condition - public bool UAAENP; - /// Target may issue an asynchronous event notification instead of a deferred error - public bool EAENP; - /// Minimum time in ms after initialization before attempting asynchronous event notifications - public ushort ReadyAENHoldOffPeriod; - - /// Global logging target save disabled - public bool GLTSD; - /// CHECK CONDITION should be reported rather than a long busy condition - public bool RAC; - /// Software write protect is active - public bool SWP; - /// Maximum time in 100 ms units allowed to remain busy. 0xFFFF == unlimited. - public ushort BusyTimeoutPeriod; - - /// Task set type - public byte TST; - /// Tasks aborted by other initiator's actions should be terminated with TASK ABORTED - public bool TAS; - /// Action to be taken when a medium is inserted - public byte AutoloadMode; - /// Time in seconds to complete an extended self-test - public byte ExtendedSelfTestCompletionTime; - - /// All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate - public bool TMF_ONLY; - /// - /// Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK - /// CONDITION - /// - public bool D_SENSE; - /// Unit attention interlocks control - public byte UA_INTLCK_CTRL; - /// LOGICAL BLOCK APPLICATION TAG should not be modified - public bool ATO; - - /// Protector information checking is disabled - public bool DPICZ; - /// No unit attention on release - public bool NUAR; - /// Application Tag mode page is enabled - public bool ATMPE; - /// Abort any write command without protection information - public bool RWWP; - /// Supportes block lengths and protection information - public bool SBLP; - } - - public static ModePage_0A? DecodeModePage_0A(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x0A) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 8) - return null; - - var decoded = new ModePage_0A(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.RLEC |= (pageResponse[2] & 0x01) == 0x01; - - decoded.QueueAlgorithm = (byte)((pageResponse[3] & 0xF0) >> 4); - decoded.QErr = (byte)((pageResponse[3] & 0x06) >> 1); - - decoded.DQue |= (pageResponse[3] & 0x01) == 0x01; - decoded.EECA |= (pageResponse[4] & 0x80) == 0x80; - decoded.RAENP |= (pageResponse[4] & 0x04) == 0x04; - decoded.UAAENP |= (pageResponse[4] & 0x02) == 0x02; - decoded.EAENP |= (pageResponse[4] & 0x01) == 0x01; - - decoded.ReadyAENHoldOffPeriod = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - - if(pageResponse.Length < 10) - return decoded; - - // SPC-1 - decoded.GLTSD |= (pageResponse[2] & 0x02) == 0x02; - decoded.RAC |= (pageResponse[4] & 0x40) == 0x40; - decoded.SWP |= (pageResponse[4] & 0x08) == 0x08; - - decoded.BusyTimeoutPeriod = (ushort)((pageResponse[8] << 8) + pageResponse[9]); - - // SPC-2 - decoded.TST = (byte)((pageResponse[2] & 0xE0) >> 5); - decoded.TAS |= (pageResponse[4] & 0x80) == 0x80; - decoded.AutoloadMode = (byte)(pageResponse[5] & 0x07); - decoded.BusyTimeoutPeriod = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - - // SPC-3 - decoded.TMF_ONLY |= (pageResponse[2] & 0x10) == 0x10; - decoded.D_SENSE |= (pageResponse[2] & 0x04) == 0x04; - decoded.UA_INTLCK_CTRL = (byte)((pageResponse[4] & 0x30) >> 4); - decoded.TAS |= (pageResponse[5] & 0x40) == 0x40; - decoded.ATO |= (pageResponse[5] & 0x80) == 0x80; - - // SPC-5 - decoded.DPICZ |= (pageResponse[2] & 0x08) == 0x08; - decoded.NUAR |= (pageResponse[3] & 0x08) == 0x08; - decoded.ATMPE |= (pageResponse[5] & 0x20) == 0x20; - decoded.RWWP |= (pageResponse[5] & 0x10) == 0x10; - decoded.SBLP |= (pageResponse[5] & 0x08) == 0x08; - - return decoded; - } - - public static string PrettifyModePage_0A(byte[] pageResponse) => - PrettifyModePage_0A(DecodeModePage_0A(pageResponse)); - - public static string PrettifyModePage_0A(ModePage_0A? modePage) - { - if(!modePage.HasValue) - return null; - - 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.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.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"); - - 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; - } - - switch(page.QueueAlgorithm) - { - 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; - } - - switch(page.QErr) - { - 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; - } - - switch(page.UA_INTLCK_CTRL) - { - 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; - } - - switch(page.AutoloadMode) - { - 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; - } - - if(page.ReadyAENHoldOffPeriod > 0) - sb.AppendFormat("\t{0} ms before attempting asynchronous event notifications after initialization", - page.ReadyAENHoldOffPeriod).AppendLine(); - - if(page.BusyTimeoutPeriod > 0) - 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(); - - if(page.ExtendedSelfTestCompletionTime > 0) - sb.AppendFormat("\t{0} seconds to complete extended self-test", page.ExtendedSelfTestCompletionTime); - - return sb.ToString(); - } - #endregion Mode Page 0x0A: Control mode page - - #region Mode Page 0x0A subpage 0x01: Control Extension mode page - /// Control Extension mode page Page code 0x0A Subpage code 0x01 32 bytes in SPC-3, SPC-4, SPC-5 - public struct ModePage_0A_S01 - { - /// Parameters can be saved - public bool PS; - /// Timestamp outside this standard - public bool TCMOS; - /// SCSI precedence - public bool SCSIP; - /// Implicit Asymmetric Logical Unit Access Enabled - public bool IALUAE; - /// Initial task priority - public byte InitialPriority; - - /// Device life control disabled - public bool DLC; - /// Maximum size of SENSE data in bytes - public byte MaximumSenseLength; - } - - public static ModePage_0A_S01? DecodeModePage_0A_S01(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) != 0x40) - return null; - - if((pageResponse[0] & 0x3F) != 0x0A) - return null; - - if(pageResponse[1] != 0x01) - return null; - - if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 32) - return null; - - var decoded = new ModePage_0A_S01(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.IALUAE |= (pageResponse[4] & 0x01) == 0x01; - decoded.SCSIP |= (pageResponse[4] & 0x02) == 0x02; - decoded.TCMOS |= (pageResponse[4] & 0x04) == 0x04; - - decoded.InitialPriority = (byte)(pageResponse[5] & 0x0F); - - return decoded; - } - - public static string PrettifyModePage_0A_S01(byte[] pageResponse) => - PrettifyModePage_0A_S01(DecodeModePage_0A_S01(pageResponse)); - - public static string PrettifyModePage_0A_S01(ModePage_0A_S01? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_0A_S01 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Control extension page:"); - - 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"); - - sb.AppendLine(); - } - - 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.MaximumSenseLength > 0) - sb.AppendFormat("\tMaximum sense data would be {0} bytes", page.MaximumSenseLength).AppendLine(); - - return sb.ToString(); - } - #endregion Mode Page 0x0A subpage 0x01: Control Extension mode page + /// Parameters can be saved + public bool PS; + /// If set, target shall report log exception conditions + public bool RLEC; + /// Queue algorithm modifier + public byte QueueAlgorithm; + /// + /// If set all remaining suspended I/O processes shall be aborted after the contingent allegiance condition or + /// extended contingent allegiance condition + /// + public byte QErr; + /// Tagged queuing is disabled + public bool DQue; + /// Extended Contingent Allegiance is enabled + public bool EECA; + /// Target may issue an asynchronous event notification upon completing its initialization + public bool RAENP; + /// Target may issue an asynchronous event notification instead of a unit attention condition + public bool UAAENP; + /// Target may issue an asynchronous event notification instead of a deferred error + public bool EAENP; + /// Minimum time in ms after initialization before attempting asynchronous event notifications + public ushort ReadyAENHoldOffPeriod; + + /// Global logging target save disabled + public bool GLTSD; + /// CHECK CONDITION should be reported rather than a long busy condition + public bool RAC; + /// Software write protect is active + public bool SWP; + /// Maximum time in 100 ms units allowed to remain busy. 0xFFFF == unlimited. + public ushort BusyTimeoutPeriod; + + /// Task set type + public byte TST; + /// Tasks aborted by other initiator's actions should be terminated with TASK ABORTED + public bool TAS; + /// Action to be taken when a medium is inserted + public byte AutoloadMode; + /// Time in seconds to complete an extended self-test + public byte ExtendedSelfTestCompletionTime; + + /// All tasks received in nexus with ACA ACTIVE is set and an ACA condition is established shall terminate + public bool TMF_ONLY; + /// + /// Device shall return descriptor format sense data when returning sense data in the same transactions as a CHECK + /// CONDITION + /// + public bool D_SENSE; + /// Unit attention interlocks control + public byte UA_INTLCK_CTRL; + /// LOGICAL BLOCK APPLICATION TAG should not be modified + public bool ATO; + + /// Protector information checking is disabled + public bool DPICZ; + /// No unit attention on release + public bool NUAR; + /// Application Tag mode page is enabled + public bool ATMPE; + /// Abort any write command without protection information + public bool RWWP; + /// Supportes block lengths and protection information + public bool SBLP; } + + public static ModePage_0A? DecodeModePage_0A(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x0A) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + var decoded = new ModePage_0A(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.RLEC |= (pageResponse[2] & 0x01) == 0x01; + + decoded.QueueAlgorithm = (byte)((pageResponse[3] & 0xF0) >> 4); + decoded.QErr = (byte)((pageResponse[3] & 0x06) >> 1); + + decoded.DQue |= (pageResponse[3] & 0x01) == 0x01; + decoded.EECA |= (pageResponse[4] & 0x80) == 0x80; + decoded.RAENP |= (pageResponse[4] & 0x04) == 0x04; + decoded.UAAENP |= (pageResponse[4] & 0x02) == 0x02; + decoded.EAENP |= (pageResponse[4] & 0x01) == 0x01; + + decoded.ReadyAENHoldOffPeriod = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + + if(pageResponse.Length < 10) + return decoded; + + // SPC-1 + decoded.GLTSD |= (pageResponse[2] & 0x02) == 0x02; + decoded.RAC |= (pageResponse[4] & 0x40) == 0x40; + decoded.SWP |= (pageResponse[4] & 0x08) == 0x08; + + decoded.BusyTimeoutPeriod = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + + // SPC-2 + decoded.TST = (byte)((pageResponse[2] & 0xE0) >> 5); + decoded.TAS |= (pageResponse[4] & 0x80) == 0x80; + decoded.AutoloadMode = (byte)(pageResponse[5] & 0x07); + decoded.BusyTimeoutPeriod = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + + // SPC-3 + decoded.TMF_ONLY |= (pageResponse[2] & 0x10) == 0x10; + decoded.D_SENSE |= (pageResponse[2] & 0x04) == 0x04; + decoded.UA_INTLCK_CTRL = (byte)((pageResponse[4] & 0x30) >> 4); + decoded.TAS |= (pageResponse[5] & 0x40) == 0x40; + decoded.ATO |= (pageResponse[5] & 0x80) == 0x80; + + // SPC-5 + decoded.DPICZ |= (pageResponse[2] & 0x08) == 0x08; + decoded.NUAR |= (pageResponse[3] & 0x08) == 0x08; + decoded.ATMPE |= (pageResponse[5] & 0x20) == 0x20; + decoded.RWWP |= (pageResponse[5] & 0x10) == 0x10; + decoded.SBLP |= (pageResponse[5] & 0x08) == 0x08; + + return decoded; + } + + public static string PrettifyModePage_0A(byte[] pageResponse) => + PrettifyModePage_0A(DecodeModePage_0A(pageResponse)); + + public static string PrettifyModePage_0A(ModePage_0A? modePage) + { + if(!modePage.HasValue) + return null; + + 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.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.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"); + + 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; + } + + switch(page.QueueAlgorithm) + { + 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; + } + + switch(page.QErr) + { + 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; + } + + switch(page.UA_INTLCK_CTRL) + { + 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; + } + + switch(page.AutoloadMode) + { + 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; + } + + if(page.ReadyAENHoldOffPeriod > 0) + sb.AppendFormat("\t{0} ms before attempting asynchronous event notifications after initialization", + page.ReadyAENHoldOffPeriod).AppendLine(); + + if(page.BusyTimeoutPeriod > 0) + 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(); + + if(page.ExtendedSelfTestCompletionTime > 0) + sb.AppendFormat("\t{0} seconds to complete extended self-test", page.ExtendedSelfTestCompletionTime); + + return sb.ToString(); + } + #endregion Mode Page 0x0A: Control mode page + + #region Mode Page 0x0A subpage 0x01: Control Extension mode page + /// Control Extension mode page Page code 0x0A Subpage code 0x01 32 bytes in SPC-3, SPC-4, SPC-5 + public struct ModePage_0A_S01 + { + /// Parameters can be saved + public bool PS; + /// Timestamp outside this standard + public bool TCMOS; + /// SCSI precedence + public bool SCSIP; + /// Implicit Asymmetric Logical Unit Access Enabled + public bool IALUAE; + /// Initial task priority + public byte InitialPriority; + + /// Device life control disabled + public bool DLC; + /// Maximum size of SENSE data in bytes + public byte MaximumSenseLength; + } + + public static ModePage_0A_S01? DecodeModePage_0A_S01(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) != 0x40) + return null; + + if((pageResponse[0] & 0x3F) != 0x0A) + return null; + + if(pageResponse[1] != 0x01) + return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 32) + return null; + + var decoded = new ModePage_0A_S01(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.IALUAE |= (pageResponse[4] & 0x01) == 0x01; + decoded.SCSIP |= (pageResponse[4] & 0x02) == 0x02; + decoded.TCMOS |= (pageResponse[4] & 0x04) == 0x04; + + decoded.InitialPriority = (byte)(pageResponse[5] & 0x0F); + + return decoded; + } + + public static string PrettifyModePage_0A_S01(byte[] pageResponse) => + PrettifyModePage_0A_S01(DecodeModePage_0A_S01(pageResponse)); + + public static string PrettifyModePage_0A_S01(ModePage_0A_S01? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_0A_S01 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Control extension page:"); + + 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"); + + sb.AppendLine(); + } + + 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.MaximumSenseLength > 0) + sb.AppendFormat("\tMaximum sense data would be {0} bytes", page.MaximumSenseLength).AppendLine(); + + return sb.ToString(); + } + #endregion Mode Page 0x0A subpage 0x01: Control Extension mode page } \ No newline at end of file diff --git a/SCSI/Modes/0B.cs b/SCSI/Modes/0B.cs index 9b4ddd9..e96345b 100644 --- a/SCSI/Modes/0B.cs +++ b/SCSI/Modes/0B.cs @@ -33,83 +33,82 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x0B: Medium types supported page + /// Disconnect-reconnect page Page code 0x0B 8 bytes in SCSI-2 + public struct ModePage_0B { - #region Mode Page 0x0B: Medium types supported page - /// Disconnect-reconnect page Page code 0x0B 8 bytes in SCSI-2 - public struct ModePage_0B - { - /// Parameters can be saved - public bool PS; - public MediumTypes MediumType1; - public MediumTypes MediumType2; - public MediumTypes MediumType3; - public MediumTypes MediumType4; - } - - public static ModePage_0B? DecodeModePage_0B(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x0B) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 8) - return null; - - var decoded = new ModePage_0B(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.MediumType1 = (MediumTypes)pageResponse[4]; - decoded.MediumType2 = (MediumTypes)pageResponse[5]; - decoded.MediumType3 = (MediumTypes)pageResponse[6]; - decoded.MediumType4 = (MediumTypes)pageResponse[7]; - - return decoded; - } - - public static string PrettifyModePage_0B(byte[] pageResponse) => - PrettifyModePage_0B(DecodeModePage_0B(pageResponse)); - - public static string PrettifyModePage_0B(ModePage_0B? modePage) - { - if(!modePage.HasValue) - return null; - - 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.MediumType1 != MediumTypes.Default) - 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(); - - if(page.MediumType3 != MediumTypes.Default) - 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(); - - return sb.ToString(); - } - #endregion Mode Page 0x0B: Medium types supported page + /// Parameters can be saved + public bool PS; + public MediumTypes MediumType1; + public MediumTypes MediumType2; + public MediumTypes MediumType3; + public MediumTypes MediumType4; } + + public static ModePage_0B? DecodeModePage_0B(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x0B) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + var decoded = new ModePage_0B(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.MediumType1 = (MediumTypes)pageResponse[4]; + decoded.MediumType2 = (MediumTypes)pageResponse[5]; + decoded.MediumType3 = (MediumTypes)pageResponse[6]; + decoded.MediumType4 = (MediumTypes)pageResponse[7]; + + return decoded; + } + + public static string PrettifyModePage_0B(byte[] pageResponse) => + PrettifyModePage_0B(DecodeModePage_0B(pageResponse)); + + public static string PrettifyModePage_0B(ModePage_0B? modePage) + { + if(!modePage.HasValue) + return null; + + 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.MediumType1 != MediumTypes.Default) + 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(); + + if(page.MediumType3 != MediumTypes.Default) + 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(); + + return sb.ToString(); + } + #endregion Mode Page 0x0B: Medium types supported page } \ No newline at end of file diff --git a/SCSI/Modes/0C.cs b/SCSI/Modes/0C.cs index c824243..cecda47 100644 --- a/SCSI/Modes/0C.cs +++ b/SCSI/Modes/0C.cs @@ -30,12 +30,11 @@ // Copyright © 2011-2022 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +public static partial class Modes { - public static partial class Modes - { - #region Mode Page 0x0C: Notch page - // TODO: Implement this page - #endregion Mode Page 0x0C: Notch page - } + #region Mode Page 0x0C: Notch page + // TODO: Implement this page + #endregion Mode Page 0x0C: Notch page } \ No newline at end of file diff --git a/SCSI/Modes/0D.cs b/SCSI/Modes/0D.cs index 6b34c77..c6d408c 100644 --- a/SCSI/Modes/0D.cs +++ b/SCSI/Modes/0D.cs @@ -33,142 +33,141 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x0D: CD-ROM parameteres page + /// CD-ROM parameteres page Page code 0x0D 8 bytes in SCSI-2, MMC-1, MMC-2, MMC-3 + public struct ModePage_0D { - #region Mode Page 0x0D: CD-ROM parameteres page - /// CD-ROM parameteres page Page code 0x0D 8 bytes in SCSI-2, MMC-1, MMC-2, MMC-3 - public struct ModePage_0D - { - /// Parameters can be saved - public bool PS; - /// Time the drive shall remain in hold track state after seek or read - public byte InactivityTimerMultiplier; - /// Seconds per Minute - public ushort SecondsPerMinute; - /// Frames per Second - public ushort FramesPerSecond; - } - - public static ModePage_0D? DecodeModePage_0D(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x0D) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 8) - return null; - - var decoded = new ModePage_0D(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.InactivityTimerMultiplier = (byte)(pageResponse[3] & 0xF); - decoded.SecondsPerMinute = (ushort)((pageResponse[4] << 8) + pageResponse[5]); - decoded.FramesPerSecond = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - - return decoded; - } - - public static string PrettifyModePage_0D(byte[] pageResponse) => - PrettifyModePage_0D(DecodeModePage_0D(pageResponse)); - - public static string PrettifyModePage_0D(ModePage_0D? modePage) - { - if(!modePage.HasValue) - return null; - - 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"); - - 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(); - - return sb.ToString(); - } - #endregion Mode Page 0x0D: CD-ROM parameteres page + /// Parameters can be saved + public bool PS; + /// Time the drive shall remain in hold track state after seek or read + public byte InactivityTimerMultiplier; + /// Seconds per Minute + public ushort SecondsPerMinute; + /// Frames per Second + public ushort FramesPerSecond; } + + public static ModePage_0D? DecodeModePage_0D(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x0D) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + var decoded = new ModePage_0D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.InactivityTimerMultiplier = (byte)(pageResponse[3] & 0xF); + decoded.SecondsPerMinute = (ushort)((pageResponse[4] << 8) + pageResponse[5]); + decoded.FramesPerSecond = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + + return decoded; + } + + public static string PrettifyModePage_0D(byte[] pageResponse) => + PrettifyModePage_0D(DecodeModePage_0D(pageResponse)); + + public static string PrettifyModePage_0D(ModePage_0D? modePage) + { + if(!modePage.HasValue) + return null; + + 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"); + + 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(); + + return sb.ToString(); + } + #endregion Mode Page 0x0D: CD-ROM parameteres page } \ No newline at end of file diff --git a/SCSI/Modes/0E.cs b/SCSI/Modes/0E.cs index bd32746..74faa3c 100644 --- a/SCSI/Modes/0E.cs +++ b/SCSI/Modes/0E.cs @@ -33,231 +33,131 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 + /// CD-ROM audio control parameters Page code 0x0E 16 bytes in SCSI-2, MMC-1, MMC-2, MMC-3 + public struct ModePage_0E { - #region Mode Page 0x0E: CD-ROM audio control parameters page - /// CD-ROM audio control parameters Page code 0x0E 16 bytes in SCSI-2, MMC-1, MMC-2, MMC-3 - public struct ModePage_0E + /// Parameters can be saved + public bool PS; + /// Return status as soon as playback operation starts + public bool Immed; + /// Stop on track crossing + public bool SOTC; + /// Indicates is valid + public bool APRVal; + /// Multiplier for + public byte LBAFormat; + /// LBAs per second of audio + public ushort BlocksPerSecondOfAudio; + /// Channels output on this port + public byte OutputPort0ChannelSelection; + /// Volume level for this port + public byte OutputPort0Volume; + /// Channels output on this port + public byte OutputPort1ChannelSelection; + /// Volume level for this port + public byte OutputPort1Volume; + /// Channels output on this port + public byte OutputPort2ChannelSelection; + /// Volume level for this port + public byte OutputPort2Volume; + /// Channels output on this port + public byte OutputPort3ChannelSelection; + /// Volume level for this port + public byte OutputPort3Volume; + } + + public static ModePage_0E? DecodeModePage_0E(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x0E) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 16) + return null; + + var decoded = new ModePage_0E(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.Immed |= (pageResponse[2] & 0x04) == 0x04; + decoded.SOTC |= (pageResponse[2] & 0x02) == 0x02; + decoded.APRVal |= (pageResponse[5] & 0x80) == 0x80; + decoded.LBAFormat = (byte)(pageResponse[5] & 0x0F); + decoded.BlocksPerSecondOfAudio = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.OutputPort0ChannelSelection = (byte)(pageResponse[8] & 0x0F); + decoded.OutputPort0Volume = pageResponse[9]; + decoded.OutputPort1ChannelSelection = (byte)(pageResponse[10] & 0x0F); + decoded.OutputPort1Volume = pageResponse[11]; + decoded.OutputPort2ChannelSelection = (byte)(pageResponse[12] & 0x0F); + decoded.OutputPort2Volume = pageResponse[13]; + decoded.OutputPort3ChannelSelection = (byte)(pageResponse[14] & 0x0F); + decoded.OutputPort3Volume = pageResponse[15]; + + return decoded; + } + + public static string PrettifyModePage_0E(byte[] pageResponse) => + PrettifyModePage_0E(DecodeModePage_0E(pageResponse)); + + public static string PrettifyModePage_0E(ModePage_0E? modePage) + { + if(!modePage.HasValue) + return null; + + 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" + : "\tDrive will return from playback command when playback ends"); + + if(page.SOTC) + sb.AppendLine("\tDrive will stop playback on track end"); + + if(page.APRVal) { - /// Parameters can be saved - public bool PS; - /// Return status as soon as playback operation starts - public bool Immed; - /// Stop on track crossing - public bool SOTC; - /// Indicates is valid - public bool APRVal; - /// Multiplier for - public byte LBAFormat; - /// LBAs per second of audio - public ushort BlocksPerSecondOfAudio; - /// Channels output on this port - public byte OutputPort0ChannelSelection; - /// Volume level for this port - public byte OutputPort0Volume; - /// Channels output on this port - public byte OutputPort1ChannelSelection; - /// Volume level for this port - public byte OutputPort1Volume; - /// Channels output on this port - public byte OutputPort2ChannelSelection; - /// Volume level for this port - public byte OutputPort2Volume; - /// Channels output on this port - public byte OutputPort3ChannelSelection; - /// Volume level for this port - public byte OutputPort3Volume; + double blocks; + + 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(); } - public static ModePage_0E? DecodeModePage_0E(byte[] pageResponse) + if(page.OutputPort0ChannelSelection > 0) { - if((pageResponse?[0] & 0x40) == 0x40) - return null; + sb.Append("\tOutput port 0 has channels "); - if((pageResponse?[0] & 0x3F) != 0x0E) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 16) - return null; - - var decoded = new ModePage_0E(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.Immed |= (pageResponse[2] & 0x04) == 0x04; - decoded.SOTC |= (pageResponse[2] & 0x02) == 0x02; - decoded.APRVal |= (pageResponse[5] & 0x80) == 0x80; - decoded.LBAFormat = (byte)(pageResponse[5] & 0x0F); - decoded.BlocksPerSecondOfAudio = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - decoded.OutputPort0ChannelSelection = (byte)(pageResponse[8] & 0x0F); - decoded.OutputPort0Volume = pageResponse[9]; - decoded.OutputPort1ChannelSelection = (byte)(pageResponse[10] & 0x0F); - decoded.OutputPort1Volume = pageResponse[11]; - decoded.OutputPort2ChannelSelection = (byte)(pageResponse[12] & 0x0F); - decoded.OutputPort2Volume = pageResponse[13]; - decoded.OutputPort3ChannelSelection = (byte)(pageResponse[14] & 0x0F); - decoded.OutputPort3Volume = pageResponse[15]; - - return decoded; - } - - public static string PrettifyModePage_0E(byte[] pageResponse) => - PrettifyModePage_0E(DecodeModePage_0E(pageResponse)); - - public static string PrettifyModePage_0E(ModePage_0E? modePage) - { - if(!modePage.HasValue) - return null; - - 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" - : "\tDrive will return from playback command when playback ends"); - - 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; - - sb.AppendFormat("\tThere are {0} blocks per each second of audio", blocks).AppendLine(); - } - - 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 "); - - 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; - } - } - - 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 "); - - 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; - } - } - - 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 "); - - 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(); - - sb.Append("\tOutput port 3 has channels "); - - if((page.OutputPort3ChannelSelection & 0x01) == 0x01) + if((page.OutputPort0ChannelSelection & 0x01) == 0x01) sb.Append("0 "); - if((page.OutputPort3ChannelSelection & 0x02) == 0x02) + if((page.OutputPort0ChannelSelection & 0x02) == 0x02) sb.Append("1 "); - if((page.OutputPort3ChannelSelection & 0x04) == 0x04) + if((page.OutputPort0ChannelSelection & 0x04) == 0x04) sb.Append("2 "); - if((page.OutputPort3ChannelSelection & 0x08) == 0x08) + if((page.OutputPort0ChannelSelection & 0x08) == 0x08) sb.Append("3 "); - switch(page.OutputPort3Volume) + switch(page.OutputPort0Volume) { case 0: sb.AppendLine("muted"); @@ -268,13 +168,112 @@ namespace Aaru.Decoders.SCSI break; default: - sb.AppendFormat("at volume {0}", page.OutputPort3Volume).AppendLine(); + sb.AppendFormat("at volume {0}", page.OutputPort0Volume).AppendLine(); break; } - - return sb.ToString(); } - #endregion Mode Page 0x0E: CD-ROM audio control parameters page + + 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 "); + + 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; + } + } + + 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 "); + + 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(); + + 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 "); + + 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; + } + + return sb.ToString(); } + #endregion Mode Page 0x0E: CD-ROM audio control parameters page } \ No newline at end of file diff --git a/SCSI/Modes/0F.cs b/SCSI/Modes/0F.cs index f2cc098..26464da 100644 --- a/SCSI/Modes/0F.cs +++ b/SCSI/Modes/0F.cs @@ -33,87 +33,130 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x0F: Data compression page + /// Data compression page Page code 0x0F 16 bytes in SSC-1, SSC-2, SSC-3 + public struct ModePage_0F { - #region Mode Page 0x0F: Data compression page - /// Data compression page Page code 0x0F 16 bytes in SSC-1, SSC-2, SSC-3 - public struct ModePage_0F + /// Parameters can be saved + public bool PS; + /// Data compression enabled + public bool DCE; + /// Data compression capable + public bool DCC; + /// Data decompression enabled + public bool DDE; + /// Report exception on decompression + public byte RED; + /// Compression algorithm + public uint CompressionAlgo; + /// Decompression algorithm + public uint DecompressionAlgo; + } + + public static ModePage_0F? DecodeModePage_0F(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x0F) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 16) + return null; + + var decoded = new ModePage_0F(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.DCE |= (pageResponse[2] & 0x80) == 0x80; + decoded.DCC |= (pageResponse[2] & 0x40) == 0x40; + decoded.DDE |= (pageResponse[3] & 0x80) == 0x80; + decoded.RED = (byte)((pageResponse[3] & 0x60) >> 5); + + 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]); + + return decoded; + } + + public static string PrettifyModePage_0F(byte[] pageResponse) => + PrettifyModePage_0F(DecodeModePage_0F(pageResponse)); + + public static string PrettifyModePage_0F(ModePage_0F? modePage) + { + if(!modePage.HasValue) + return null; + + 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.DCC) { - /// Parameters can be saved - public bool PS; - /// Data compression enabled - public bool DCE; - /// Data compression capable - public bool DCC; - /// Data decompression enabled - public bool DDE; - /// Report exception on decompression - public byte RED; - /// Compression algorithm - public uint CompressionAlgo; - /// Decompression algorithm - public uint DecompressionAlgo; - } + sb.AppendLine("\tDrive supports data compression"); - public static ModePage_0F? DecodeModePage_0F(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x0F) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 16) - return null; - - var decoded = new ModePage_0F(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.DCE |= (pageResponse[2] & 0x80) == 0x80; - decoded.DCC |= (pageResponse[2] & 0x40) == 0x40; - decoded.DDE |= (pageResponse[3] & 0x80) == 0x80; - decoded.RED = (byte)((pageResponse[3] & 0x60) >> 5); - - 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]); - - return decoded; - } - - public static string PrettifyModePage_0F(byte[] pageResponse) => - PrettifyModePage_0F(DecodeModePage_0F(pageResponse)); - - public static string PrettifyModePage_0F(ModePage_0F? modePage) - { - if(!modePage.HasValue) - return null; - - 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.DCC) + if(page.DCE) { - sb.AppendLine("\tDrive supports data compression"); + sb.Append("\tData compression is enabled with "); - if(page.DCE) + switch(page.CompressionAlgo) { - sb.Append("\tData compression is enabled with "); + 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; + } + } + + if(page.DDE) + { + sb.AppendLine("\tData decompression is enabled"); + + if(page.DecompressionAlgo == 0) + sb.AppendLine("\tLast data read was uncompressed"); + else + { + sb.Append("\tLast data read was compressed with "); switch(page.CompressionAlgo) { @@ -147,58 +190,14 @@ namespace Aaru.Decoders.SCSI break; } } - - if(page.DDE) - { - sb.AppendLine("\tData decompression is enabled"); - - 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; - } - } - } - - sb.AppendFormat("\tReport exception on compression is set to {0}", page.RED).AppendLine(); } - else - sb.AppendLine("\tDrive does not support data compression"); - return sb.ToString(); + sb.AppendFormat("\tReport exception on compression is set to {0}", page.RED).AppendLine(); } - #endregion Mode Page 0x0F: Data compression page + else + sb.AppendLine("\tDrive does not support data compression"); + + return sb.ToString(); } + #endregion Mode Page 0x0F: Data compression page } \ No newline at end of file diff --git a/SCSI/Modes/10.cs b/SCSI/Modes/10.cs index f926282..ebf41c8 100644 --- a/SCSI/Modes/10.cs +++ b/SCSI/Modes/10.cs @@ -33,103 +33,102 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x10: XOR control mode page + /// XOR control mode page Page code 0x10 24 bytes in SBC-1, SBC-2 + public struct ModePage_10 { - #region Mode Page 0x10: XOR control mode page - /// XOR control mode page Page code 0x10 24 bytes in SBC-1, SBC-2 - public struct ModePage_10 - { - /// Parameters can be saved - public bool PS; - /// Disables XOR operations - public bool XORDIS; - /// Maximum transfer length in blocks for a XOR command - public uint MaxXorWrite; - /// Maximum regenerate length in blocks - public uint MaxRegenSize; - /// Maximum transfer length in blocks for READ during a rebuild - public uint MaxRebuildRead; - /// Minimum time in ms between READs during a rebuild - public ushort RebuildDelay; - } - - public static ModePage_10? DecodeModePage_10(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x10) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 24) - return null; - - 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; - } - - public static string PrettifyModePage_10(byte[] pageResponse) => - PrettifyModePage_10(DecodeModePage_10(pageResponse)); - - public static string PrettifyModePage_10(ModePage_10? modePage) - { - if(!modePage.HasValue) - return null; - - 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.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(); - } - - return sb.ToString(); - } - #endregion Mode Page 0x10: XOR control mode page + /// Parameters can be saved + public bool PS; + /// Disables XOR operations + public bool XORDIS; + /// Maximum transfer length in blocks for a XOR command + public uint MaxXorWrite; + /// Maximum regenerate length in blocks + public uint MaxRegenSize; + /// Maximum transfer length in blocks for READ during a rebuild + public uint MaxRebuildRead; + /// Minimum time in ms between READs during a rebuild + public ushort RebuildDelay; } + + public static ModePage_10? DecodeModePage_10(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x10) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 24) + return null; + + 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; + } + + public static string PrettifyModePage_10(byte[] pageResponse) => + PrettifyModePage_10(DecodeModePage_10(pageResponse)); + + public static string PrettifyModePage_10(ModePage_10? modePage) + { + if(!modePage.HasValue) + return null; + + 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.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(); + } + + return sb.ToString(); + } + #endregion Mode Page 0x10: XOR control mode page } \ No newline at end of file diff --git a/SCSI/Modes/10_SSC.cs b/SCSI/Modes/10_SSC.cs index 212b4a7..1338571 100644 --- a/SCSI/Modes/10_SSC.cs +++ b/SCSI/Modes/10_SSC.cs @@ -33,299 +33,298 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x10: Device configuration page + /// Device configuration page Page code 0x10 16 bytes in SCSI-2, SSC-1, SSC-2, SSC-3 + public struct ModePage_10_SSC { - #region Mode Page 0x10: Device configuration page - /// Device configuration page Page code 0x10 16 bytes in SCSI-2, SSC-1, SSC-2, SSC-3 - public struct ModePage_10_SSC - { - /// Parameters can be saved - public bool PS; - /// Used in mode select to change partition to one specified in - public bool CAP; - /// Used in mode select to change format to one specified in - public bool CAF; - /// Active format, vendor-specific - public byte ActiveFormat; - /// Current logical partition - public byte ActivePartition; - /// How full the buffer shall be before writing to medium - public byte WriteBufferFullRatio; - /// How empty the buffer shall be before reading more data from the medium - public byte ReadBufferEmptyRatio; - /// Delay in 100 ms before buffered data is forcefully written to the medium even before buffer is full - public ushort WriteDelayTime; - /// Drive supports recovering data from buffer - public bool DBR; - /// Medium has block IDs - public bool BIS; - /// Drive recognizes and reports setmarks - public bool RSmk; - /// Drive selects best speed - public bool AVC; - /// If drive should stop pre-reading on filemarks - public byte SOCF; - /// If set, recovered buffer data is LIFO, otherwise, FIFO - public bool RBO; - /// Report early warnings - public bool REW; - /// Inter-block gap - public byte GapSize; - /// End-of-Data format - public byte EODDefined; - /// EOD generation enabled - public bool EEG; - /// Synchronize data to medium on early warning - public bool SEW; - /// Bytes to reduce buffer size on early warning - public uint BufferSizeEarlyWarning; - /// Selected data compression algorithm - public byte SelectedCompression; + /// Parameters can be saved + public bool PS; + /// Used in mode select to change partition to one specified in + public bool CAP; + /// Used in mode select to change format to one specified in + public bool CAF; + /// Active format, vendor-specific + public byte ActiveFormat; + /// Current logical partition + public byte ActivePartition; + /// How full the buffer shall be before writing to medium + public byte WriteBufferFullRatio; + /// How empty the buffer shall be before reading more data from the medium + public byte ReadBufferEmptyRatio; + /// Delay in 100 ms before buffered data is forcefully written to the medium even before buffer is full + public ushort WriteDelayTime; + /// Drive supports recovering data from buffer + public bool DBR; + /// Medium has block IDs + public bool BIS; + /// Drive recognizes and reports setmarks + public bool RSmk; + /// Drive selects best speed + public bool AVC; + /// If drive should stop pre-reading on filemarks + public byte SOCF; + /// If set, recovered buffer data is LIFO, otherwise, FIFO + public bool RBO; + /// Report early warnings + public bool REW; + /// Inter-block gap + public byte GapSize; + /// End-of-Data format + public byte EODDefined; + /// EOD generation enabled + public bool EEG; + /// Synchronize data to medium on early warning + public bool SEW; + /// Bytes to reduce buffer size on early warning + public uint BufferSizeEarlyWarning; + /// Selected data compression algorithm + public byte SelectedCompression; - /// Soft write protect - public bool SWP; - /// Associated write protect - public bool ASOCWP; - /// Persistent write protect - public bool PERSWP; - /// Permanent write protect - public bool PRMWP; + /// Soft write protect + public bool SWP; + /// Associated write protect + public bool ASOCWP; + /// Persistent write protect + public bool PERSWP; + /// Permanent write protect + public bool PRMWP; - public bool BAML; - public bool BAM; - public byte RewindOnReset; + public bool BAML; + public bool BAM; + public byte RewindOnReset; - /// How drive shall respond to detection of compromised WORM medium integrity - public byte WTRE; - /// Respond to commands only if a reservation exists - public bool OIR; - } - - public static ModePage_10_SSC? DecodeModePage_10_SSC(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x10) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 16) - return null; - - var decoded = new ModePage_10_SSC(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.CAP |= (pageResponse[2] & 0x40) == 0x40; - decoded.CAF |= (pageResponse[2] & 0x20) == 0x20; - decoded.ActiveFormat = (byte)(pageResponse[2] & 0x1F); - decoded.ActivePartition = pageResponse[3]; - decoded.WriteBufferFullRatio = pageResponse[4]; - decoded.ReadBufferEmptyRatio = pageResponse[5]; - decoded.WriteDelayTime = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - decoded.DBR |= (pageResponse[8] & 0x80) == 0x80; - decoded.BIS |= (pageResponse[8] & 0x40) == 0x40; - decoded.RSmk |= (pageResponse[8] & 0x20) == 0x20; - decoded.AVC |= (pageResponse[8] & 0x10) == 0x10; - decoded.RBO |= (pageResponse[8] & 0x02) == 0x02; - decoded.REW |= (pageResponse[8] & 0x01) == 0x01; - 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; - decoded.ASOCWP |= (pageResponse[15] & 0x04) == 0x04; - decoded.PERSWP |= (pageResponse[15] & 0x02) == 0x02; - decoded.PRMWP |= (pageResponse[15] & 0x01) == 0x01; - - decoded.BAML |= (pageResponse[10] & 0x02) == 0x02; - decoded.BAM |= (pageResponse[10] & 0x01) == 0x01; - - decoded.RewindOnReset = (byte)((pageResponse[15] & 0x18) >> 3); - - decoded.OIR |= (pageResponse[15] & 0x20) == 0x20; - decoded.WTRE = (byte)((pageResponse[15] & 0xC0) >> 6); - - return decoded; - } - - public static string PrettifyModePage_10_SSC(byte[] pageResponse) => - PrettifyModePage_10_SSC(DecodeModePage_10_SSC(pageResponse)); - - public static string PrettifyModePage_10_SSC(ModePage_10_SSC? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_10_SSC page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Device configuration page:"); - - 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", - 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" - : "\tRecovered buffer data comes in FIFO order"); - } - - 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"); - } - - switch(page.GapSize) - { - case 0: break; - case 1: - sb.AppendLine("\tInter-block gap is long enough to support update in place"); - - break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - 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"); - - 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.BAML) - 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; - } - - switch(page.WTRE) - { - 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"); - - return sb.ToString(); - } - #endregion Mode Page 0x10: Device configuration page + /// How drive shall respond to detection of compromised WORM medium integrity + public byte WTRE; + /// Respond to commands only if a reservation exists + public bool OIR; } + + public static ModePage_10_SSC? DecodeModePage_10_SSC(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x10) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 16) + return null; + + var decoded = new ModePage_10_SSC(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.CAP |= (pageResponse[2] & 0x40) == 0x40; + decoded.CAF |= (pageResponse[2] & 0x20) == 0x20; + decoded.ActiveFormat = (byte)(pageResponse[2] & 0x1F); + decoded.ActivePartition = pageResponse[3]; + decoded.WriteBufferFullRatio = pageResponse[4]; + decoded.ReadBufferEmptyRatio = pageResponse[5]; + decoded.WriteDelayTime = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.DBR |= (pageResponse[8] & 0x80) == 0x80; + decoded.BIS |= (pageResponse[8] & 0x40) == 0x40; + decoded.RSmk |= (pageResponse[8] & 0x20) == 0x20; + decoded.AVC |= (pageResponse[8] & 0x10) == 0x10; + decoded.RBO |= (pageResponse[8] & 0x02) == 0x02; + decoded.REW |= (pageResponse[8] & 0x01) == 0x01; + 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; + decoded.ASOCWP |= (pageResponse[15] & 0x04) == 0x04; + decoded.PERSWP |= (pageResponse[15] & 0x02) == 0x02; + decoded.PRMWP |= (pageResponse[15] & 0x01) == 0x01; + + decoded.BAML |= (pageResponse[10] & 0x02) == 0x02; + decoded.BAM |= (pageResponse[10] & 0x01) == 0x01; + + decoded.RewindOnReset = (byte)((pageResponse[15] & 0x18) >> 3); + + decoded.OIR |= (pageResponse[15] & 0x20) == 0x20; + decoded.WTRE = (byte)((pageResponse[15] & 0xC0) >> 6); + + return decoded; + } + + public static string PrettifyModePage_10_SSC(byte[] pageResponse) => + PrettifyModePage_10_SSC(DecodeModePage_10_SSC(pageResponse)); + + public static string PrettifyModePage_10_SSC(ModePage_10_SSC? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_10_SSC page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Device configuration page:"); + + 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", + 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" + : "\tRecovered buffer data comes in FIFO order"); + } + + 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"); + } + + switch(page.GapSize) + { + case 0: break; + case 1: + sb.AppendLine("\tInter-block gap is long enough to support update in place"); + + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + 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"); + + 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.BAML) + 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; + } + + switch(page.WTRE) + { + 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"); + + return sb.ToString(); + } + #endregion Mode Page 0x10: Device configuration page } \ No newline at end of file diff --git a/SCSI/Modes/11.cs b/SCSI/Modes/11.cs index d2a2cf9..e2ef39c 100644 --- a/SCSI/Modes/11.cs +++ b/SCSI/Modes/11.cs @@ -34,217 +34,216 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region Mode Page 0x11: Medium partition page (1) - public enum PartitionSizeUnitOfMeasures : byte - { - /// Partition size is measures in bytes - Bytes = 0, - /// Partition size is measures in Kilobytes - Kilobytes = 1, - /// Partition size is measures in Megabytes - Megabytes = 2, - /// Partition size is 10eUNITS bytes - Exponential = 3 - } - - public enum MediumFormatRecognitionValues : byte - { - /// Logical unit is incapable of format or partition recognition - Incapable = 0, - /// Logical unit is capable of format recognition only - FormatCapable = 1, - /// Logical unit is capable of partition recognition only - PartitionCapable = 2, - /// Logical unit is capable of both format and partition recognition - Capable = 3 - } - - /// Medium partition page(1) Page code 0x11 - public struct ModePage_11 - { - /// Parameters can be saved - public bool PS; - /// Maximum number of additional partitions supported - public byte MaxAdditionalPartitions; - /// Number of additional partitions to be defined for a volume - public byte AdditionalPartitionsDefined; - /// Device defines partitions based on its fixed definition - public bool FDP; - /// Device should divide medium according to the additional partitions defined field using sizes defined by device - public bool SDP; - /// Initiator defines number and size of partitions - public bool IDP; - /// Defines the unit on which the partition sizes are defined - public PartitionSizeUnitOfMeasures PSUM; - public bool POFM; - public bool CLEAR; - public bool ADDP; - /// Defines the capabilities for the unit to recognize media partitions and format - public MediumFormatRecognitionValues MediumFormatRecognition; - public byte PartitionUnits; - /// Array of partition sizes in units defined above - public ushort[] PartitionSizes; - } - - public static ModePage_11? DecodeModePage_11(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x11) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 8) - return null; - - var decoded = new ModePage_11(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.MaxAdditionalPartitions = pageResponse[2]; - decoded.AdditionalPartitionsDefined = pageResponse[3]; - decoded.FDP |= (pageResponse[4] & 0x80) == 0x80; - decoded.SDP |= (pageResponse[4] & 0x40) == 0x40; - decoded.IDP |= (pageResponse[4] & 0x20) == 0x20; - decoded.PSUM = (PartitionSizeUnitOfMeasures)((pageResponse[4] & 0x18) >> 3); - decoded.POFM |= (pageResponse[4] & 0x04) == 0x04; - decoded.CLEAR |= (pageResponse[4] & 0x02) == 0x02; - decoded.ADDP |= (pageResponse[4] & 0x01) == 0x01; - decoded.PartitionUnits = (byte)(pageResponse[6] & 0x0F); - decoded.MediumFormatRecognition = (MediumFormatRecognitionValues)pageResponse[5]; - decoded.PartitionSizes = new ushort[(pageResponse.Length - 8) / 2]; - - for(int i = 8; i < pageResponse.Length; i += 2) - { - decoded.PartitionSizes[(i - 8) / 2] = (ushort)(pageResponse[i] << 8); - decoded.PartitionSizes[(i - 8) / 2] += pageResponse[i + 1]; - } - - return decoded; - } - - public static string PrettifyModePage_11(byte[] pageResponse) => - PrettifyModePage_11(DecodeModePage_11(pageResponse)); - - public static string PrettifyModePage_11(ModePage_11? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_11 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI medium partition page:"); - - 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.POFM) - sb.AppendLine("\tPartition parameters will not be applied until a FORMAT MEDIUM command is received"); - - 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) - 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"); - - string measure; - - switch(page.PSUM) - { - 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(); - - 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; - } - - switch(page.MediumFormatRecognition) - { - 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(); - - break; - } - - sb.AppendFormat("\tMedium has defined {0} partitions", page.PartitionSizes.Length).AppendLine(); - - for(int i = 0; i < page.PartitionSizes.Length; i++) - if(page.PartitionSizes[i] == 0) - if(page.PartitionSizes.Length == 1) - sb.AppendLine("\tDevice recognizes one single partition spanning whole medium"); - else - sb.AppendFormat("\tPartition {0} runs for rest of medium", i).AppendLine(); - else - sb.AppendFormat("\tPartition {0} is {1} {2} long", i, page.PartitionSizes[i], measure).AppendLine(); - - return sb.ToString(); - } - #endregion Mode Page 0x11: Medium partition page (1) + /// Partition size is measures in bytes + Bytes = 0, + /// Partition size is measures in Kilobytes + Kilobytes = 1, + /// Partition size is measures in Megabytes + Megabytes = 2, + /// Partition size is 10eUNITS bytes + Exponential = 3 } + + public enum MediumFormatRecognitionValues : byte + { + /// Logical unit is incapable of format or partition recognition + Incapable = 0, + /// Logical unit is capable of format recognition only + FormatCapable = 1, + /// Logical unit is capable of partition recognition only + PartitionCapable = 2, + /// Logical unit is capable of both format and partition recognition + Capable = 3 + } + + /// Medium partition page(1) Page code 0x11 + public struct ModePage_11 + { + /// Parameters can be saved + public bool PS; + /// Maximum number of additional partitions supported + public byte MaxAdditionalPartitions; + /// Number of additional partitions to be defined for a volume + public byte AdditionalPartitionsDefined; + /// Device defines partitions based on its fixed definition + public bool FDP; + /// Device should divide medium according to the additional partitions defined field using sizes defined by device + public bool SDP; + /// Initiator defines number and size of partitions + public bool IDP; + /// Defines the unit on which the partition sizes are defined + public PartitionSizeUnitOfMeasures PSUM; + public bool POFM; + public bool CLEAR; + public bool ADDP; + /// Defines the capabilities for the unit to recognize media partitions and format + public MediumFormatRecognitionValues MediumFormatRecognition; + public byte PartitionUnits; + /// Array of partition sizes in units defined above + public ushort[] PartitionSizes; + } + + public static ModePage_11? DecodeModePage_11(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x11) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + var decoded = new ModePage_11(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.MaxAdditionalPartitions = pageResponse[2]; + decoded.AdditionalPartitionsDefined = pageResponse[3]; + decoded.FDP |= (pageResponse[4] & 0x80) == 0x80; + decoded.SDP |= (pageResponse[4] & 0x40) == 0x40; + decoded.IDP |= (pageResponse[4] & 0x20) == 0x20; + decoded.PSUM = (PartitionSizeUnitOfMeasures)((pageResponse[4] & 0x18) >> 3); + decoded.POFM |= (pageResponse[4] & 0x04) == 0x04; + decoded.CLEAR |= (pageResponse[4] & 0x02) == 0x02; + decoded.ADDP |= (pageResponse[4] & 0x01) == 0x01; + decoded.PartitionUnits = (byte)(pageResponse[6] & 0x0F); + decoded.MediumFormatRecognition = (MediumFormatRecognitionValues)pageResponse[5]; + decoded.PartitionSizes = new ushort[(pageResponse.Length - 8) / 2]; + + for(int i = 8; i < pageResponse.Length; i += 2) + { + decoded.PartitionSizes[(i - 8) / 2] = (ushort)(pageResponse[i] << 8); + decoded.PartitionSizes[(i - 8) / 2] += pageResponse[i + 1]; + } + + return decoded; + } + + public static string PrettifyModePage_11(byte[] pageResponse) => + PrettifyModePage_11(DecodeModePage_11(pageResponse)); + + public static string PrettifyModePage_11(ModePage_11? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_11 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI medium partition page:"); + + 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.POFM) + sb.AppendLine("\tPartition parameters will not be applied until a FORMAT MEDIUM command is received"); + + 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) + 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"); + + string measure; + + switch(page.PSUM) + { + 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(); + + 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; + } + + switch(page.MediumFormatRecognition) + { + 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(); + + break; + } + + sb.AppendFormat("\tMedium has defined {0} partitions", page.PartitionSizes.Length).AppendLine(); + + for(int i = 0; i < page.PartitionSizes.Length; i++) + if(page.PartitionSizes[i] == 0) + if(page.PartitionSizes.Length == 1) + sb.AppendLine("\tDevice recognizes one single partition spanning whole medium"); + else + sb.AppendFormat("\tPartition {0} runs for rest of medium", i).AppendLine(); + else + sb.AppendFormat("\tPartition {0} is {1} {2} long", i, page.PartitionSizes[i], measure).AppendLine(); + + return sb.ToString(); + } + #endregion Mode Page 0x11: Medium partition page (1) } \ No newline at end of file diff --git a/SCSI/Modes/12_13_14.cs b/SCSI/Modes/12_13_14.cs index fc43112..9565bbc 100644 --- a/SCSI/Modes/12_13_14.cs +++ b/SCSI/Modes/12_13_14.cs @@ -33,79 +33,78 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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) + /// Medium partition page (2-4) Page codes 0x12, 0x13 and 0x14 + public struct ModePage_12_13_14 { - #region Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4) - /// Medium partition page (2-4) Page codes 0x12, 0x13 and 0x14 - public struct ModePage_12_13_14 - { - /// Parameters can be saved - public bool PS; - /// Array of partition sizes in units defined in mode page 11 - public ushort[] PartitionSizes; - } - - public static ModePage_12_13_14? DecodeModePage_12_13_14(byte[] pageResponse) - { - if(pageResponse == null) - 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[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 2) - return null; - - var decoded = new ModePage_12_13_14(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.PartitionSizes = new ushort[(pageResponse.Length - 2) / 2]; - - for(int i = 2; i < pageResponse.Length; i += 2) - { - decoded.PartitionSizes[(i - 2) / 2] = (ushort)(pageResponse[i] << 8); - decoded.PartitionSizes[(i - 2) / 2] += pageResponse[i + 1]; - } - - return decoded; - } - - public static string PrettifyModePage_12_13_14(byte[] pageResponse) => - PrettifyModePage_12_13_14(DecodeModePage_12_13_14(pageResponse)); - - public static string PrettifyModePage_12_13_14(ModePage_12_13_14? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_12_13_14 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI medium partition page (extra):"); - - if(page.PS) - sb.AppendLine("\tParameters can be saved"); - - sb.AppendFormat("\tMedium has defined {0} partitions", page.PartitionSizes.Length).AppendLine(); - - for(int i = 0; i < page.PartitionSizes.Length; i++) - sb.AppendFormat("\tPartition {0} is {1} units long", i, page.PartitionSizes[i]).AppendLine(); - - return sb.ToString(); - } - #endregion Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4) + /// Parameters can be saved + public bool PS; + /// Array of partition sizes in units defined in mode page 11 + public ushort[] PartitionSizes; } + + public static ModePage_12_13_14? DecodeModePage_12_13_14(byte[] pageResponse) + { + if(pageResponse == null) + 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[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 2) + return null; + + var decoded = new ModePage_12_13_14(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.PartitionSizes = new ushort[(pageResponse.Length - 2) / 2]; + + for(int i = 2; i < pageResponse.Length; i += 2) + { + decoded.PartitionSizes[(i - 2) / 2] = (ushort)(pageResponse[i] << 8); + decoded.PartitionSizes[(i - 2) / 2] += pageResponse[i + 1]; + } + + return decoded; + } + + public static string PrettifyModePage_12_13_14(byte[] pageResponse) => + PrettifyModePage_12_13_14(DecodeModePage_12_13_14(pageResponse)); + + public static string PrettifyModePage_12_13_14(ModePage_12_13_14? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_12_13_14 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI medium partition page (extra):"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + sb.AppendFormat("\tMedium has defined {0} partitions", page.PartitionSizes.Length).AppendLine(); + + for(int i = 0; i < page.PartitionSizes.Length; i++) + sb.AppendFormat("\tPartition {0} is {1} units long", i, page.PartitionSizes[i]).AppendLine(); + + return sb.ToString(); + } + #endregion Mode Pages 0x12, 0x13, 0x14: Medium partition page (2-4) } \ No newline at end of file diff --git a/SCSI/Modes/1A.cs b/SCSI/Modes/1A.cs index 633fd36..a514fa5 100644 --- a/SCSI/Modes/1A.cs +++ b/SCSI/Modes/1A.cs @@ -33,240 +33,239 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x1A: Power condition page + /// Power condition page Page code 0x1A 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 40 bytes in SPC-5 + public struct ModePage_1A { - #region Mode Page 0x1A: Power condition page - /// Power condition page Page code 0x1A 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 40 bytes in SPC-5 - public struct ModePage_1A - { - /// Parameters can be saved - public bool PS; - /// Idle timer activated - public bool Idle; - /// Standby timer activated - public bool Standby; - /// Idle timer - public uint IdleTimer; - /// Standby timer - public uint StandbyTimer; + /// Parameters can be saved + public bool PS; + /// Idle timer activated + public bool Idle; + /// Standby timer activated + public bool Standby; + /// Idle timer + public uint IdleTimer; + /// Standby timer + public uint StandbyTimer; - /// Interactions between background functions and power management - public byte PM_BG_Precedence; - /// Standby timer Y activated - public bool Standby_Y; - /// Idle timer B activated - public bool Idle_B; - /// Idle timer C activated - public bool Idle_C; - /// Idle timer B - public uint IdleTimer_B; - /// Idle timer C - public uint IdleTimer_C; - /// Standby timer Y - public uint StandbyTimer_Y; - public byte CCF_Idle; - public byte CCF_Standby; - public byte CCF_Stopped; - } - - public static ModePage_1A? DecodeModePage_1A(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x1A) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 12) - return null; - - var decoded = new ModePage_1A(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.Standby |= (pageResponse[3] & 0x01) == 0x01; - decoded.Idle |= (pageResponse[3] & 0x02) == 0x02; - - 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; - - decoded.PM_BG_Precedence = (byte)((pageResponse[2] & 0xC0) >> 6); - decoded.Standby_Y |= (pageResponse[2] & 0x01) == 0x01; - decoded.Idle_B |= (pageResponse[3] & 0x04) == 0x04; - decoded.Idle_C |= (pageResponse[3] & 0x08) == 0x08; - - 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]); - - decoded.CCF_Idle = (byte)((pageResponse[39] & 0xC0) >> 6); - decoded.CCF_Standby = (byte)((pageResponse[39] & 0x30) >> 4); - decoded.CCF_Stopped = (byte)((pageResponse[39] & 0x0C) >> 2); - - return decoded; - } - - public static string PrettifyModePage_1A(byte[] pageResponse) => - PrettifyModePage_1A(DecodeModePage_1A(pageResponse)); - - public static string PrettifyModePage_1A(ModePage_1A? modePage) - { - if(!modePage.HasValue) - return null; - - 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.Standby && page.StandbyTimer > 0) || - (page.Standby_Y && page.StandbyTimer_Y > 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) - sb.AppendFormat("\tStandby timer Y is set to {0} ms", page.StandbyTimer_Y * 100).AppendLine(); - } - else - sb.AppendLine("\tDrive will not enter standy mode"); - - 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) - sb.AppendFormat("\tIdle timer A is set to {0} ms", page.IdleTimer * 100).AppendLine(); - - 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) - sb.AppendFormat("\tIdle timer C is set to {0} ms", page.IdleTimer_C * 100).AppendLine(); - } - 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; - } - - return sb.ToString(); - } - #endregion Mode Page 0x1A: Power condition page - - #region Mode Page 0x1A subpage 0x01: Power Consumption mode page - /// Power Consumption mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5 - public struct ModePage_1A_S01 - { - /// Parameters can be saved - public bool PS; - /// Active power level - public byte ActiveLevel; - /// Power Consumption VPD identifier in use - public byte PowerConsumptionIdentifier; - } - - public static ModePage_1A_S01? DecodeModePage_1A_S01(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) != 0x40) - return null; - - if((pageResponse[0] & 0x3F) != 0x1A) - return null; - - if(pageResponse[1] != 0x01) - return null; - - if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 16) - return null; - - var decoded = new ModePage_1A_S01(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.ActiveLevel = (byte)(pageResponse[6] & 0x03); - decoded.PowerConsumptionIdentifier = pageResponse[7]; - - return decoded; - } - - public static string PrettifyModePage_1A_S01(byte[] pageResponse) => - PrettifyModePage_1A_S01(DecodeModePage_1A_S01(pageResponse)); - - public static string PrettifyModePage_1A_S01(ModePage_1A_S01? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_1A_S01 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Power Consumption page:"); - - 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; - } - - return sb.ToString(); - } - #endregion Mode Page 0x1A subpage 0x01: Power Consumption mode page + /// Interactions between background functions and power management + public byte PM_BG_Precedence; + /// Standby timer Y activated + public bool Standby_Y; + /// Idle timer B activated + public bool Idle_B; + /// Idle timer C activated + public bool Idle_C; + /// Idle timer B + public uint IdleTimer_B; + /// Idle timer C + public uint IdleTimer_C; + /// Standby timer Y + public uint StandbyTimer_Y; + public byte CCF_Idle; + public byte CCF_Standby; + public byte CCF_Stopped; } + + public static ModePage_1A? DecodeModePage_1A(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x1A) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 12) + return null; + + var decoded = new ModePage_1A(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.Standby |= (pageResponse[3] & 0x01) == 0x01; + decoded.Idle |= (pageResponse[3] & 0x02) == 0x02; + + 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; + + decoded.PM_BG_Precedence = (byte)((pageResponse[2] & 0xC0) >> 6); + decoded.Standby_Y |= (pageResponse[2] & 0x01) == 0x01; + decoded.Idle_B |= (pageResponse[3] & 0x04) == 0x04; + decoded.Idle_C |= (pageResponse[3] & 0x08) == 0x08; + + 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]); + + decoded.CCF_Idle = (byte)((pageResponse[39] & 0xC0) >> 6); + decoded.CCF_Standby = (byte)((pageResponse[39] & 0x30) >> 4); + decoded.CCF_Stopped = (byte)((pageResponse[39] & 0x0C) >> 2); + + return decoded; + } + + public static string PrettifyModePage_1A(byte[] pageResponse) => + PrettifyModePage_1A(DecodeModePage_1A(pageResponse)); + + public static string PrettifyModePage_1A(ModePage_1A? modePage) + { + if(!modePage.HasValue) + return null; + + 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.Standby && page.StandbyTimer > 0) || + (page.Standby_Y && page.StandbyTimer_Y > 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) + sb.AppendFormat("\tStandby timer Y is set to {0} ms", page.StandbyTimer_Y * 100).AppendLine(); + } + else + sb.AppendLine("\tDrive will not enter standy mode"); + + 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) + sb.AppendFormat("\tIdle timer A is set to {0} ms", page.IdleTimer * 100).AppendLine(); + + 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) + sb.AppendFormat("\tIdle timer C is set to {0} ms", page.IdleTimer_C * 100).AppendLine(); + } + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x1A: Power condition page + + #region Mode Page 0x1A subpage 0x01: Power Consumption mode page + /// Power Consumption mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5 + public struct ModePage_1A_S01 + { + /// Parameters can be saved + public bool PS; + /// Active power level + public byte ActiveLevel; + /// Power Consumption VPD identifier in use + public byte PowerConsumptionIdentifier; + } + + public static ModePage_1A_S01? DecodeModePage_1A_S01(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) != 0x40) + return null; + + if((pageResponse[0] & 0x3F) != 0x1A) + return null; + + if(pageResponse[1] != 0x01) + return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 16) + return null; + + var decoded = new ModePage_1A_S01(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.ActiveLevel = (byte)(pageResponse[6] & 0x03); + decoded.PowerConsumptionIdentifier = pageResponse[7]; + + return decoded; + } + + public static string PrettifyModePage_1A_S01(byte[] pageResponse) => + PrettifyModePage_1A_S01(DecodeModePage_1A_S01(pageResponse)); + + public static string PrettifyModePage_1A_S01(ModePage_1A_S01? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_1A_S01 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Power Consumption page:"); + + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x1A subpage 0x01: Power Consumption mode page } \ No newline at end of file diff --git a/SCSI/Modes/1B.cs b/SCSI/Modes/1B.cs index 75c308e..29cd752 100644 --- a/SCSI/Modes/1B.cs +++ b/SCSI/Modes/1B.cs @@ -33,90 +33,89 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x1B: Removable Block Access Capabilities page + /// Removable Block Access Capabilities page Page code 0x1B 12 bytes in INF-8070 + public struct ModePage_1B { - #region Mode Page 0x1B: Removable Block Access Capabilities page - /// Removable Block Access Capabilities page Page code 0x1B 12 bytes in INF-8070 - public struct ModePage_1B - { - /// Parameters can be saved - public bool PS; - /// Supports reporting progress of format - public bool SRFP; - /// Non-CD Optical Device - public bool NCD; - /// Phase change dual device supporting a CD and a Non-CD Optical devices - public bool SML; - /// Total number of LUNs - public byte TLUN; - /// System Floppy Type device - public bool SFLP; - } - - public static ModePage_1B? DecodeModePage_1B(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x1B) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 12) - return null; - - var decoded = new ModePage_1B(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.SFLP |= (pageResponse[2] & 0x80) == 0x80; - decoded.SRFP |= (pageResponse[2] & 0x40) == 0x40; - decoded.NCD |= (pageResponse[3] & 0x80) == 0x80; - decoded.SML |= (pageResponse[3] & 0x40) == 0x40; - - decoded.TLUN = (byte)(pageResponse[3] & 0x07); - - return decoded; - } - - public static string PrettifyModePage_1B(byte[] pageResponse) => - PrettifyModePage_1B(DecodeModePage_1B(pageResponse)); - - public static string PrettifyModePage_1B(ModePage_1B? modePage) - { - if(!modePage.HasValue) - return null; - - 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.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(); - } - #endregion Mode Page 0x1B: Removable Block Access Capabilities page + /// Parameters can be saved + public bool PS; + /// Supports reporting progress of format + public bool SRFP; + /// Non-CD Optical Device + public bool NCD; + /// Phase change dual device supporting a CD and a Non-CD Optical devices + public bool SML; + /// Total number of LUNs + public byte TLUN; + /// System Floppy Type device + public bool SFLP; } + + public static ModePage_1B? DecodeModePage_1B(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x1B) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 12) + return null; + + var decoded = new ModePage_1B(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.SFLP |= (pageResponse[2] & 0x80) == 0x80; + decoded.SRFP |= (pageResponse[2] & 0x40) == 0x40; + decoded.NCD |= (pageResponse[3] & 0x80) == 0x80; + decoded.SML |= (pageResponse[3] & 0x40) == 0x40; + + decoded.TLUN = (byte)(pageResponse[3] & 0x07); + + return decoded; + } + + public static string PrettifyModePage_1B(byte[] pageResponse) => + PrettifyModePage_1B(DecodeModePage_1B(pageResponse)); + + public static string PrettifyModePage_1B(ModePage_1B? modePage) + { + if(!modePage.HasValue) + return null; + + 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.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(); + } + #endregion Mode Page 0x1B: Removable Block Access Capabilities page } \ No newline at end of file diff --git a/SCSI/Modes/1C.cs b/SCSI/Modes/1C.cs index d33cb34..dac1a6a 100644 --- a/SCSI/Modes/1C.cs +++ b/SCSI/Modes/1C.cs @@ -33,278 +33,277 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x1C: Informational exceptions control page + /// Informational exceptions control page Page code 0x1C 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 + public struct ModePage_1C { - #region Mode Page 0x1C: Informational exceptions control page - /// Informational exceptions control page Page code 0x1C 12 bytes in SPC-1, SPC-2, SPC-3, SPC-4 - public struct ModePage_1C + /// Parameters can be saved + public bool PS; + /// Informational exception operations should not affect performance + public bool Perf; + /// Disable informational exception operations + public bool DExcpt; + /// Create a test device failure at next interval time + public bool Test; + /// Log informational exception conditions + public bool LogErr; + /// Method of reporting informational exceptions + public byte MRIE; + /// 100 ms period to report an informational exception condition + public uint IntervalTimer; + /// How many times to report informational exceptions + public uint ReportCount; + + /// Enable background functions + public bool EBF; + /// Warning reporting enabled + public bool EWasc; + + /// Enable reporting of background self-test errors + public bool EBACKERR; + } + + public static ModePage_1C? DecodeModePage_1C(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x1C) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + var decoded = new ModePage_1C(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.Perf |= (pageResponse[2] & 0x80) == 0x80; + decoded.DExcpt |= (pageResponse[2] & 0x08) == 0x08; + decoded.Test |= (pageResponse[2] & 0x04) == 0x04; + decoded.LogErr |= (pageResponse[2] & 0x01) == 0x01; + + decoded.MRIE = (byte)(pageResponse[3] & 0x0F); + + decoded.IntervalTimer = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + + pageResponse[7]); + + decoded.EBF |= (pageResponse[2] & 0x20) == 0x20; + decoded.EWasc |= (pageResponse[2] & 0x10) == 0x10; + + decoded.EBACKERR |= (pageResponse[2] & 0x02) == 0x02; + + if(pageResponse.Length >= 12) + decoded.ReportCount = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + + (pageResponse[10] << 8) + pageResponse[11]); + + return decoded; + } + + public static string PrettifyModePage_1C(byte[] pageResponse) => + PrettifyModePage_1C(DecodeModePage_1C(pageResponse)); + + public static string PrettifyModePage_1C(ModePage_1C? modePage) + { + if(!modePage.HasValue) + return null; + + 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.DExcpt) + sb.AppendLine("\tInformational exceptions are disabled"); + else { - /// Parameters can be saved - public bool PS; - /// Informational exception operations should not affect performance - public bool Perf; - /// Disable informational exception operations - public bool DExcpt; - /// Create a test device failure at next interval time - public bool Test; - /// Log informational exception conditions - public bool LogErr; - /// Method of reporting informational exceptions - public byte MRIE; - /// 100 ms period to report an informational exception condition - public uint IntervalTimer; - /// How many times to report informational exceptions - public uint ReportCount; + sb.AppendLine("\tInformational exceptions are enabled"); - /// Enable background functions - public bool EBF; - /// Warning reporting enabled - public bool EWasc; - - /// Enable reporting of background self-test errors - public bool EBACKERR; - } - - public static ModePage_1C? DecodeModePage_1C(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x1C) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 8) - return null; - - var decoded = new ModePage_1C(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.Perf |= (pageResponse[2] & 0x80) == 0x80; - decoded.DExcpt |= (pageResponse[2] & 0x08) == 0x08; - decoded.Test |= (pageResponse[2] & 0x04) == 0x04; - decoded.LogErr |= (pageResponse[2] & 0x01) == 0x01; - - decoded.MRIE = (byte)(pageResponse[3] & 0x0F); - - decoded.IntervalTimer = (uint)((pageResponse[4] << 24) + (pageResponse[5] << 16) + (pageResponse[6] << 8) + - pageResponse[7]); - - decoded.EBF |= (pageResponse[2] & 0x20) == 0x20; - decoded.EWasc |= (pageResponse[2] & 0x10) == 0x10; - - decoded.EBACKERR |= (pageResponse[2] & 0x02) == 0x02; - - if(pageResponse.Length >= 12) - decoded.ReportCount = (uint)((pageResponse[8] << 24) + (pageResponse[9] << 16) + - (pageResponse[10] << 8) + pageResponse[11]); - - return decoded; - } - - public static string PrettifyModePage_1C(byte[] pageResponse) => - PrettifyModePage_1C(DecodeModePage_1C(pageResponse)); - - public static string PrettifyModePage_1C(ModePage_1C? modePage) - { - if(!modePage.HasValue) - return null; - - 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.DExcpt) - sb.AppendLine("\tInformational exceptions are disabled"); - else + switch(page.MRIE) { - sb.AppendLine("\tInformational exceptions are enabled"); + case 0: + sb.AppendLine("\tNo reporting of informational exception condition"); - switch(page.MRIE) - { - case 0: - sb.AppendLine("\tNo reporting of informational exception condition"); + break; + case 1: + sb.AppendLine("\tAsynchronous event reporting of informational exceptions"); - break; - case 1: - sb.AppendLine("\tAsynchronous event reporting of informational exceptions"); + break; + case 2: + sb.AppendLine("\tGenerate unit attention on 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 3: - sb.AppendLine("\tConditionally generate recovered error on informational exceptions"); + break; + case 4: + sb.AppendLine("\tUnconditionally 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 5: - sb.AppendLine("\tGenerate no sense on informational exceptions"); + break; + case 6: + sb.AppendLine("\tOnly report informational exception condition on request"); - 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; - 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.IntervalTimer > 0) - if(page.IntervalTimer == 0xFFFFFFFF) - sb.AppendLine("\tTimer interval is vendor-specific"); - else - sb.AppendFormat("\tTimer interval is {0} ms", page.IntervalTimer * 100).AppendLine(); - - if(page.ReportCount > 0) - sb.AppendFormat("\tInformational exception conditions will be reported a maximum of {0} times", - page.ReportCount); + break; } - if(page.EWasc) - sb.AppendLine("\tWarning reporting is enabled"); + if(page.Perf) + sb.AppendLine("\tInformational exceptions reporting should not affect drive performance"); - if(page.EBF) - sb.AppendLine("\tBackground functions are enabled"); + if(page.Test) + sb.AppendLine("\tA test informational exception will raise on next timer"); - if(page.EBACKERR) - sb.AppendLine("\tDrive will report background self-test errors"); + if(page.LogErr) + sb.AppendLine("\tDrive shall log informational exception conditions"); - return sb.ToString(); - } - #endregion Mode Page 0x1C: Informational exceptions control page + if(page.IntervalTimer > 0) + if(page.IntervalTimer == 0xFFFFFFFF) + sb.AppendLine("\tTimer interval is vendor-specific"); + else + sb.AppendFormat("\tTimer interval is {0} ms", page.IntervalTimer * 100).AppendLine(); - #region Mode Page 0x1C subpage 0x01: Background Control mode page - /// Background Control mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5 - public struct ModePage_1C_S01 - { - /// Parameters can be saved - public bool PS; - /// Suspend on log full - public bool S_L_Full; - /// Log only when intervention required - public bool LOWIR; - /// Enable background medium scan - public bool En_Bms; - /// Enable background pre-scan - public bool En_Ps; - /// Time in hours between background medium scans - public ushort BackgroundScanInterval; - /// Maximum time in hours for a background pre-scan to complete - public ushort BackgroundPrescanTimeLimit; - /// Minimum time in ms being idle before resuming a background scan - public ushort MinIdleBeforeBgScan; - /// Maximum time in ms to start processing commands while performing a background scan - public ushort MaxTimeSuspendBgScan; + if(page.ReportCount > 0) + sb.AppendFormat("\tInformational exception conditions will be reported a maximum of {0} times", + page.ReportCount); } - public static ModePage_1C_S01? DecodeModePage_1C_S01(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) != 0x40) - return null; + if(page.EWasc) + sb.AppendLine("\tWarning reporting is enabled"); - if((pageResponse[0] & 0x3F) != 0x1C) - return null; + if(page.EBF) + sb.AppendLine("\tBackground functions are enabled"); - if(pageResponse[1] != 0x01) - return null; + if(page.EBACKERR) + sb.AppendLine("\tDrive will report background self-test errors"); - if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) - return null; - - if(pageResponse.Length < 16) - return null; - - var decoded = new ModePage_1C_S01(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.S_L_Full |= (pageResponse[4] & 0x04) == 0x04; - decoded.LOWIR |= (pageResponse[4] & 0x02) == 0x02; - decoded.En_Bms |= (pageResponse[4] & 0x01) == 0x01; - decoded.En_Ps |= (pageResponse[5] & 0x01) == 0x01; - - decoded.BackgroundScanInterval = (ushort)((pageResponse[6] << 8) + pageResponse[7]); - decoded.BackgroundPrescanTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]); - decoded.MinIdleBeforeBgScan = (ushort)((pageResponse[10] << 8) + pageResponse[11]); - decoded.MaxTimeSuspendBgScan = (ushort)((pageResponse[12] << 8) + pageResponse[13]); - - return decoded; - } - - public static string PrettifyModePage_1C_S01(byte[] pageResponse) => - PrettifyModePage_1C_S01(DecodeModePage_1C_S01(pageResponse)); - - public static string PrettifyModePage_1C_S01(ModePage_1C_S01? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_1C_S01 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Background Control page:"); - - 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.BackgroundScanInterval > 0) - sb.AppendFormat("\t{0} hours shall be between the start of a background scan operation and the next", - page.BackgroundScanInterval).AppendLine(); - - if(page.BackgroundPrescanTimeLimit > 0) - sb.AppendFormat("\tBackgroun pre-scan operations can take a maximum of {0} hours", - page.BackgroundPrescanTimeLimit).AppendLine(); - - if(page.MinIdleBeforeBgScan > 0) - sb.AppendFormat("\tAt least {0} ms must be idle before resuming a suspended background scan operation", - 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", - page.MaxTimeSuspendBgScan).AppendLine(); - - return sb.ToString(); - } - #endregion Mode Page 0x1C subpage 0x01: Background Control mode page + return sb.ToString(); } + #endregion Mode Page 0x1C: Informational exceptions control page + + #region Mode Page 0x1C subpage 0x01: Background Control mode page + /// Background Control mode page Page code 0x1A Subpage code 0x01 16 bytes in SPC-5 + public struct ModePage_1C_S01 + { + /// Parameters can be saved + public bool PS; + /// Suspend on log full + public bool S_L_Full; + /// Log only when intervention required + public bool LOWIR; + /// Enable background medium scan + public bool En_Bms; + /// Enable background pre-scan + public bool En_Ps; + /// Time in hours between background medium scans + public ushort BackgroundScanInterval; + /// Maximum time in hours for a background pre-scan to complete + public ushort BackgroundPrescanTimeLimit; + /// Minimum time in ms being idle before resuming a background scan + public ushort MinIdleBeforeBgScan; + /// Maximum time in ms to start processing commands while performing a background scan + public ushort MaxTimeSuspendBgScan; + } + + public static ModePage_1C_S01? DecodeModePage_1C_S01(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) != 0x40) + return null; + + if((pageResponse[0] & 0x3F) != 0x1C) + return null; + + if(pageResponse[1] != 0x01) + return null; + + if((pageResponse[2] << 8) + pageResponse[3] + 4 != pageResponse.Length) + return null; + + if(pageResponse.Length < 16) + return null; + + var decoded = new ModePage_1C_S01(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.S_L_Full |= (pageResponse[4] & 0x04) == 0x04; + decoded.LOWIR |= (pageResponse[4] & 0x02) == 0x02; + decoded.En_Bms |= (pageResponse[4] & 0x01) == 0x01; + decoded.En_Ps |= (pageResponse[5] & 0x01) == 0x01; + + decoded.BackgroundScanInterval = (ushort)((pageResponse[6] << 8) + pageResponse[7]); + decoded.BackgroundPrescanTimeLimit = (ushort)((pageResponse[8] << 8) + pageResponse[9]); + decoded.MinIdleBeforeBgScan = (ushort)((pageResponse[10] << 8) + pageResponse[11]); + decoded.MaxTimeSuspendBgScan = (ushort)((pageResponse[12] << 8) + pageResponse[13]); + + return decoded; + } + + public static string PrettifyModePage_1C_S01(byte[] pageResponse) => + PrettifyModePage_1C_S01(DecodeModePage_1C_S01(pageResponse)); + + public static string PrettifyModePage_1C_S01(ModePage_1C_S01? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_1C_S01 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Background Control page:"); + + 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.BackgroundScanInterval > 0) + sb.AppendFormat("\t{0} hours shall be between the start of a background scan operation and the next", + page.BackgroundScanInterval).AppendLine(); + + if(page.BackgroundPrescanTimeLimit > 0) + sb.AppendFormat("\tBackgroun pre-scan operations can take a maximum of {0} hours", + page.BackgroundPrescanTimeLimit).AppendLine(); + + if(page.MinIdleBeforeBgScan > 0) + sb.AppendFormat("\tAt least {0} ms must be idle before resuming a suspended background scan operation", + 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", + page.MaxTimeSuspendBgScan).AppendLine(); + + return sb.ToString(); + } + #endregion Mode Page 0x1C subpage 0x01: Background Control mode page } \ No newline at end of file diff --git a/SCSI/Modes/1C_SFF.cs b/SCSI/Modes/1C_SFF.cs index b937511..bb410a5 100644 --- a/SCSI/Modes/1C_SFF.cs +++ b/SCSI/Modes/1C_SFF.cs @@ -33,143 +33,142 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + #region Mode Page 0x1C: Timer & Protect page + /// Timer & Protect page Page code 0x1C 8 bytes in INF-8070 + public struct ModePage_1C_SFF { - #region Mode Page 0x1C: Timer & Protect page - /// Timer & Protect page Page code 0x1C 8 bytes in INF-8070 - public struct ModePage_1C_SFF - { - /// Parameters can be saved - public bool PS; - /// Time the device shall remain in the current state after seek, read or write operation - public byte InactivityTimeMultiplier; - /// Disabled until power cycle - public bool DISP; - /// Software Write Protect until Power-down - public bool SWPP; - } - - public static ModePage_1C_SFF? DecodeModePage_1C_SFF(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x1C) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 8) - return null; - - var decoded = new ModePage_1C_SFF(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.DISP |= (pageResponse[2] & 0x02) == 0x02; - decoded.SWPP |= (pageResponse[3] & 0x01) == 0x01; - - decoded.InactivityTimeMultiplier = (byte)(pageResponse[3] & 0x0F); - - return decoded; - } - - public static string PrettifyModePage_1C_SFF(byte[] pageResponse) => - PrettifyModePage_1C_SFF(DecodeModePage_1C_SFF(pageResponse)); - - public static string PrettifyModePage_1C_SFF(ModePage_1C_SFF? modePage) - { - if(!modePage.HasValue) - return null; - - ModePage_1C_SFF page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Timer & Protect page:"); - - 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"); - - 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; - } - - return sb.ToString(); - } - #endregion Mode Page 0x1C: Timer & Protect page + /// Parameters can be saved + public bool PS; + /// Time the device shall remain in the current state after seek, read or write operation + public byte InactivityTimeMultiplier; + /// Disabled until power cycle + public bool DISP; + /// Software Write Protect until Power-down + public bool SWPP; } + + public static ModePage_1C_SFF? DecodeModePage_1C_SFF(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x1C) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 8) + return null; + + var decoded = new ModePage_1C_SFF(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.DISP |= (pageResponse[2] & 0x02) == 0x02; + decoded.SWPP |= (pageResponse[3] & 0x01) == 0x01; + + decoded.InactivityTimeMultiplier = (byte)(pageResponse[3] & 0x0F); + + return decoded; + } + + public static string PrettifyModePage_1C_SFF(byte[] pageResponse) => + PrettifyModePage_1C_SFF(DecodeModePage_1C_SFF(pageResponse)); + + public static string PrettifyModePage_1C_SFF(ModePage_1C_SFF? modePage) + { + if(!modePage.HasValue) + return null; + + ModePage_1C_SFF page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Timer & Protect page:"); + + 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"); + + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x1C: Timer & Protect page } \ No newline at end of file diff --git a/SCSI/Modes/1D.cs b/SCSI/Modes/1D.cs index 829a00a..de450be 100644 --- a/SCSI/Modes/1D.cs +++ b/SCSI/Modes/1D.cs @@ -33,105 +33,104 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region Mode Page 0x1D: Medium Configuration Mode Page - public struct ModePage_1D - { - /// Parameters can be saved - public bool PS; - public bool WORMM; - public byte WormModeLabelRestrictions; - public byte WormModeFilemarkRestrictions; - } - - public static ModePage_1D? DecodeModePage_1D(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x1D) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length < 32) - return null; - - var decoded = new ModePage_1D(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.WORMM |= (pageResponse[2] & 0x01) == 0x01; - decoded.WormModeLabelRestrictions = pageResponse[4]; - decoded.WormModeFilemarkRestrictions = pageResponse[5]; - - return decoded; - } - - public static string PrettifyModePage_1D(byte[] pageResponse) => - PrettifyModePage_1D(DecodeModePage_1D(pageResponse)); - - public static string PrettifyModePage_1D(ModePage_1D? modePage) - { - if(!modePage.HasValue) - return null; - - 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.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(); - - break; - } - - switch(page.WormModeFilemarkRestrictions) - { - 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; - } - - return sb.ToString(); - } - #endregion Mode Page 0x1D: Medium Configuration Mode Page + /// Parameters can be saved + public bool PS; + public bool WORMM; + public byte WormModeLabelRestrictions; + public byte WormModeFilemarkRestrictions; } + + public static ModePage_1D? DecodeModePage_1D(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x1D) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length < 32) + return null; + + var decoded = new ModePage_1D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.WORMM |= (pageResponse[2] & 0x01) == 0x01; + decoded.WormModeLabelRestrictions = pageResponse[4]; + decoded.WormModeFilemarkRestrictions = pageResponse[5]; + + return decoded; + } + + public static string PrettifyModePage_1D(byte[] pageResponse) => + PrettifyModePage_1D(DecodeModePage_1D(pageResponse)); + + public static string PrettifyModePage_1D(ModePage_1D? modePage) + { + if(!modePage.HasValue) + return null; + + 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.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(); + + break; + } + + switch(page.WormModeFilemarkRestrictions) + { + 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; + } + + return sb.ToString(); + } + #endregion Mode Page 0x1D: Medium Configuration Mode Page } \ No newline at end of file diff --git a/SCSI/Modes/21_Certance.cs b/SCSI/Modes/21_Certance.cs index f11775d..c88b88d 100644 --- a/SCSI/Modes/21_Certance.cs +++ b/SCSI/Modes/21_Certance.cs @@ -33,173 +33,172 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region Certance Mode Page 0x21: Drive Capabilities Control Mode page - public struct Certance_ModePage_21 - { - /// Parameters can be saved - public bool PS; - public byte OperatingSystemsSupport; - public byte FirmwareTestControl2; - public byte ExtendedPOSTMode; - public byte InquiryStringControl; - public byte FirmwareTestControl; - public byte DataCompressionControl; - public bool HostUnloadOverride; - public byte AutoUnloadMode; - } - - public static Certance_ModePage_21? DecodeCertanceModePage_21(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x21) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 9) - return null; - - var decoded = new Certance_ModePage_21(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.OperatingSystemsSupport = pageResponse[2]; - decoded.FirmwareTestControl2 = pageResponse[3]; - decoded.ExtendedPOSTMode = pageResponse[4]; - decoded.InquiryStringControl = pageResponse[5]; - decoded.FirmwareTestControl = pageResponse[6]; - decoded.DataCompressionControl = pageResponse[7]; - decoded.HostUnloadOverride |= (pageResponse[8] & 0x80) == 0x80; - decoded.AutoUnloadMode = (byte)(pageResponse[8] & 0x7F); - - return decoded; - } - - public static string PrettifyCertanceModePage_21(byte[] pageResponse) => - PrettifyCertanceModePage_21(DecodeCertanceModePage_21(pageResponse)); - - public static string PrettifyCertanceModePage_21(Certance_ModePage_21? modePage) - { - if(!modePage.HasValue) - return null; - - Certance_ModePage_21 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Certance Drive Capabilities Control Mode Page:"); - - 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(); - - break; - } - - if(page.FirmwareTestControl == page.FirmwareTestControl2) - switch(page.FirmwareTestControl) - { - 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; - } - - switch(page.ExtendedPOSTMode) - { - 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; - } - - switch(page.DataCompressionControl) - { - 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"); - - 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; - } - - return sb.ToString(); - } - #endregion Certance Mode Page 0x21: Drive Capabilities Control Mode page + /// Parameters can be saved + public bool PS; + public byte OperatingSystemsSupport; + public byte FirmwareTestControl2; + public byte ExtendedPOSTMode; + public byte InquiryStringControl; + public byte FirmwareTestControl; + public byte DataCompressionControl; + public bool HostUnloadOverride; + public byte AutoUnloadMode; } + + public static Certance_ModePage_21? DecodeCertanceModePage_21(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x21) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 9) + return null; + + var decoded = new Certance_ModePage_21(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.OperatingSystemsSupport = pageResponse[2]; + decoded.FirmwareTestControl2 = pageResponse[3]; + decoded.ExtendedPOSTMode = pageResponse[4]; + decoded.InquiryStringControl = pageResponse[5]; + decoded.FirmwareTestControl = pageResponse[6]; + decoded.DataCompressionControl = pageResponse[7]; + decoded.HostUnloadOverride |= (pageResponse[8] & 0x80) == 0x80; + decoded.AutoUnloadMode = (byte)(pageResponse[8] & 0x7F); + + return decoded; + } + + public static string PrettifyCertanceModePage_21(byte[] pageResponse) => + PrettifyCertanceModePage_21(DecodeCertanceModePage_21(pageResponse)); + + public static string PrettifyCertanceModePage_21(Certance_ModePage_21? modePage) + { + if(!modePage.HasValue) + return null; + + Certance_ModePage_21 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Certance Drive Capabilities Control Mode Page:"); + + 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(); + + break; + } + + if(page.FirmwareTestControl == page.FirmwareTestControl2) + switch(page.FirmwareTestControl) + { + 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; + } + + switch(page.ExtendedPOSTMode) + { + 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; + } + + switch(page.DataCompressionControl) + { + 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"); + + 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; + } + + return sb.ToString(); + } + #endregion Certance Mode Page 0x21: Drive Capabilities Control Mode page } \ No newline at end of file diff --git a/SCSI/Modes/22_Certance.cs b/SCSI/Modes/22_Certance.cs index eeafb1a..62e2972 100644 --- a/SCSI/Modes/22_Certance.cs +++ b/SCSI/Modes/22_Certance.cs @@ -33,158 +33,157 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes { - [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 { - #region Certance Mode Page 0x22: Interface Control Mode Page - public struct Certance_ModePage_22 - { - /// Parameters can be saved - public bool PS; - public byte BaudRate; - public byte CmdFwd; - public bool StopBits; - public byte Alerts; - public byte PortATransportType; - public byte PortAPresentSelectionID; - public byte NextSelectionID; - public byte JumperedSelectionID; - public byte TargetInitiatedBusControl; - public bool PortAEnabled; - public bool PortAEnabledOnPower; - } - - public static Certance_ModePage_22? DecodeCertanceModePage_22(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x22) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 16) - return null; - - var decoded = new Certance_ModePage_22(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.BaudRate = pageResponse[2]; - decoded.CmdFwd = (byte)((pageResponse[3] & 0x18) >> 3); - decoded.StopBits |= (pageResponse[3] & 0x04) == 0x04; - decoded.CmdFwd = (byte)(pageResponse[3] & 0x03); - decoded.PortATransportType = pageResponse[4]; - decoded.PortAPresentSelectionID = pageResponse[7]; - decoded.NextSelectionID = pageResponse[12]; - decoded.JumperedSelectionID = pageResponse[13]; - decoded.TargetInitiatedBusControl = pageResponse[14]; - decoded.PortAEnabled |= (pageResponse[15] & 0x10) == 0x10; - decoded.PortAEnabledOnPower |= (pageResponse[15] & 0x04) == 0x04; - - return decoded; - } - - public static string PrettifyCertanceModePage_22(byte[] pageResponse) => - PrettifyCertanceModePage_22(DecodeCertanceModePage_22(pageResponse)); - - public static string PrettifyCertanceModePage_22(Certance_ModePage_22? modePage) - { - if(!modePage.HasValue) - return null; - - Certance_ModePage_22 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Certance Interface Control Mode Page:"); - - if(page.PS) - sb.AppendLine("\tParameters can be saved"); - - switch(page.BaudRate) - { - case 0: - 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" - : "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; - } - - switch(page.PortATransportType) - { - 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 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" - : "\tSCSI port will be disabled on next power up"); - - return sb.ToString(); - } - #endregion Certance Mode Page 0x22: Interface Control Mode Page + /// Parameters can be saved + public bool PS; + public byte BaudRate; + public byte CmdFwd; + public bool StopBits; + public byte Alerts; + public byte PortATransportType; + public byte PortAPresentSelectionID; + public byte NextSelectionID; + public byte JumperedSelectionID; + public byte TargetInitiatedBusControl; + public bool PortAEnabled; + public bool PortAEnabledOnPower; } + + public static Certance_ModePage_22? DecodeCertanceModePage_22(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x22) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 16) + return null; + + var decoded = new Certance_ModePage_22(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.BaudRate = pageResponse[2]; + decoded.CmdFwd = (byte)((pageResponse[3] & 0x18) >> 3); + decoded.StopBits |= (pageResponse[3] & 0x04) == 0x04; + decoded.CmdFwd = (byte)(pageResponse[3] & 0x03); + decoded.PortATransportType = pageResponse[4]; + decoded.PortAPresentSelectionID = pageResponse[7]; + decoded.NextSelectionID = pageResponse[12]; + decoded.JumperedSelectionID = pageResponse[13]; + decoded.TargetInitiatedBusControl = pageResponse[14]; + decoded.PortAEnabled |= (pageResponse[15] & 0x10) == 0x10; + decoded.PortAEnabledOnPower |= (pageResponse[15] & 0x04) == 0x04; + + return decoded; + } + + public static string PrettifyCertanceModePage_22(byte[] pageResponse) => + PrettifyCertanceModePage_22(DecodeCertanceModePage_22(pageResponse)); + + public static string PrettifyCertanceModePage_22(Certance_ModePage_22? modePage) + { + if(!modePage.HasValue) + return null; + + Certance_ModePage_22 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Certance Interface Control Mode Page:"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + switch(page.BaudRate) + { + case 0: + 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" + : "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; + } + + switch(page.PortATransportType) + { + 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 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" + : "\tSCSI port will be disabled on next power up"); + + return sb.ToString(); + } + #endregion Certance Mode Page 0x22: Interface Control Mode Page } \ No newline at end of file diff --git a/SCSI/Modes/24_IBM.cs b/SCSI/Modes/24_IBM.cs index 9695bcc..6564c0e 100644 --- a/SCSI/Modes/24_IBM.cs +++ b/SCSI/Modes/24_IBM.cs @@ -33,77 +33,76 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region IBM Mode Page 0x24: Drive Capabilities Control Mode page - public struct IBM_ModePage_24 - { - /// Parameters can be saved - public bool PS; - public byte ModeControl; - public byte VelocitySetting; - public bool EncryptionEnabled; - public bool EncryptionCapable; - } - - public static IBM_ModePage_24? DecodeIBMModePage_24(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x24) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 8) - return null; - - var decoded = new IBM_ModePage_24(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.ModeControl = pageResponse[2]; - decoded.VelocitySetting = pageResponse[3]; - decoded.EncryptionEnabled |= (pageResponse[7] & 0x08) == 0x08; - decoded.EncryptionCapable |= (pageResponse[7] & 0x01) == 0x01; - - return decoded; - } - - public static string PrettifyIBMModePage_24(byte[] pageResponse) => - PrettifyIBMModePage_24(DecodeIBMModePage_24(pageResponse)); - - public static string PrettifyIBMModePage_24(IBM_ModePage_24? modePage) - { - if(!modePage.HasValue) - return null; - - IBM_ModePage_24 page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("IBM Vendor-Specific Control Mode Page:"); - - if(page.PS) - sb.AppendLine("\tParameters can be saved"); - - sb.AppendFormat("\tVendor-specific mode control: {0}", page.ModeControl); - sb.AppendFormat("\tVendor-specific velocity setting: {0}", page.VelocitySetting); - - if(!page.EncryptionCapable) - return sb.ToString(); - - sb.AppendLine("\tDrive supports encryption"); - - if(page.EncryptionEnabled) - sb.AppendLine("\tDrive has encryption enabled"); - - return sb.ToString(); - } - #endregion IBM Mode Page 0x24: Drive Capabilities Control Mode page + /// Parameters can be saved + public bool PS; + public byte ModeControl; + public byte VelocitySetting; + public bool EncryptionEnabled; + public bool EncryptionCapable; } + + public static IBM_ModePage_24? DecodeIBMModePage_24(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x24) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 8) + return null; + + var decoded = new IBM_ModePage_24(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.ModeControl = pageResponse[2]; + decoded.VelocitySetting = pageResponse[3]; + decoded.EncryptionEnabled |= (pageResponse[7] & 0x08) == 0x08; + decoded.EncryptionCapable |= (pageResponse[7] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyIBMModePage_24(byte[] pageResponse) => + PrettifyIBMModePage_24(DecodeIBMModePage_24(pageResponse)); + + public static string PrettifyIBMModePage_24(IBM_ModePage_24? modePage) + { + if(!modePage.HasValue) + return null; + + IBM_ModePage_24 page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("IBM Vendor-Specific Control Mode Page:"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + sb.AppendFormat("\tVendor-specific mode control: {0}", page.ModeControl); + sb.AppendFormat("\tVendor-specific velocity setting: {0}", page.VelocitySetting); + + if(!page.EncryptionCapable) + return sb.ToString(); + + sb.AppendLine("\tDrive supports encryption"); + + if(page.EncryptionEnabled) + sb.AppendLine("\tDrive has encryption enabled"); + + return sb.ToString(); + } + #endregion IBM Mode Page 0x24: Drive Capabilities Control Mode page } \ No newline at end of file diff --git a/SCSI/Modes/2A.cs b/SCSI/Modes/2A.cs index 9281040..de28225 100644 --- a/SCSI/Modes/2A.cs +++ b/SCSI/Modes/2A.cs @@ -35,209 +35,208 @@ using System.Linq; using System.Text; using Aaru.CommonTypes.Structs.Devices.SCSI.Modes; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes { - [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 + public static string PrettifyModePage_2A(byte[] pageResponse) => + PrettifyModePage_2A(ModePage_2A.Decode(pageResponse)); + + public static string PrettifyModePage_2A(ModePage_2A modePage) { - #region Mode Page 0x2A: CD-ROM capabilities page - public static string PrettifyModePage_2A(byte[] pageResponse) => - PrettifyModePage_2A(ModePage_2A.Decode(pageResponse)); + if(modePage is null) + return null; - public static string PrettifyModePage_2A(ModePage_2A modePage) + 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.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.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) { - if(modePage is null) - return null; + case 0: + sb.AppendLine("\tDrive uses media caddy"); - ModePage_2A page = modePage; - var sb = new StringBuilder(); + break; + case 1: + sb.AppendLine("\tDrive uses a tray"); - sb.AppendLine("SCSI CD-ROM capabilities page:"); + break; + case 2: + sb.AppendLine("\tDrive is pop-up"); - if(page.PS) - sb.AppendLine("\tParameters can be saved"); + break; + case 4: + sb.AppendLine("\tDrive is a changer with individually changeable discs"); - if(page.AudioPlay) - sb.AppendLine("\tDrive can play audio"); + break; + case 5: + sb.AppendLine("\tDrive is a changer using cartridges"); - if(page.Mode2Form1) - sb.AppendLine("\tDrive can read sectors in Mode 2 Form 1 format"); + break; + default: + sb.AppendFormat("\tDrive uses unknown loading mechanism type {0}", page.LoadingMechanism). + AppendLine(); - 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(); - - break; - } - - 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" - : "\tDrive is not locked, media can be ejected and inserted"); - } - else - sb.AppendLine(page.LockState - ? "\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.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.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(); - - if(page.ReadCDR) - { - 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.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.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.SDP) - sb.AppendLine("\tDrive contains a changer that can report the exact contents of the slots"); - - if(page.CurrentWriteSpeedSelected > 0) - { - if(page.RotationControlSelected == 0) - sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec. in CLV mode", - page.CurrentWriteSpeedSelected).AppendLine(); - else if(page.RotationControlSelected == 1) - sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec. in pure CAV mode", - page.CurrentWriteSpeedSelected).AppendLine(); - } - else - { - if(page.MaxWriteSpeed > 0) - 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(); - } - - 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(); - 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.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.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(); + break; } - #endregion Mode Page 0x2A: CD-ROM capabilities page + + 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" + : "\tDrive is not locked, media can be ejected and inserted"); + } + else + sb.AppendLine(page.LockState + ? "\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.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.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(); + + if(page.ReadCDR) + { + 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.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.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.SDP) + sb.AppendLine("\tDrive contains a changer that can report the exact contents of the slots"); + + if(page.CurrentWriteSpeedSelected > 0) + { + if(page.RotationControlSelected == 0) + sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec. in CLV mode", + page.CurrentWriteSpeedSelected).AppendLine(); + else if(page.RotationControlSelected == 1) + sb.AppendFormat("\tDrive's current writing speed is {0} Kbyte/sec. in pure CAV mode", + page.CurrentWriteSpeedSelected).AppendLine(); + } + else + { + if(page.MaxWriteSpeed > 0) + 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(); + } + + 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(); + 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.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.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(); } + #endregion Mode Page 0x2A: CD-ROM capabilities page } \ No newline at end of file diff --git a/SCSI/Modes/2F_IBM.cs b/SCSI/Modes/2F_IBM.cs index a30d40e..9fa77f1 100644 --- a/SCSI/Modes/2F_IBM.cs +++ b/SCSI/Modes/2F_IBM.cs @@ -33,163 +33,162 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global")] +public static partial class Modes { - [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 { - #region IBM Mode Page 0x2F: Behaviour Configuration Mode page - public struct IBM_ModePage_2F - { - /// Parameters can be saved - public bool PS; - public byte FenceBehaviour; - public byte CleanBehaviour; - public byte WORMEmulation; - public byte SenseDataBehaviour; - public bool CCDM; - public bool DDEOR; - public bool CLNCHK; - public byte FirmwareUpdateBehaviour; - public byte UOE_D; - public byte UOE_F; - public byte UOE_C; - } - - public static IBM_ModePage_2F? DecodeIBMModePage_2F(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x2F) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - 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) - }; - } - - public static string PrettifyIBMModePage_2F(byte[] pageResponse) => - PrettifyIBMModePage_2F(DecodeIBMModePage_2F(pageResponse)); - - public static string PrettifyIBMModePage_2F(IBM_ModePage_2F? modePage) - { - if(!modePage.HasValue) - return null; - - IBM_ModePage_2F page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("IBM Behaviour Configuration Mode Page:"); - - 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; - } - - switch(page.CleanBehaviour) - { - 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; - } - - switch(page.WORMEmulation) - { - 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; - } - - switch(page.SenseDataBehaviour) - { - 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.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"); - - return sb.ToString(); - } - #endregion IBM Mode Page 0x2F: Behaviour Configuration Mode page + /// Parameters can be saved + public bool PS; + public byte FenceBehaviour; + public byte CleanBehaviour; + public byte WORMEmulation; + public byte SenseDataBehaviour; + public bool CCDM; + public bool DDEOR; + public bool CLNCHK; + public byte FirmwareUpdateBehaviour; + public byte UOE_D; + public byte UOE_F; + public byte UOE_C; } + + public static IBM_ModePage_2F? DecodeIBMModePage_2F(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x2F) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + 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) + }; + } + + public static string PrettifyIBMModePage_2F(byte[] pageResponse) => + PrettifyIBMModePage_2F(DecodeIBMModePage_2F(pageResponse)); + + public static string PrettifyIBMModePage_2F(IBM_ModePage_2F? modePage) + { + if(!modePage.HasValue) + return null; + + IBM_ModePage_2F page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("IBM Behaviour Configuration Mode Page:"); + + 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; + } + + switch(page.CleanBehaviour) + { + 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; + } + + switch(page.WORMEmulation) + { + 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; + } + + switch(page.SenseDataBehaviour) + { + 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.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"); + + return sb.ToString(); + } + #endregion IBM Mode Page 0x2F: Behaviour Configuration Mode page } \ No newline at end of file diff --git a/SCSI/Modes/30_Apple.cs b/SCSI/Modes/30_Apple.cs index a6d898d..4528970 100644 --- a/SCSI/Modes/30_Apple.cs +++ b/SCSI/Modes/30_Apple.cs @@ -34,38 +34,37 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Linq; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 = { - #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; + public static bool IsAppleModePage_30(byte[] pageResponse) + { + 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); + byte[] str = new byte[20]; + Array.Copy(pageResponse, 10, str, 0, 20); - return AppleOEMString.SequenceEqual(str); - } - #endregion Apple Mode Page 0x30: Apple OEM String + return AppleOEMString.SequenceEqual(str); } + #endregion Apple Mode Page 0x30: Apple OEM String } \ No newline at end of file diff --git a/SCSI/Modes/3B_HP.cs b/SCSI/Modes/3B_HP.cs index f6eb14d..a4820d6 100644 --- a/SCSI/Modes/3B_HP.cs +++ b/SCSI/Modes/3B_HP.cs @@ -35,77 +35,76 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region HP Mode Page 0x3B: Serial Number Override Mode page - public struct HP_ModePage_3B - { - /// Parameters can be saved - public bool PS; - public byte MSN; - public byte[] SerialNumber; - } - - public static HP_ModePage_3B? DecodeHPModePage_3B(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x3B) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 16) - return null; - - var decoded = new HP_ModePage_3B(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.MSN = (byte)(pageResponse[2] & 0x03); - decoded.SerialNumber = new byte[10]; - Array.Copy(pageResponse, 6, decoded.SerialNumber, 0, 10); - - return decoded; - } - - public static string PrettifyHPModePage_3B(byte[] pageResponse) => - PrettifyHPModePage_3B(DecodeHPModePage_3B(pageResponse)); - - public static string PrettifyHPModePage_3B(HP_ModePage_3B? modePage) - { - if(!modePage.HasValue) - return null; - - HP_ModePage_3B page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("HP Serial Number Override Mode Page:"); - - 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; - } - - sb.AppendFormat("\tSerial number: {0}", StringHandlers.CToString(page.SerialNumber)).AppendLine(); - - return sb.ToString(); - } - #endregion HP Mode Page 0x3B: Serial Number Override Mode page + /// Parameters can be saved + public bool PS; + public byte MSN; + public byte[] SerialNumber; } + + public static HP_ModePage_3B? DecodeHPModePage_3B(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x3B) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 16) + return null; + + var decoded = new HP_ModePage_3B(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.MSN = (byte)(pageResponse[2] & 0x03); + decoded.SerialNumber = new byte[10]; + Array.Copy(pageResponse, 6, decoded.SerialNumber, 0, 10); + + return decoded; + } + + public static string PrettifyHPModePage_3B(byte[] pageResponse) => + PrettifyHPModePage_3B(DecodeHPModePage_3B(pageResponse)); + + public static string PrettifyHPModePage_3B(HP_ModePage_3B? modePage) + { + if(!modePage.HasValue) + return null; + + HP_ModePage_3B page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("HP Serial Number Override Mode Page:"); + + 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; + } + + sb.AppendFormat("\tSerial number: {0}", StringHandlers.CToString(page.SerialNumber)).AppendLine(); + + return sb.ToString(); + } + #endregion HP Mode Page 0x3B: Serial Number Override Mode page } \ No newline at end of file diff --git a/SCSI/Modes/3C_HP.cs b/SCSI/Modes/3C_HP.cs index 2ea295b..fb61fa2 100644 --- a/SCSI/Modes/3C_HP.cs +++ b/SCSI/Modes/3C_HP.cs @@ -35,118 +35,117 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region HP Mode Page 0x3C: Device Time Mode page - public struct HP_ModePage_3C - { - /// Parameters can be saved - public bool PS; - public bool LT; - public bool WT; - public bool PT; - public ushort CurrentPowerOn; - public uint PowerOnTime; - public bool UTC; - public bool NTP; - public uint WorldTime; - public byte LibraryHours; - public byte LibraryMinutes; - public byte LibrarySeconds; - public uint CumulativePowerOn; - } - - public static HP_ModePage_3C? DecodeHPModePage_3C(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x3C) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 36) - return null; - - 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]); - - return decoded; - } - - public static string PrettifyHPModePage_3C(byte[] pageResponse) => - PrettifyHPModePage_3C(DecodeHPModePage_3C(pageResponse)); - - public static string PrettifyHPModePage_3C(HP_ModePage_3C? modePage) - { - if(!modePage.HasValue) - return null; - - HP_ModePage_3C page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("HP Device Time Mode Page:"); - - 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"); - } - - if(page.LT) - sb.AppendFormat("\tLibrary time is {0}", - new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, page.LibraryHours, - page.LibraryMinutes, page.LibrarySeconds)).AppendLine(); - - return sb.ToString(); - } - #endregion HP Mode Page 0x3C: Device Time Mode page + /// Parameters can be saved + public bool PS; + public bool LT; + public bool WT; + public bool PT; + public ushort CurrentPowerOn; + public uint PowerOnTime; + public bool UTC; + public bool NTP; + public uint WorldTime; + public byte LibraryHours; + public byte LibraryMinutes; + public byte LibrarySeconds; + public uint CumulativePowerOn; } + + public static HP_ModePage_3C? DecodeHPModePage_3C(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x3C) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 36) + return null; + + 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]); + + return decoded; + } + + public static string PrettifyHPModePage_3C(byte[] pageResponse) => + PrettifyHPModePage_3C(DecodeHPModePage_3C(pageResponse)); + + public static string PrettifyHPModePage_3C(HP_ModePage_3C? modePage) + { + if(!modePage.HasValue) + return null; + + HP_ModePage_3C page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("HP Device Time Mode Page:"); + + 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"); + } + + if(page.LT) + sb.AppendFormat("\tLibrary time is {0}", + new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, page.LibraryHours, + page.LibraryMinutes, page.LibrarySeconds)).AppendLine(); + + return sb.ToString(); + } + #endregion HP Mode Page 0x3C: Device Time Mode page } \ No newline at end of file diff --git a/SCSI/Modes/3D_HP.cs b/SCSI/Modes/3D_HP.cs index 5c46794..898b318 100644 --- a/SCSI/Modes/3D_HP.cs +++ b/SCSI/Modes/3D_HP.cs @@ -33,76 +33,75 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region HP Mode Page 0x3D: Extended Reset Mode page - public struct HP_ModePage_3D - { - /// Parameters can be saved - 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] & 0x3F) != 0x3D) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 4) - return null; - - var decoded = new HP_ModePage_3D(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.ResetBehaviour = (byte)(pageResponse[2] & 0x03); - - return decoded; - } - - public static string PrettifyHPModePage_3D(byte[] pageResponse) => - PrettifyHPModePage_3D(DecodeHPModePage_3D(pageResponse)); - - public static string PrettifyHPModePage_3D(HP_ModePage_3D? modePage) - { - if(!modePage.HasValue) - return null; - - HP_ModePage_3D page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("HP Extended Reset Mode Page:"); - - 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; - } - - return sb.ToString(); - } - #endregion HP Mode Page 0x3D: Extended Reset Mode page + /// Parameters can be saved + 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] & 0x3F) != 0x3D) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 4) + return null; + + var decoded = new HP_ModePage_3D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.ResetBehaviour = (byte)(pageResponse[2] & 0x03); + + return decoded; + } + + public static string PrettifyHPModePage_3D(byte[] pageResponse) => + PrettifyHPModePage_3D(DecodeHPModePage_3D(pageResponse)); + + public static string PrettifyHPModePage_3D(HP_ModePage_3D? modePage) + { + if(!modePage.HasValue) + return null; + + HP_ModePage_3D page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("HP Extended Reset Mode Page:"); + + 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; + } + + return sb.ToString(); + } + #endregion HP Mode Page 0x3D: Extended Reset Mode page } \ No newline at end of file diff --git a/SCSI/Modes/3D_IBM.cs b/SCSI/Modes/3D_IBM.cs index a9049ee..eec079c 100644 --- a/SCSI/Modes/3D_IBM.cs +++ b/SCSI/Modes/3D_IBM.cs @@ -33,62 +33,61 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region IBM Mode Page 0x3D: Behaviour Configuration Mode page - public struct IBM_ModePage_3D - { - /// Parameters can be saved - 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] & 0x3F) != 0x3D) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 5) - return null; - - var decoded = new IBM_ModePage_3D(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.NumberOfWraps = (ushort)((pageResponse[3] << 8) + pageResponse[4]); - - return decoded; - } - - public static string PrettifyIBMModePage_3D(byte[] pageResponse) => - PrettifyIBMModePage_3D(DecodeIBMModePage_3D(pageResponse)); - - public static string PrettifyIBMModePage_3D(IBM_ModePage_3D? modePage) - { - if(!modePage.HasValue) - return null; - - IBM_ModePage_3D page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("IBM LEOT Mode Page:"); - - if(page.PS) - sb.AppendLine("\tParameters can be saved"); - - sb.AppendFormat("\t{0} wraps", page.NumberOfWraps).AppendLine(); - - return sb.ToString(); - } - #endregion IBM Mode Page 0x3D: Behaviour Configuration Mode page + /// Parameters can be saved + 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] & 0x3F) != 0x3D) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 5) + return null; + + var decoded = new IBM_ModePage_3D(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.NumberOfWraps = (ushort)((pageResponse[3] << 8) + pageResponse[4]); + + return decoded; + } + + public static string PrettifyIBMModePage_3D(byte[] pageResponse) => + PrettifyIBMModePage_3D(DecodeIBMModePage_3D(pageResponse)); + + public static string PrettifyIBMModePage_3D(IBM_ModePage_3D? modePage) + { + if(!modePage.HasValue) + return null; + + IBM_ModePage_3D page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("IBM LEOT Mode Page:"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + sb.AppendFormat("\t{0} wraps", page.NumberOfWraps).AppendLine(); + + return sb.ToString(); + } + #endregion IBM Mode Page 0x3D: Behaviour Configuration Mode page } \ No newline at end of file diff --git a/SCSI/Modes/3E_Fujitsu.cs b/SCSI/Modes/3E_Fujitsu.cs index aea9a56..0104faa 100644 --- a/SCSI/Modes/3E_Fujitsu.cs +++ b/SCSI/Modes/3E_Fujitsu.cs @@ -35,115 +35,114 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.CommonTypes.Structs.Devices.SCSI; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static partial class Modes { - [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 { - #region Fujitsu Mode Page 0x3E: Verify Control page - public enum Fujitsu_VerifyModes : byte - { - /// Always verify after writing - Always = 0, - /// Never verify after writing - Never = 1, - /// Verify after writing depending on condition - Depends = 2, Reserved = 4 - } - - public struct Fujitsu_ModePage_3E - { - /// Parameters can be saved - public bool PS; - /// If set, AV data support mode is applied - public bool audioVisualMode; - /// If set the test write operation is restricted - public bool streamingMode; - public byte Reserved1; - /// Verify mode for WRITE commands - public Fujitsu_VerifyModes verifyMode; - public byte Reserved2; - /// Device type provided in response to INQUIRY - 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] & 0x3F) != 0x3E) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 8) - return null; - - var decoded = new Fujitsu_ModePage_3E(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - - decoded.audioVisualMode |= (pageResponse[2] & 0x80) == 0x80; - decoded.streamingMode |= (pageResponse[2] & 0x40) == 0x40; - decoded.Reserved1 = (byte)((pageResponse[2] & 0x3C) >> 2); - decoded.verifyMode = (Fujitsu_VerifyModes)(pageResponse[2] & 0x03); - - decoded.Reserved2 = (byte)((pageResponse[3] & 0xE0) >> 5); - decoded.devType = (PeripheralDeviceTypes)(pageResponse[3] & 0x1F); - - decoded.Reserved3 = new byte[4]; - Array.Copy(pageResponse, 4, decoded.Reserved3, 0, 4); - - return decoded; - } - - public static string PrettifyFujitsuModePage_3E(byte[] pageResponse) => - PrettifyFujitsuModePage_3E(DecodeFujitsuModePage_3E(pageResponse)); - - public static string PrettifyFujitsuModePage_3E(Fujitsu_ModePage_3E? modePage) - { - if(!modePage.HasValue) - return null; - - Fujitsu_ModePage_3E page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("Fujitsu Verify Control Page:"); - - if(page.PS) - sb.AppendLine("\tParameters can be saved"); - - 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."); - - switch(page.verifyMode) - { - 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(); - - return sb.ToString(); - } - #endregion Fujitsu Mode Page 0x3E: Verify Control page + /// Always verify after writing + Always = 0, + /// Never verify after writing + Never = 1, + /// Verify after writing depending on condition + Depends = 2, Reserved = 4 } + + public struct Fujitsu_ModePage_3E + { + /// Parameters can be saved + public bool PS; + /// If set, AV data support mode is applied + public bool audioVisualMode; + /// If set the test write operation is restricted + public bool streamingMode; + public byte Reserved1; + /// Verify mode for WRITE commands + public Fujitsu_VerifyModes verifyMode; + public byte Reserved2; + /// Device type provided in response to INQUIRY + 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] & 0x3F) != 0x3E) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 8) + return null; + + var decoded = new Fujitsu_ModePage_3E(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + + decoded.audioVisualMode |= (pageResponse[2] & 0x80) == 0x80; + decoded.streamingMode |= (pageResponse[2] & 0x40) == 0x40; + decoded.Reserved1 = (byte)((pageResponse[2] & 0x3C) >> 2); + decoded.verifyMode = (Fujitsu_VerifyModes)(pageResponse[2] & 0x03); + + decoded.Reserved2 = (byte)((pageResponse[3] & 0xE0) >> 5); + decoded.devType = (PeripheralDeviceTypes)(pageResponse[3] & 0x1F); + + decoded.Reserved3 = new byte[4]; + Array.Copy(pageResponse, 4, decoded.Reserved3, 0, 4); + + return decoded; + } + + public static string PrettifyFujitsuModePage_3E(byte[] pageResponse) => + PrettifyFujitsuModePage_3E(DecodeFujitsuModePage_3E(pageResponse)); + + public static string PrettifyFujitsuModePage_3E(Fujitsu_ModePage_3E? modePage) + { + if(!modePage.HasValue) + return null; + + Fujitsu_ModePage_3E page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("Fujitsu Verify Control Page:"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + 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."); + + switch(page.verifyMode) + { + 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(); + + return sb.ToString(); + } + #endregion Fujitsu Mode Page 0x3E: Verify Control page } \ No newline at end of file diff --git a/SCSI/Modes/3E_HP.cs b/SCSI/Modes/3E_HP.cs index e38cc66..6b17c92 100644 --- a/SCSI/Modes/3E_HP.cs +++ b/SCSI/Modes/3E_HP.cs @@ -33,68 +33,67 @@ using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [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 { - #region HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page - public struct HP_ModePage_3E - { - /// Parameters can be saved - public bool PS; - public bool NonAuto; - public bool CDmode; - } - - public static HP_ModePage_3E? DecodeHPModePage_3E(byte[] pageResponse) - { - if((pageResponse?[0] & 0x40) == 0x40) - return null; - - if((pageResponse?[0] & 0x3F) != 0x3E) - return null; - - if(pageResponse[1] + 2 != pageResponse.Length) - return null; - - if(pageResponse.Length != 4) - return null; - - var decoded = new HP_ModePage_3E(); - - decoded.PS |= (pageResponse[0] & 0x80) == 0x80; - decoded.NonAuto |= (pageResponse[2] & 0x02) == 0x02; - decoded.CDmode |= (pageResponse[2] & 0x01) == 0x01; - - return decoded; - } - - public static string PrettifyHPModePage_3E(byte[] pageResponse) => - PrettifyHPModePage_3E(DecodeHPModePage_3E(pageResponse)); - - public static string PrettifyHPModePage_3E(HP_ModePage_3E? modePage) - { - if(!modePage.HasValue) - return null; - - HP_ModePage_3E page = modePage.Value; - var sb = new StringBuilder(); - - sb.AppendLine("HP CD-ROM Emulation/Disaster Recovery Mode Page:"); - - if(page.PS) - sb.AppendLine("\tParameters can be saved"); - - 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"); - - return sb.ToString(); - } - #endregion HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page + /// Parameters can be saved + public bool PS; + public bool NonAuto; + public bool CDmode; } + + public static HP_ModePage_3E? DecodeHPModePage_3E(byte[] pageResponse) + { + if((pageResponse?[0] & 0x40) == 0x40) + return null; + + if((pageResponse?[0] & 0x3F) != 0x3E) + return null; + + if(pageResponse[1] + 2 != pageResponse.Length) + return null; + + if(pageResponse.Length != 4) + return null; + + var decoded = new HP_ModePage_3E(); + + decoded.PS |= (pageResponse[0] & 0x80) == 0x80; + decoded.NonAuto |= (pageResponse[2] & 0x02) == 0x02; + decoded.CDmode |= (pageResponse[2] & 0x01) == 0x01; + + return decoded; + } + + public static string PrettifyHPModePage_3E(byte[] pageResponse) => + PrettifyHPModePage_3E(DecodeHPModePage_3E(pageResponse)); + + public static string PrettifyHPModePage_3E(HP_ModePage_3E? modePage) + { + if(!modePage.HasValue) + return null; + + HP_ModePage_3E page = modePage.Value; + var sb = new StringBuilder(); + + sb.AppendLine("HP CD-ROM Emulation/Disaster Recovery Mode Page:"); + + if(page.PS) + sb.AppendLine("\tParameters can be saved"); + + 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"); + + return sb.ToString(); + } + #endregion HP Mode Page 0x3E: CD-ROM Emulation/Disaster Recovery Mode page } \ No newline at end of file diff --git a/SCSI/Modes/Headers.cs b/SCSI/Modes/Headers.cs index 3e61ced..f3f4b1a 100644 --- a/SCSI/Modes/Headers.cs +++ b/SCSI/Modes/Headers.cs @@ -34,2096 +34,2095 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.CommonTypes.Structs.Devices.SCSI; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + public static string GetMediumTypeDescription(MediumTypes type) { - public static string GetMediumTypeDescription(MediumTypes type) + switch(type) { - switch(type) - { - case MediumTypes.ECMA54: - return - "ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side"; - case MediumTypes.ECMA59: - return - "ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on Both Sides"; - case MediumTypes.ECMA69: - return "ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides"; - case MediumTypes.ECMA66: - return - "ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side"; - case MediumTypes.ECMA70: - return - "ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 1,9 Tracks per mm"; - case MediumTypes.ECMA78: - return - "ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 3,8 Tracks per mm"; - case MediumTypes.ECMA99: - return - "ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; 3,8 Tracks per mm"; - case MediumTypes.ECMA100: - return - "ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; 5,3 Tracks per mm"; + case MediumTypes.ECMA54: + return + "ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side"; + case MediumTypes.ECMA59: + return + "ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on Both Sides"; + case MediumTypes.ECMA69: + return "ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides"; + case MediumTypes.ECMA66: + return + "ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side"; + case MediumTypes.ECMA70: + return + "ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 1,9 Tracks per mm"; + case MediumTypes.ECMA78: + return + "ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both Sides; 3,8 Tracks per mm"; + case MediumTypes.ECMA99: + return + "ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; 3,8 Tracks per mm"; + case MediumTypes.ECMA100: + return + "ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; 5,3 Tracks per mm"; - // Most probably they will never appear, but magneto-opticals use these codes - /* - case MediumTypes.Unspecified_SS: - return "Unspecified single sided flexible disk"; - case MediumTypes.Unspecified_DS: - return "Unspecified double sided flexible disk"; - */ - case MediumTypes.X3_73: return "ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 1 side"; - case MediumTypes.X3_73_DS: return "ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 2 sides"; - case MediumTypes.X3_82: return "ANSI X3.80-1980: 130 mm, 3979 ftprad, 1,9 Tracks per mm, 1 side"; - case MediumTypes.Type3Floppy: - return "3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb)"; - case MediumTypes.HDFloppy: return "3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb)"; - case MediumTypes.ReadOnly: return "a Read-only optical"; - case MediumTypes.WORM: return "a Write-once Read-many optical"; - case MediumTypes.Erasable: return "a Erasable optical"; - case MediumTypes.RO_WORM: return "a combination of read-only and write-once optical"; + // Most probably they will never appear, but magneto-opticals use these codes + /* + case MediumTypes.Unspecified_SS: + return "Unspecified single sided flexible disk"; + case MediumTypes.Unspecified_DS: + return "Unspecified double sided flexible disk"; + */ + case MediumTypes.X3_73: return "ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 1 side"; + case MediumTypes.X3_73_DS: return "ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 2 sides"; + case MediumTypes.X3_82: return "ANSI X3.80-1980: 130 mm, 3979 ftprad, 1,9 Tracks per mm, 1 side"; + case MediumTypes.Type3Floppy: + return "3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb)"; + case MediumTypes.HDFloppy: return "3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb)"; + case MediumTypes.ReadOnly: return "a Read-only optical"; + case MediumTypes.WORM: return "a Write-once Read-many optical"; + case MediumTypes.Erasable: return "a Erasable optical"; + case MediumTypes.RO_WORM: return "a combination of read-only and write-once optical"; - // These magneto-opticals were never manufactured - /* - case MediumTypes.RO_RW: - return "a combination of read-only and erasable optical"; - break; - case MediumTypes.WORM_RW: - return "a combination of write-once and erasable optical"; - */ - case MediumTypes.DOW: return "a direct-overwrite optical"; - case MediumTypes.HiMD: return "a Sony Hi-MD disc"; - default: return $"Unknown medium type 0x{(byte)type:X2}"; - } + // These magneto-opticals were never manufactured + /* + case MediumTypes.RO_RW: + return "a combination of read-only and erasable optical"; + break; + case MediumTypes.WORM_RW: + return "a combination of write-once and erasable optical"; + */ + case MediumTypes.DOW: return "a direct-overwrite optical"; + case MediumTypes.HiMD: return "a Sony Hi-MD disc"; + default: return $"Unknown medium type 0x{(byte)type:X2}"; } + } - public static string PrettifyModeHeader(ModeHeader? header, PeripheralDeviceTypes deviceType) + public static string PrettifyModeHeader(ModeHeader? header, PeripheralDeviceTypes deviceType) + { + if(!header.HasValue) + return null; + + var sb = new StringBuilder(); + + sb.AppendLine("SCSI Mode Sense Header:"); + + switch(deviceType) { - if(!header.HasValue) - return null; - - var sb = new StringBuilder(); - - sb.AppendLine("SCSI Mode Sense Header:"); - - switch(deviceType) + #region Direct access device mode header + case PeripheralDeviceTypes.DirectAccess: { - #region Direct access device mode header - case PeripheralDeviceTypes.DirectAccess: - { - if(header.Value.MediumType != MediumTypes.Default) - sb.AppendFormat("\tMedium is {0}", GetMediumTypeDescription(header.Value.MediumType)). - AppendLine(); + if(header.Value.MediumType != MediumTypes.Default) + sb.AppendFormat("\tMedium is {0}", GetMediumTypeDescription(header.Value.MediumType)). + AppendLine(); - if(header.Value.WriteProtected) - sb.AppendLine("\tMedium is write protected"); + if(header.Value.WriteProtected) + sb.AppendLine("\tMedium is write protected"); - if(header.Value.DPOFUA) - sb.AppendLine("\tDrive supports DPO and FUA bits"); + if(header.Value.DPOFUA) + sb.AppendLine("\tDrive supports DPO and FUA bits"); - if(header.Value.BlockDescriptors != null) - foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + if(header.Value.BlockDescriptors != null) + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + string density = ""; + + switch(descriptor.Density) { - string density = ""; - - switch(descriptor.Density) - { - case DensityType.Default: break; - case DensityType.Flux7958: - density = "7958 flux transitions per radian"; - - break; - case DensityType.Flux13262: - density = "13262 flux transitions per radian"; - - break; - case DensityType.Flux15916: - density = "15916 flux transitions per radian"; - - break; - default: - density = $"with unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - - if(density != "") - if(descriptor.Blocks == 0) - sb.AppendFormat("\tAll remaining blocks have {0} and are {1} bytes each", density, - descriptor.BlockLength).AppendLine(); - else - sb.AppendFormat("\t{0} blocks have {1} and are {2} bytes each", descriptor.Blocks, - density, descriptor.BlockLength).AppendLine(); - else if(descriptor.Blocks == 0) - sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength). - AppendLine(); - else - sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, - descriptor.BlockLength).AppendLine(); - } - - break; - } - #endregion Direct access device mode header - - #region Sequential access device mode header - case PeripheralDeviceTypes.SequentialAccess: - { - switch(header.Value.BufferedMode) - { - case 0: - sb.AppendLine("\tDevice writes directly to media"); - - break; - case 1: - sb.AppendLine("\tDevice uses a write cache"); - - break; - case 2: - sb.AppendLine("\tDevice uses a write cache but doesn't return until cache is flushed"); - - break; - default: - sb.AppendFormat("\tUnknown buffered mode code 0x{0:X2}", header.Value.BufferedMode). - AppendLine(); - - break; - } - - if(header.Value.Speed == 0) - sb.AppendLine("\tDevice uses default speed"); - else - sb.AppendFormat("\tDevice uses speed {0}", header.Value.Speed).AppendLine(); - - if(header.Value.WriteProtected) - sb.AppendLine("\tMedium is write protected"); - - string medium; - - switch(header.Value.MediumType) - { - case MediumTypes.Default: - medium = "undefined"; - - break; - case MediumTypes.Tape12: - medium = "6,3 mm tape with 12 tracks at 394 ftpmm or DC-9250"; - - break; - case MediumTypes.Tape24: - medium = "6,3 mm tape with 24 tracks at 394 ftpmm or MLR1-26GBSL"; - - break; - case MediumTypes.LTOWORM: - medium = "LTO Ultrium WORM or cleaning cartridge"; - - break; - case MediumTypes.LTO: - medium = "LTO Ultrium"; - - break; - case MediumTypes.LTO2: - medium = "LTO Ultrium-2"; - - break; - case MediumTypes.DC2900SL: - medium = "DC-2900SL"; - - break; - case MediumTypes.MLR1: - medium = "MLR1-26GB or DDS-3"; - - break; - case MediumTypes.DC9200: - medium = "DC-9200 or DDS-4"; - - break; - case MediumTypes.DAT72: - medium = "DAT-72"; - - break; - case MediumTypes.LTO3: - medium = "LTO Ultrium-3"; - - break; - case MediumTypes.LTO3WORM: - medium = "LTO Ultrium-3 WORM"; - - break; - case MediumTypes.DDSCleaning: - medium = "DDS cleaning cartridge"; - - break; - case MediumTypes.SLR32: - medium = "SLR-32"; - - break; - case MediumTypes.SLRtape50: - medium = "SLRtape-50"; - - break; - case MediumTypes.LTO4: - medium = "LTO Ultrium-4"; - - break; - case MediumTypes.LTO4WORM: - medium = "LTO Ultrium-4 WORM"; - - break; - case MediumTypes.SLRtape50SL: - medium = "SLRtape-50 SL"; - - break; - case MediumTypes.SLR32SL: - medium = "SLR-32SL"; - - break; - case MediumTypes.SLR5: - medium = "SLR-5"; - - break; - case MediumTypes.SLR5SL: - medium = "SLR-5SL"; - - break; - case MediumTypes.LTO5: - medium = "LTO Ultrium-5"; - - break; - case MediumTypes.LTO5WORM: - medium = "LTO Ultrium-5 WORM"; - - break; - case MediumTypes.SLRtape7: - medium = "SLRtape-7"; - - break; - case MediumTypes.SLRtape7SL: - medium = "SLRtape-7 SL"; - - break; - case MediumTypes.SLRtape24: - medium = "SLRtape-24"; - - break; - case MediumTypes.SLRtape24SL: - medium = "SLRtape-24 SL"; - - break; - case MediumTypes.LTO6: - medium = "LTO Ultrium-6"; - - break; - case MediumTypes.LTO6WORM: - medium = "LTO Ultrium-6 WORM"; - - break; - case MediumTypes.SLRtape140: - medium = "SLRtape-140"; - - break; - case MediumTypes.SLRtape40: - medium = "SLRtape-40"; - - break; - case MediumTypes.SLRtape60: - medium = "SLRtape-60 or SLRtape-75"; - - break; - case MediumTypes.SLRtape100: - medium = "SLRtape-100"; - - break; - case MediumTypes.SLR40_60_100: - medium = "SLR-40, SLR-60 or SLR-100"; - - break; - case MediumTypes.LTO7: - medium = "LTO Ultrium-7"; - - break; - case MediumTypes.LTO7WORM: - medium = "LTO Ultrium-7 WORM"; - - break; - case MediumTypes.LTOCD: - medium = "LTO Ultrium"; - - break; - case MediumTypes.Exatape15m: - medium = "Exatape 15m, IBM MagStar or VXA"; - - break; - case MediumTypes.CT1: - medium = "CompactTape I, Exatape 28m, CompactTape II, VXA-2 or VXA-3"; - - break; - case MediumTypes.Exatape54m: - medium = "Exatape 54m or DLTtape III"; - - break; - case MediumTypes.Exatape80m: - medium = "Exatape 80m or DLTtape IIIxt"; - - break; - case MediumTypes.Exatape106m: - medium = "Exatape 106m, DLTtape IV or Travan 5"; - - break; - case MediumTypes.Exatape106mXL: - medium = "Exatape 160m XL or Super DLTtape I"; - - break; - case MediumTypes.SDLT2: - medium = "Super DLTtape II"; - - break; - case MediumTypes.VStapeI: - medium = "VStape I"; - - break; - case MediumTypes.DLTtapeS4: - medium = "DLTtape S4"; - - break; - case MediumTypes.Travan7: - medium = "Travan 7"; - - break; - case MediumTypes.Exatape22m: - medium = "Exatape 22m"; - - break; - case MediumTypes.Exatape40m: - medium = "Exatape 40m"; - - break; - case MediumTypes.Exatape76m: - medium = "Exatape 76m"; - - break; - case MediumTypes.Exatape112m: - medium = "Exatape 112m"; - - break; - case MediumTypes.Exatape22mAME: - medium = "Exatape 22m AME"; - - break; - case MediumTypes.Exatape170m: - medium = "Exatape 170m"; - - break; - case MediumTypes.Exatape125m: - medium = "Exatape 125m"; - - break; - case MediumTypes.Exatape45m: - medium = "Exatape 45m"; - - break; - case MediumTypes.Exatape225m: - medium = "Exatape 225m"; - - break; - case MediumTypes.Exatape150m: - medium = "Exatape 150m"; - - break; - case MediumTypes.Exatape75m: - medium = "Exatape 75m"; - - break; - default: - medium = $"unknown medium type 0x{(byte)header.Value.MediumType:X2}"; - - break; - } - - sb.AppendFormat("\tMedium is {0}", medium).AppendLine(); - - if(header.Value.BlockDescriptors != null) - foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) - { - string density = ""; - - switch(header.Value.MediumType) - { - case MediumTypes.Default: - { - switch(descriptor.Density) - { - case DensityType.Default: break; - case DensityType.ECMA62: - density = - "ECMA-62 & ANSI X3.22-1983: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm"; - - break; - case DensityType.ECMA62_Phase: - density = - "ECMA-62 & ANSI X3.39-1986: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm"; - - break; - case DensityType.ECMA62_GCR: - density = - "ECMA-62 & ANSI X3.54-1986: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR"; - - break; - case DensityType.ECMA79: - density = - "ECMA-79 & ANSI X3.116-1986: 6,30 mm Magnetic Tape Cartridge, 252 ftpmm, MFM"; - - break; - case DensityType.IBM3480: - density = - "Draft ECMA & ANSI X3B5/87-099: 12,7 mm 18-Track Magnetic Tape Cartridge, 1944 ftpmm, IFM, GCR (IBM 3480, 3490, 3490E)"; - - break; - case DensityType.ECMA46: - density = - "ECMA-46 & ANSI X3.56-1986: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm"; - - break; - case DensityType.ECMA98: - density = "ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZI, 394 ftpmm"; - - break; - case DensityType.X3_136: - density = - "ANXI X3.136-1986: 6,3 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24)"; - - break; - case DensityType.X3_157: - density = - "ANXI X3.157-1987: 12,7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding"; - - break; - case DensityType.X3_158: - density = - "ANXI X3.158-1987: 3,81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR"; - - break; - case DensityType.X3B5_86: - density = - "ANXI X3B5/86-199: 12,7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM"; - - break; - case DensityType.HiTC1: - density = "HI-TC1: 12,7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR"; - - break; - case DensityType.HiTC2: - density = "HI-TC2: 12,7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR"; - - break; - case DensityType.QIC120: - density = "QIC-120: 6,3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR"; - - break; - case DensityType.QIC150: - density = "QIC-150: 6,3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR"; - - break; - case DensityType.QIC320: - density = "QIC-320: 6,3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR"; - - break; - case DensityType.QIC1350: - density = - "QIC-1350: 6,3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL"; - - break; - case DensityType.X3B5_88: - density = - "ANXI X3B5/88-185A: 3,81 mm Magnetic Tape Cassette, 2400 bpmm, DDS"; - - break; - case DensityType.X3_202: - density = "ANXI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL"; - - break; - case DensityType.ECMA_TC17: - density = "ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL"; - - break; - case DensityType.X3_193: - density = - "ANXI X3.193-1990: 12,7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM"; - - break; - case DensityType.X3B5_91: - density = - "ANXI X3B5/97-174: 12,7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM"; - - break; - case DensityType.QIC11: - density = "QIC-11"; - - break; - case DensityType.IBM3490E: - density = "IBM 3490E"; - - break; - case DensityType.LTO1: - //case DensityType.SAIT1: - density = "LTO Ultrium or Super AIT-1"; - - break; - case DensityType.LTO2Old: - density = "LTO Ultrium-2"; - - break; - case DensityType.LTO2: - //case DensityType.T9840: - density = "LTO Ultrium-2 or T9840"; - - break; - case DensityType.T9940: - density = "T9940"; - - break; - case DensityType.LTO3: - //case DensityType.T9940: - density = "LTO Ultrium-3 or T9940"; - - break; - case DensityType.T9840C: - density = "T9840C"; - - break; - case DensityType.LTO4: - //case DensityType.T9840D: - density = "LTO Ultrium-4 or T9840D"; - - break; - case DensityType.T10000A: - density = "T10000A"; - - break; - case DensityType.T10000B: - density = "T10000B"; - - break; - case DensityType.T10000C: - density = "T10000C"; - - break; - case DensityType.T10000D: - density = "T10000D"; - - break; - case DensityType.AIT1: - density = "AIT-1"; - - break; - case DensityType.AIT2: - density = "AIT-2"; - - break; - case DensityType.AIT3: - density = "AIT-3"; - - break; - case DensityType.DDS2: - density = "DDS-2"; - - break; - case DensityType.DDS3: - density = "DDS-3"; - - break; - case DensityType.DDS4: - density = "DDS-4"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTOWORM: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "LTO Ultrium cleaning cartridge"; - - break; - case DensityType.LTO3: - density = "LTO Ultrium-3 WORM"; - - break; - case DensityType.LTO4: - density = "LTO Ultrium-4 WORM"; - - break; - case DensityType.LTO5: - density = "LTO Ultrium-5 WORM"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTO: - { - switch(descriptor.Density) - { - case DensityType.LTO1: - density = "LTO Ultrium"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTO2: - { - switch(descriptor.Density) - { - case DensityType.LTO2: - density = "LTO Ultrium-2"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.DDS3: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "MLR1-26GB"; - - break; - case DensityType.DDS3: - density = "DDS-3"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.DDS4: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "DC-9200"; - - break; - case DensityType.DDS4: - density = "DDS-4"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.DAT72: - { - switch(descriptor.Density) - { - case DensityType.DAT72: - density = "DAT-72"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTO3: - case MediumTypes.LTO3WORM: - { - switch(descriptor.Density) - { - case DensityType.LTO3: - density = "LTO Ultrium-3"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.DDSCleaning: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "DDS cleaning cartridge"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTO4: - case MediumTypes.LTO4WORM: - { - switch(descriptor.Density) - { - case DensityType.LTO4: - density = "LTO Ultrium-4"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTO5: - case MediumTypes.LTO5WORM: - { - switch(descriptor.Density) - { - case DensityType.LTO5: - density = "LTO Ultrium-5"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTO6: - case MediumTypes.LTO6WORM: - { - switch(descriptor.Density) - { - case DensityType.LTO6: - density = "LTO Ultrium-6"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTO7: - case MediumTypes.LTO7WORM: - { - switch(descriptor.Density) - { - case DensityType.LTO7: - density = "LTO Ultrium-7"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.LTOCD: - { - switch(descriptor.Density) - { - case DensityType.LTO2: - density = "LTO Ultrium-2 in CD emulation mode"; - - break; - case DensityType.LTO3: - density = "LTO Ultrium-3 in CD emulation mode"; - - break; - case DensityType.LTO4: - density = "LTO Ultrium-4 in CD emulation mode"; - - break; - case DensityType.LTO5: - density = "LTO Ultrium-5 in CD emulation mode"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape15m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - case DensityType.IBM3590: - density = "IBM 3590"; - - break; - case DensityType.IBM3590E: - density = "IBM 3590E"; - - break; - case DensityType.VXA1: - density = "VXA-1"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape28m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - case DensityType.CT1: - density = "CompactTape I"; - - break; - case DensityType.CT2: - density = "CompactTape II"; - - break; - case DensityType.IBM3590: - density = "IBM 3590 extended"; - - break; - case DensityType.IBM3590E: - density = "IBM 3590E extended"; - - break; - case DensityType.VXA2: - density = "VXA-2"; - - break; - case DensityType.VXA3: - density = "VXA-3"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape54m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - case DensityType.DLT3_42k: - density = "DLTtape III at 42500 bpi"; - - break; - case DensityType.DLT3_56t: - density = "DLTtape III with 56 tracks"; - - break; - case DensityType.DLT3_62k: - case DensityType.DLT3_62kAlt: - density = "DLTtape III at 62500 bpi"; - - break; - case DensityType.DLT3c: - density = "DLTtape III compressed"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape80m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - case DensityType.DLT3_62k: - case DensityType.DLT3_62kAlt: - density = "DLTtape IIIxt"; - - break; - case DensityType.DLT3c: - density = "DLTtape IIIxt compressed"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape106m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - case DensityType.DLT4: - case DensityType.DLT4Alt: - density = "DLTtape IV"; - - break; - case DensityType.DLT4_123k: - case DensityType.DLT4_123kAlt: - density = "DLTtape IV at 123090 bpi"; - - break; - case DensityType.DLT4_98k: - density = "DLTtape IV at 98250 bpi"; - - break; - case DensityType.Travan5: - density = "Travan 5"; - - break; - case DensityType.DLT4c: - density = "DLTtape IV compressed"; - - break; - case DensityType.DLT4_85k: - density = "DLTtape IV at 85937 bpi"; - - break; - case DensityType.DLT4c_85k: - density = "DLTtape IV at 85937 bpi compressed"; - - break; - case DensityType.DLT4c_123k: - density = "DLTtape IV at 123090 bpi compressed"; - - break; - case DensityType.DLT4c_98k: - density = "DLTtape IV at 98250 bpi compressed"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape106mXL: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - case DensityType.SDLT1_133k: - case DensityType.SDLT1_133kAlt: - density = "Super DLTtape I at 133000 bpi"; - - break; - case DensityType.SDLT1: - //case DensityType.SDLT1Alt: - density = "Super DLTtape I"; - - break; - case DensityType.SDLT1c: - density = "Super DLTtape I compressed"; - - break; - /*case DensityType.SDLT1_133kAlt: - density = "Super DLTtape I at 133000 bpi compressed"; - break;*/ - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SDLT2: - { - switch(descriptor.Density) - { - case DensityType.SDLT2: - density = "Super DLTtape II"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.VStapeI: - { - switch(descriptor.Density) - { - case DensityType.VStape1: - case DensityType.VStape1Alt: - density = "VStape I"; - - break; - case DensityType.VStape1c: - density = "VStape I compressed"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.DLTtapeS4: - { - switch(descriptor.Density) - { - case DensityType.DLTS4: - density = "DLTtape S4"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape22m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape40m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape76m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape112m: - { - switch(descriptor.Density) - { - case DensityType.Ex8200: - density = "EXB-8200"; - - break; - case DensityType.Ex8200c: - density = "EXB-8200 compressed"; - - break; - case DensityType.Ex8500: - density = "EXB-8500"; - - break; - case DensityType.Ex8500c: - density = "EXB-8500 compressed"; - - break; - case DensityType.Mammoth: - density = "Mammoth"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.Exatape22mAME: - case MediumTypes.Exatape170m: - case MediumTypes.Exatape125m: - case MediumTypes.Exatape45m: - case MediumTypes.Exatape225m: - case MediumTypes.Exatape150m: - case MediumTypes.Exatape75m: - { - switch(descriptor.Density) - { - case DensityType.Mammoth: - density = "Mammoth"; - - break; - case DensityType.Mammoth2: - density = "Mammoth-2"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.DC2900SL: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "DC-2900SL"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.DC9250: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "DC-9250"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLR32: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLR-32"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.MLR1SL: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "MRL1-26GBSL"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape50: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-50"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape50SL: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-50 SL"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLR32SL: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLR-32 SL"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLR5: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLR-5"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLR5SL: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLR-5 SL"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape7: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-7"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape7SL: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-7 SL"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape24: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-24"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape24SL: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-24 SL"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape140: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-140"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape40: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-40"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape60: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-60 or SLRtape-75"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLRtape100: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLRtape-100"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - case MediumTypes.SLR40_60_100: - { - switch(descriptor.Density) - { - case DensityType.Default: - density = "SLR40, SLR60 or SLR100"; - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - } - - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - - break; - } - - if(density != "") - if(descriptor.Blocks == 0) - if(descriptor.BlockLength == 0) - sb. - AppendFormat("\tAll remaining blocks conform to {0} and have a variable length", - density).AppendLine(); - else - sb.AppendFormat("\tAll remaining blocks conform to {0} and are {1} bytes each", - density, descriptor.BlockLength).AppendLine(); - else if(descriptor.BlockLength == 0) - sb.AppendFormat("\t{0} blocks conform to {1} and have a variable length", - descriptor.Blocks, density).AppendLine(); - else - sb.AppendFormat("\t{0} blocks conform to {1} and are {2} bytes each", - descriptor.Blocks, density, descriptor.BlockLength).AppendLine(); - else if(descriptor.Blocks == 0) - if(descriptor.BlockLength == 0) - sb.AppendFormat("\tAll remaining blocks have a variable length").AppendLine(); - else - sb.AppendFormat("\tAll remaining blocks are {0} bytes each", - descriptor.BlockLength).AppendLine(); - else if(descriptor.BlockLength == 0) - sb.AppendFormat("\t{0} blocks have a variable length", descriptor.Blocks).AppendLine(); - else - sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, - descriptor.BlockLength).AppendLine(); - } - - break; - } - #endregion Sequential access device mode header - - #region Printer device mode header - case PeripheralDeviceTypes.PrinterDevice: - { - switch(header.Value.BufferedMode) - { - case 0: - sb.AppendLine("\tDevice prints directly"); - - break; - case 1: - sb.AppendLine("\tDevice uses a print cache"); - - break; - default: - sb.AppendFormat("\tUnknown buffered mode code 0x{0:X2}", header.Value.BufferedMode). - AppendLine(); - - break; - } - - break; - } - #endregion Printer device mode header - - #region Optical device mode header - case PeripheralDeviceTypes.OpticalDevice: - { - if(header.Value.MediumType != MediumTypes.Default) - { - sb.Append("\tMedium is "); - - switch(header.Value.MediumType) - { - case MediumTypes.ReadOnly: - sb.AppendLine("a Read-only optical"); + case DensityType.Default: break; + case DensityType.Flux7958: + density = "7958 flux transitions per radian"; break; - case MediumTypes.WORM: - sb.AppendLine("a Write-once Read-many optical"); + case DensityType.Flux13262: + density = "13262 flux transitions per radian"; break; - case MediumTypes.Erasable: - sb.AppendLine("a Erasable optical"); - - break; - case MediumTypes.RO_WORM: - sb.AppendLine("a combination of read-only and write-once optical"); - - break; - case MediumTypes.RO_RW: - sb.AppendLine("a combination of read-only and erasable optical"); - - break; - case MediumTypes.WORM_RW: - sb.AppendLine("a combination of write-once and erasable optical"); - - break; - case MediumTypes.DOW: - sb.AppendLine("a direct-overwrite optical"); + case DensityType.Flux15916: + density = "15916 flux transitions per radian"; break; default: - sb.AppendFormat("an unknown medium type 0x{0:X2}", (byte)header.Value.MediumType). - AppendLine(); + density = $"with unknown density code 0x{(byte)descriptor.Density:X2}"; break; } + + if(density != "") + if(descriptor.Blocks == 0) + sb.AppendFormat("\tAll remaining blocks have {0} and are {1} bytes each", density, + descriptor.BlockLength).AppendLine(); + else + sb.AppendFormat("\t{0} blocks have {1} and are {2} bytes each", descriptor.Blocks, + density, descriptor.BlockLength).AppendLine(); + else if(descriptor.Blocks == 0) + sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength). + AppendLine(); + else + sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, + descriptor.BlockLength).AppendLine(); } - if(header.Value.WriteProtected) - sb.AppendLine("\tMedium is write protected"); + break; + } + #endregion Direct access device mode header - if(header.Value.EBC) - sb.AppendLine("\tBlank checking during write is enabled"); + #region Sequential access device mode header + case PeripheralDeviceTypes.SequentialAccess: + { + switch(header.Value.BufferedMode) + { + case 0: + sb.AppendLine("\tDevice writes directly to media"); - if(header.Value.DPOFUA) - sb.AppendLine("\tDrive supports DPO and FUA bits"); + break; + case 1: + sb.AppendLine("\tDevice uses a write cache"); - if(header.Value.BlockDescriptors != null) - foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + break; + case 2: + sb.AppendLine("\tDevice uses a write cache but doesn't return until cache is flushed"); + + break; + default: + sb.AppendFormat("\tUnknown buffered mode code 0x{0:X2}", header.Value.BufferedMode). + AppendLine(); + + break; + } + + if(header.Value.Speed == 0) + sb.AppendLine("\tDevice uses default speed"); + else + sb.AppendFormat("\tDevice uses speed {0}", header.Value.Speed).AppendLine(); + + if(header.Value.WriteProtected) + sb.AppendLine("\tMedium is write protected"); + + string medium; + + switch(header.Value.MediumType) + { + case MediumTypes.Default: + medium = "undefined"; + + break; + case MediumTypes.Tape12: + medium = "6,3 mm tape with 12 tracks at 394 ftpmm or DC-9250"; + + break; + case MediumTypes.Tape24: + medium = "6,3 mm tape with 24 tracks at 394 ftpmm or MLR1-26GBSL"; + + break; + case MediumTypes.LTOWORM: + medium = "LTO Ultrium WORM or cleaning cartridge"; + + break; + case MediumTypes.LTO: + medium = "LTO Ultrium"; + + break; + case MediumTypes.LTO2: + medium = "LTO Ultrium-2"; + + break; + case MediumTypes.DC2900SL: + medium = "DC-2900SL"; + + break; + case MediumTypes.MLR1: + medium = "MLR1-26GB or DDS-3"; + + break; + case MediumTypes.DC9200: + medium = "DC-9200 or DDS-4"; + + break; + case MediumTypes.DAT72: + medium = "DAT-72"; + + break; + case MediumTypes.LTO3: + medium = "LTO Ultrium-3"; + + break; + case MediumTypes.LTO3WORM: + medium = "LTO Ultrium-3 WORM"; + + break; + case MediumTypes.DDSCleaning: + medium = "DDS cleaning cartridge"; + + break; + case MediumTypes.SLR32: + medium = "SLR-32"; + + break; + case MediumTypes.SLRtape50: + medium = "SLRtape-50"; + + break; + case MediumTypes.LTO4: + medium = "LTO Ultrium-4"; + + break; + case MediumTypes.LTO4WORM: + medium = "LTO Ultrium-4 WORM"; + + break; + case MediumTypes.SLRtape50SL: + medium = "SLRtape-50 SL"; + + break; + case MediumTypes.SLR32SL: + medium = "SLR-32SL"; + + break; + case MediumTypes.SLR5: + medium = "SLR-5"; + + break; + case MediumTypes.SLR5SL: + medium = "SLR-5SL"; + + break; + case MediumTypes.LTO5: + medium = "LTO Ultrium-5"; + + break; + case MediumTypes.LTO5WORM: + medium = "LTO Ultrium-5 WORM"; + + break; + case MediumTypes.SLRtape7: + medium = "SLRtape-7"; + + break; + case MediumTypes.SLRtape7SL: + medium = "SLRtape-7 SL"; + + break; + case MediumTypes.SLRtape24: + medium = "SLRtape-24"; + + break; + case MediumTypes.SLRtape24SL: + medium = "SLRtape-24 SL"; + + break; + case MediumTypes.LTO6: + medium = "LTO Ultrium-6"; + + break; + case MediumTypes.LTO6WORM: + medium = "LTO Ultrium-6 WORM"; + + break; + case MediumTypes.SLRtape140: + medium = "SLRtape-140"; + + break; + case MediumTypes.SLRtape40: + medium = "SLRtape-40"; + + break; + case MediumTypes.SLRtape60: + medium = "SLRtape-60 or SLRtape-75"; + + break; + case MediumTypes.SLRtape100: + medium = "SLRtape-100"; + + break; + case MediumTypes.SLR40_60_100: + medium = "SLR-40, SLR-60 or SLR-100"; + + break; + case MediumTypes.LTO7: + medium = "LTO Ultrium-7"; + + break; + case MediumTypes.LTO7WORM: + medium = "LTO Ultrium-7 WORM"; + + break; + case MediumTypes.LTOCD: + medium = "LTO Ultrium"; + + break; + case MediumTypes.Exatape15m: + medium = "Exatape 15m, IBM MagStar or VXA"; + + break; + case MediumTypes.CT1: + medium = "CompactTape I, Exatape 28m, CompactTape II, VXA-2 or VXA-3"; + + break; + case MediumTypes.Exatape54m: + medium = "Exatape 54m or DLTtape III"; + + break; + case MediumTypes.Exatape80m: + medium = "Exatape 80m or DLTtape IIIxt"; + + break; + case MediumTypes.Exatape106m: + medium = "Exatape 106m, DLTtape IV or Travan 5"; + + break; + case MediumTypes.Exatape106mXL: + medium = "Exatape 160m XL or Super DLTtape I"; + + break; + case MediumTypes.SDLT2: + medium = "Super DLTtape II"; + + break; + case MediumTypes.VStapeI: + medium = "VStape I"; + + break; + case MediumTypes.DLTtapeS4: + medium = "DLTtape S4"; + + break; + case MediumTypes.Travan7: + medium = "Travan 7"; + + break; + case MediumTypes.Exatape22m: + medium = "Exatape 22m"; + + break; + case MediumTypes.Exatape40m: + medium = "Exatape 40m"; + + break; + case MediumTypes.Exatape76m: + medium = "Exatape 76m"; + + break; + case MediumTypes.Exatape112m: + medium = "Exatape 112m"; + + break; + case MediumTypes.Exatape22mAME: + medium = "Exatape 22m AME"; + + break; + case MediumTypes.Exatape170m: + medium = "Exatape 170m"; + + break; + case MediumTypes.Exatape125m: + medium = "Exatape 125m"; + + break; + case MediumTypes.Exatape45m: + medium = "Exatape 45m"; + + break; + case MediumTypes.Exatape225m: + medium = "Exatape 225m"; + + break; + case MediumTypes.Exatape150m: + medium = "Exatape 150m"; + + break; + case MediumTypes.Exatape75m: + medium = "Exatape 75m"; + + break; + default: + medium = $"unknown medium type 0x{(byte)header.Value.MediumType:X2}"; + + break; + } + + sb.AppendFormat("\tMedium is {0}", medium).AppendLine(); + + if(header.Value.BlockDescriptors != null) + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + string density = ""; + + switch(header.Value.MediumType) { - string density = ""; - - switch(descriptor.Density) + case MediumTypes.Default: { - case DensityType.Default: break; - case DensityType.ISO10090: - density = - "ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks"; + switch(descriptor.Density) + { + case DensityType.Default: break; + case DensityType.ECMA62: + density = + "ECMA-62 & ANSI X3.22-1983: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm"; - break; - case DensityType.D581: - density = "89 mm Read/Write double-sided optical disc with 12500 tracks"; + break; + case DensityType.ECMA62_Phase: + density = + "ECMA-62 & ANSI X3.39-1986: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm"; - break; - case DensityType.X3_212: - density = - "ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks"; + break; + case DensityType.ECMA62_GCR: + density = + "ECMA-62 & ANSI X3.54-1986: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR"; - break; - case DensityType.X3_191: - density = - "ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks"; + break; + case DensityType.ECMA79: + density = + "ECMA-79 & ANSI X3.116-1986: 6,30 mm Magnetic Tape Cartridge, 252 ftpmm, MFM"; - break; - case DensityType.X3_214: - density = - "ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks"; + break; + case DensityType.IBM3480: + density = + "Draft ECMA & ANSI X3B5/87-099: 12,7 mm 18-Track Magnetic Tape Cartridge, 1944 ftpmm, IFM, GCR (IBM 3480, 3490, 3490E)"; - break; - case DensityType.X3_211: - density = - "ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks"; + break; + case DensityType.ECMA46: + density = + "ECMA-46 & ANSI X3.56-1986: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm"; - break; - case DensityType.D407: - density = "200 mm optical disc"; + break; + case DensityType.ECMA98: + density = "ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZI, 394 ftpmm"; - break; - case DensityType.ISO13614: - density = "ISO/IEC 13614: 300 mm double-sided optical disc"; + break; + case DensityType.X3_136: + density = + "ANXI X3.136-1986: 6,3 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24)"; - break; - case DensityType.X3_200: - density = "ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks"; + break; + case DensityType.X3_157: + density = + "ANXI X3.157-1987: 12,7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding"; - break; - default: - density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + break; + case DensityType.X3_158: + density = + "ANXI X3.158-1987: 3,81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR"; - break; + break; + case DensityType.X3B5_86: + density = + "ANXI X3B5/86-199: 12,7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM"; + + break; + case DensityType.HiTC1: + density = "HI-TC1: 12,7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR"; + + break; + case DensityType.HiTC2: + density = "HI-TC2: 12,7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR"; + + break; + case DensityType.QIC120: + density = "QIC-120: 6,3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR"; + + break; + case DensityType.QIC150: + density = "QIC-150: 6,3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR"; + + break; + case DensityType.QIC320: + density = "QIC-320: 6,3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR"; + + break; + case DensityType.QIC1350: + density = + "QIC-1350: 6,3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL"; + + break; + case DensityType.X3B5_88: + density = + "ANXI X3B5/88-185A: 3,81 mm Magnetic Tape Cassette, 2400 bpmm, DDS"; + + break; + case DensityType.X3_202: + density = "ANXI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL"; + + break; + case DensityType.ECMA_TC17: + density = "ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL"; + + break; + case DensityType.X3_193: + density = + "ANXI X3.193-1990: 12,7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM"; + + break; + case DensityType.X3B5_91: + density = + "ANXI X3B5/97-174: 12,7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM"; + + break; + case DensityType.QIC11: + density = "QIC-11"; + + break; + case DensityType.IBM3490E: + density = "IBM 3490E"; + + break; + case DensityType.LTO1: + //case DensityType.SAIT1: + density = "LTO Ultrium or Super AIT-1"; + + break; + case DensityType.LTO2Old: + density = "LTO Ultrium-2"; + + break; + case DensityType.LTO2: + //case DensityType.T9840: + density = "LTO Ultrium-2 or T9840"; + + break; + case DensityType.T9940: + density = "T9940"; + + break; + case DensityType.LTO3: + //case DensityType.T9940: + density = "LTO Ultrium-3 or T9940"; + + break; + case DensityType.T9840C: + density = "T9840C"; + + break; + case DensityType.LTO4: + //case DensityType.T9840D: + density = "LTO Ultrium-4 or T9840D"; + + break; + case DensityType.T10000A: + density = "T10000A"; + + break; + case DensityType.T10000B: + density = "T10000B"; + + break; + case DensityType.T10000C: + density = "T10000C"; + + break; + case DensityType.T10000D: + density = "T10000D"; + + break; + case DensityType.AIT1: + density = "AIT-1"; + + break; + case DensityType.AIT2: + density = "AIT-2"; + + break; + case DensityType.AIT3: + density = "AIT-3"; + + break; + case DensityType.DDS2: + density = "DDS-2"; + + break; + case DensityType.DDS3: + density = "DDS-3"; + + break; + case DensityType.DDS4: + density = "DDS-4"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } } - if(density != "") - if(descriptor.Blocks == 0) - if(descriptor.BlockLength == 0) - sb.AppendFormat("\tAll remaining blocks are {0} and have a variable length", - density).AppendLine(); - else - sb.AppendFormat("\tAll remaining blocks are {0} and are {1} bytes each", - density, descriptor.BlockLength).AppendLine(); - else if(descriptor.BlockLength == 0) - sb.AppendFormat("\t{0} blocks are {1} and have a variable length", - descriptor.Blocks, density).AppendLine(); - else - sb.AppendFormat("\t{0} blocks are {1} and are {2} bytes each", descriptor.Blocks, - density, descriptor.BlockLength).AppendLine(); - else if(descriptor.Blocks == 0) - if(descriptor.BlockLength == 0) - sb.AppendFormat("\tAll remaining blocks have a variable length").AppendLine(); - else - sb.AppendFormat("\tAll remaining blocks are {0} bytes each", - descriptor.BlockLength).AppendLine(); - else if(descriptor.BlockLength == 0) - sb.AppendFormat("\t{0} blocks have a variable length", descriptor.Blocks).AppendLine(); - else - sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, - descriptor.BlockLength).AppendLine(); + break; + case MediumTypes.LTOWORM: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "LTO Ultrium cleaning cartridge"; + + break; + case DensityType.LTO3: + density = "LTO Ultrium-3 WORM"; + + break; + case DensityType.LTO4: + density = "LTO Ultrium-4 WORM"; + + break; + case DensityType.LTO5: + density = "LTO Ultrium-5 WORM"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTO: + { + switch(descriptor.Density) + { + case DensityType.LTO1: + density = "LTO Ultrium"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTO2: + { + switch(descriptor.Density) + { + case DensityType.LTO2: + density = "LTO Ultrium-2"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.DDS3: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "MLR1-26GB"; + + break; + case DensityType.DDS3: + density = "DDS-3"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.DDS4: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "DC-9200"; + + break; + case DensityType.DDS4: + density = "DDS-4"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.DAT72: + { + switch(descriptor.Density) + { + case DensityType.DAT72: + density = "DAT-72"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTO3: + case MediumTypes.LTO3WORM: + { + switch(descriptor.Density) + { + case DensityType.LTO3: + density = "LTO Ultrium-3"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.DDSCleaning: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "DDS cleaning cartridge"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTO4: + case MediumTypes.LTO4WORM: + { + switch(descriptor.Density) + { + case DensityType.LTO4: + density = "LTO Ultrium-4"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTO5: + case MediumTypes.LTO5WORM: + { + switch(descriptor.Density) + { + case DensityType.LTO5: + density = "LTO Ultrium-5"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTO6: + case MediumTypes.LTO6WORM: + { + switch(descriptor.Density) + { + case DensityType.LTO6: + density = "LTO Ultrium-6"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTO7: + case MediumTypes.LTO7WORM: + { + switch(descriptor.Density) + { + case DensityType.LTO7: + density = "LTO Ultrium-7"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.LTOCD: + { + switch(descriptor.Density) + { + case DensityType.LTO2: + density = "LTO Ultrium-2 in CD emulation mode"; + + break; + case DensityType.LTO3: + density = "LTO Ultrium-3 in CD emulation mode"; + + break; + case DensityType.LTO4: + density = "LTO Ultrium-4 in CD emulation mode"; + + break; + case DensityType.LTO5: + density = "LTO Ultrium-5 in CD emulation mode"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape15m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + case DensityType.IBM3590: + density = "IBM 3590"; + + break; + case DensityType.IBM3590E: + density = "IBM 3590E"; + + break; + case DensityType.VXA1: + density = "VXA-1"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape28m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + case DensityType.CT1: + density = "CompactTape I"; + + break; + case DensityType.CT2: + density = "CompactTape II"; + + break; + case DensityType.IBM3590: + density = "IBM 3590 extended"; + + break; + case DensityType.IBM3590E: + density = "IBM 3590E extended"; + + break; + case DensityType.VXA2: + density = "VXA-2"; + + break; + case DensityType.VXA3: + density = "VXA-3"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape54m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + case DensityType.DLT3_42k: + density = "DLTtape III at 42500 bpi"; + + break; + case DensityType.DLT3_56t: + density = "DLTtape III with 56 tracks"; + + break; + case DensityType.DLT3_62k: + case DensityType.DLT3_62kAlt: + density = "DLTtape III at 62500 bpi"; + + break; + case DensityType.DLT3c: + density = "DLTtape III compressed"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape80m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + case DensityType.DLT3_62k: + case DensityType.DLT3_62kAlt: + density = "DLTtape IIIxt"; + + break; + case DensityType.DLT3c: + density = "DLTtape IIIxt compressed"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape106m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + case DensityType.DLT4: + case DensityType.DLT4Alt: + density = "DLTtape IV"; + + break; + case DensityType.DLT4_123k: + case DensityType.DLT4_123kAlt: + density = "DLTtape IV at 123090 bpi"; + + break; + case DensityType.DLT4_98k: + density = "DLTtape IV at 98250 bpi"; + + break; + case DensityType.Travan5: + density = "Travan 5"; + + break; + case DensityType.DLT4c: + density = "DLTtape IV compressed"; + + break; + case DensityType.DLT4_85k: + density = "DLTtape IV at 85937 bpi"; + + break; + case DensityType.DLT4c_85k: + density = "DLTtape IV at 85937 bpi compressed"; + + break; + case DensityType.DLT4c_123k: + density = "DLTtape IV at 123090 bpi compressed"; + + break; + case DensityType.DLT4c_98k: + density = "DLTtape IV at 98250 bpi compressed"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape106mXL: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + case DensityType.SDLT1_133k: + case DensityType.SDLT1_133kAlt: + density = "Super DLTtape I at 133000 bpi"; + + break; + case DensityType.SDLT1: + //case DensityType.SDLT1Alt: + density = "Super DLTtape I"; + + break; + case DensityType.SDLT1c: + density = "Super DLTtape I compressed"; + + break; + /*case DensityType.SDLT1_133kAlt: + density = "Super DLTtape I at 133000 bpi compressed"; + break;*/ + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SDLT2: + { + switch(descriptor.Density) + { + case DensityType.SDLT2: + density = "Super DLTtape II"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.VStapeI: + { + switch(descriptor.Density) + { + case DensityType.VStape1: + case DensityType.VStape1Alt: + density = "VStape I"; + + break; + case DensityType.VStape1c: + density = "VStape I compressed"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.DLTtapeS4: + { + switch(descriptor.Density) + { + case DensityType.DLTS4: + density = "DLTtape S4"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape22m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape40m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape76m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape112m: + { + switch(descriptor.Density) + { + case DensityType.Ex8200: + density = "EXB-8200"; + + break; + case DensityType.Ex8200c: + density = "EXB-8200 compressed"; + + break; + case DensityType.Ex8500: + density = "EXB-8500"; + + break; + case DensityType.Ex8500c: + density = "EXB-8500 compressed"; + + break; + case DensityType.Mammoth: + density = "Mammoth"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.Exatape22mAME: + case MediumTypes.Exatape170m: + case MediumTypes.Exatape125m: + case MediumTypes.Exatape45m: + case MediumTypes.Exatape225m: + case MediumTypes.Exatape150m: + case MediumTypes.Exatape75m: + { + switch(descriptor.Density) + { + case DensityType.Mammoth: + density = "Mammoth"; + + break; + case DensityType.Mammoth2: + density = "Mammoth-2"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.DC2900SL: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "DC-2900SL"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.DC9250: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "DC-9250"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLR32: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLR-32"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.MLR1SL: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "MRL1-26GBSL"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape50: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-50"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape50SL: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-50 SL"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLR32SL: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLR-32 SL"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLR5: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLR-5"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLR5SL: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLR-5 SL"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape7: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-7"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape7SL: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-7 SL"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape24: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-24"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape24SL: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-24 SL"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape140: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-140"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape40: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-40"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape60: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-60 or SLRtape-75"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLRtape100: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLRtape-100"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + case MediumTypes.SLR40_60_100: + { + switch(descriptor.Density) + { + case DensityType.Default: + density = "SLR40, SLR60 or SLR100"; + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + } + + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; } - break; - } - #endregion Optical device mode header + if(density != "") + if(descriptor.Blocks == 0) + if(descriptor.BlockLength == 0) + sb. + AppendFormat("\tAll remaining blocks conform to {0} and have a variable length", + density).AppendLine(); + else + sb.AppendFormat("\tAll remaining blocks conform to {0} and are {1} bytes each", + density, descriptor.BlockLength).AppendLine(); + else if(descriptor.BlockLength == 0) + sb.AppendFormat("\t{0} blocks conform to {1} and have a variable length", + descriptor.Blocks, density).AppendLine(); + else + sb.AppendFormat("\t{0} blocks conform to {1} and are {2} bytes each", + descriptor.Blocks, density, descriptor.BlockLength).AppendLine(); + else if(descriptor.Blocks == 0) + if(descriptor.BlockLength == 0) + sb.AppendFormat("\tAll remaining blocks have a variable length").AppendLine(); + else + sb.AppendFormat("\tAll remaining blocks are {0} bytes each", + descriptor.BlockLength).AppendLine(); + else if(descriptor.BlockLength == 0) + sb.AppendFormat("\t{0} blocks have a variable length", descriptor.Blocks).AppendLine(); + else + sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, + descriptor.BlockLength).AppendLine(); + } - #region Multimedia device mode header - case PeripheralDeviceTypes.MultiMediaDevice: + break; + } + #endregion Sequential access device mode header + + #region Printer device mode header + case PeripheralDeviceTypes.PrinterDevice: + { + switch(header.Value.BufferedMode) + { + case 0: + sb.AppendLine("\tDevice prints directly"); + + break; + case 1: + sb.AppendLine("\tDevice uses a print cache"); + + break; + default: + sb.AppendFormat("\tUnknown buffered mode code 0x{0:X2}", header.Value.BufferedMode). + AppendLine(); + + break; + } + + break; + } + #endregion Printer device mode header + + #region Optical device mode header + case PeripheralDeviceTypes.OpticalDevice: + { + if(header.Value.MediumType != MediumTypes.Default) { sb.Append("\tMedium is "); switch(header.Value.MediumType) { - case MediumTypes.CDROM: - sb.AppendLine("120 mm CD-ROM"); + case MediumTypes.ReadOnly: + sb.AppendLine("a Read-only optical"); break; - case MediumTypes.CDDA: - sb.AppendLine("120 mm Compact Disc Digital Audio"); + case MediumTypes.WORM: + sb.AppendLine("a Write-once Read-many optical"); break; - case MediumTypes.MixedCD: - sb.AppendLine("120 mm Compact Disc with data and audio"); + case MediumTypes.Erasable: + sb.AppendLine("a Erasable optical"); break; - case MediumTypes.CDROM_80: - sb.AppendLine("80 mm CD-ROM"); + case MediumTypes.RO_WORM: + sb.AppendLine("a combination of read-only and write-once optical"); break; - case MediumTypes.CDDA_80: - sb.AppendLine("80 mm Compact Disc Digital Audio"); + case MediumTypes.RO_RW: + sb.AppendLine("a combination of read-only and erasable optical"); break; - case MediumTypes.MixedCD_80: - sb.AppendLine("80 mm Compact Disc with data and audio"); + case MediumTypes.WORM_RW: + sb.AppendLine("a combination of write-once and erasable optical"); break; - case MediumTypes.Unknown_CD: - sb.AppendLine("Unknown medium type"); - - break; - case MediumTypes.HybridCD: - sb.AppendLine("120 mm Hybrid disc (Photo CD)"); - - break; - case MediumTypes.Unknown_CDR: - sb.AppendLine("Unknown size CD-R"); - - break; - case MediumTypes.CDR: - sb.AppendLine("120 mm CD-R with data only"); - - break; - case MediumTypes.CDR_DA: - sb.AppendLine("120 mm CD-R with audio only"); - - break; - case MediumTypes.CDR_Mixed: - sb.AppendLine("120 mm CD-R with data and audio"); - - break; - case MediumTypes.HybridCDR: - sb.AppendLine("120 mm Hybrid CD-R (Photo CD)"); - - break; - case MediumTypes.CDR_80: - sb.AppendLine("80 mm CD-R with data only"); - - break; - case MediumTypes.CDR_DA_80: - sb.AppendLine("80 mm CD-R with audio only"); - - break; - case MediumTypes.CDR_Mixed_80: - sb.AppendLine("80 mm CD-R with data and audio"); - - break; - case MediumTypes.HybridCDR_80: - sb.AppendLine("80 mm Hybrid CD-R (Photo CD)"); - - break; - case MediumTypes.Unknown_CDRW: - sb.AppendLine("Unknown size CD-RW"); - - break; - case MediumTypes.CDRW: - sb.AppendLine("120 mm CD-RW with data only"); - - break; - case MediumTypes.CDRW_DA: - sb.AppendLine("120 mm CD-RW with audio only"); - - break; - case MediumTypes.CDRW_Mixed: - sb.AppendLine("120 mm CD-RW with data and audio"); - - break; - case MediumTypes.HybridCDRW: - sb.AppendLine("120 mm Hybrid CD-RW (Photo CD)"); - - break; - case MediumTypes.CDRW_80: - sb.AppendLine("80 mm CD-RW with data only"); - - break; - case MediumTypes.CDRW_DA_80: - sb.AppendLine("80 mm CD-RW with audio only"); - - break; - case MediumTypes.CDRW_Mixed_80: - sb.AppendLine("80 mm CD-RW with data and audio"); - - break; - case MediumTypes.HybridCDRW_80: - sb.AppendLine("80 mm Hybrid CD-RW (Photo CD)"); - - break; - case MediumTypes.Unknown_HD: - sb.AppendLine("Unknown size HD disc"); - - break; - case MediumTypes.HD: - sb.AppendLine("120 mm HD disc"); - - break; - case MediumTypes.HD_80: - sb.AppendLine("80 mm HD disc"); - - break; - case MediumTypes.NoDisc: - sb.AppendLine("No disc inserted, tray closed or caddy inserted"); - - break; - case MediumTypes.TrayOpen: - sb.AppendLine("Tray open or no caddy inserted"); - - break; - case MediumTypes.MediumError: - sb.AppendLine("Tray closed or caddy inserted but medium error"); - - break; - case MediumTypes.UnknownBlockDevice: - sb.AppendLine("Unknown block device"); - - break; - case MediumTypes.ReadOnlyBlockDevice: - sb.AppendLine("Read-only block device"); - - break; - case MediumTypes.ReadWriteBlockDevice: - sb.AppendLine("Read/Write block device"); - - break; - case MediumTypes.LTOCD: - sb.AppendLine("LTO in CD-ROM emulation mode"); + case MediumTypes.DOW: + sb.AppendLine("a direct-overwrite optical"); break; default: - sb.AppendFormat("Unknown medium type 0x{0:X2}", (byte)header.Value.MediumType).AppendLine(); + sb.AppendFormat("an unknown medium type 0x{0:X2}", (byte)header.Value.MediumType). + AppendLine(); break; } + } - if(header.Value.WriteProtected) - sb.AppendLine("\tMedium is write protected"); + if(header.Value.WriteProtected) + sb.AppendLine("\tMedium is write protected"); - if(header.Value.DPOFUA) - sb.AppendLine("\tDrive supports DPO and FUA bits"); + if(header.Value.EBC) + sb.AppendLine("\tBlank checking during write is enabled"); - if(header.Value.BlockDescriptors != null) - foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + if(header.Value.DPOFUA) + sb.AppendLine("\tDrive supports DPO and FUA bits"); + + if(header.Value.BlockDescriptors != null) + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + string density = ""; + + switch(descriptor.Density) { - string density = ""; + case DensityType.Default: break; + case DensityType.ISO10090: + density = + "ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks"; - switch(descriptor.Density) - { - case DensityType.Default: break; - case DensityType.User: - density = "user data only"; + break; + case DensityType.D581: + density = "89 mm Read/Write double-sided optical disc with 12500 tracks"; - break; - case DensityType.UserAuxiliary: - density = "user data plus auxiliary data"; + break; + case DensityType.X3_212: + density = + "ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks"; - break; - case DensityType.UserAuxiliaryTag: - density = "4-byte tag, user data plus auxiliary data"; + break; + case DensityType.X3_191: + density = + "ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks"; - break; - case DensityType.Audio: - density = "audio information only"; + break; + case DensityType.X3_214: + density = + "ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks"; - break; - case DensityType.LTO2: - density = "LTO Ultrium-2"; + break; + case DensityType.X3_211: + density = + "ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks"; - break; - case DensityType.LTO3: - density = "LTO Ultrium-3"; + break; + case DensityType.D407: + density = "200 mm optical disc"; - break; - case DensityType.LTO4: - density = "LTO Ultrium-4"; + break; + case DensityType.ISO13614: + density = "ISO/IEC 13614: 300 mm double-sided optical disc"; - break; - case DensityType.LTO5: - density = "LTO Ultrium-5"; + break; + case DensityType.X3_200: + density = "ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks"; - break; - default: - density = $"with unknown density code 0x{(byte)descriptor.Density:X2}"; + break; + default: + density = $"unknown density code 0x{(byte)descriptor.Density:X2}"; - break; - } - - if(density != "") - if(descriptor.Blocks == 0) - sb.AppendFormat("\tAll remaining blocks have {0} and are {1} bytes each", density, - descriptor.BlockLength).AppendLine(); - else - sb.AppendFormat("\t{0} blocks have {1} and are {2} bytes each", descriptor.Blocks, - density, descriptor.BlockLength).AppendLine(); - else if(descriptor.Blocks == 0) - sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength). - AppendLine(); - else - sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, - descriptor.BlockLength).AppendLine(); + break; } - break; - } - #endregion Multimedia device mode header - } + if(density != "") + if(descriptor.Blocks == 0) + if(descriptor.BlockLength == 0) + sb.AppendFormat("\tAll remaining blocks are {0} and have a variable length", + density).AppendLine(); + else + sb.AppendFormat("\tAll remaining blocks are {0} and are {1} bytes each", + density, descriptor.BlockLength).AppendLine(); + else if(descriptor.BlockLength == 0) + sb.AppendFormat("\t{0} blocks are {1} and have a variable length", + descriptor.Blocks, density).AppendLine(); + else + sb.AppendFormat("\t{0} blocks are {1} and are {2} bytes each", descriptor.Blocks, + density, descriptor.BlockLength).AppendLine(); + else if(descriptor.Blocks == 0) + if(descriptor.BlockLength == 0) + sb.AppendFormat("\tAll remaining blocks have a variable length").AppendLine(); + else + sb.AppendFormat("\tAll remaining blocks are {0} bytes each", + descriptor.BlockLength).AppendLine(); + else if(descriptor.BlockLength == 0) + sb.AppendFormat("\t{0} blocks have a variable length", descriptor.Blocks).AppendLine(); + else + sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, + descriptor.BlockLength).AppendLine(); + } - return sb.ToString(); + break; + } + #endregion Optical device mode header + + #region Multimedia device mode header + case PeripheralDeviceTypes.MultiMediaDevice: + { + sb.Append("\tMedium is "); + + switch(header.Value.MediumType) + { + case MediumTypes.CDROM: + sb.AppendLine("120 mm CD-ROM"); + + break; + case MediumTypes.CDDA: + sb.AppendLine("120 mm Compact Disc Digital Audio"); + + break; + case MediumTypes.MixedCD: + sb.AppendLine("120 mm Compact Disc with data and audio"); + + break; + case MediumTypes.CDROM_80: + sb.AppendLine("80 mm CD-ROM"); + + break; + case MediumTypes.CDDA_80: + sb.AppendLine("80 mm Compact Disc Digital Audio"); + + break; + case MediumTypes.MixedCD_80: + sb.AppendLine("80 mm Compact Disc with data and audio"); + + break; + case MediumTypes.Unknown_CD: + sb.AppendLine("Unknown medium type"); + + break; + case MediumTypes.HybridCD: + sb.AppendLine("120 mm Hybrid disc (Photo CD)"); + + break; + case MediumTypes.Unknown_CDR: + sb.AppendLine("Unknown size CD-R"); + + break; + case MediumTypes.CDR: + sb.AppendLine("120 mm CD-R with data only"); + + break; + case MediumTypes.CDR_DA: + sb.AppendLine("120 mm CD-R with audio only"); + + break; + case MediumTypes.CDR_Mixed: + sb.AppendLine("120 mm CD-R with data and audio"); + + break; + case MediumTypes.HybridCDR: + sb.AppendLine("120 mm Hybrid CD-R (Photo CD)"); + + break; + case MediumTypes.CDR_80: + sb.AppendLine("80 mm CD-R with data only"); + + break; + case MediumTypes.CDR_DA_80: + sb.AppendLine("80 mm CD-R with audio only"); + + break; + case MediumTypes.CDR_Mixed_80: + sb.AppendLine("80 mm CD-R with data and audio"); + + break; + case MediumTypes.HybridCDR_80: + sb.AppendLine("80 mm Hybrid CD-R (Photo CD)"); + + break; + case MediumTypes.Unknown_CDRW: + sb.AppendLine("Unknown size CD-RW"); + + break; + case MediumTypes.CDRW: + sb.AppendLine("120 mm CD-RW with data only"); + + break; + case MediumTypes.CDRW_DA: + sb.AppendLine("120 mm CD-RW with audio only"); + + break; + case MediumTypes.CDRW_Mixed: + sb.AppendLine("120 mm CD-RW with data and audio"); + + break; + case MediumTypes.HybridCDRW: + sb.AppendLine("120 mm Hybrid CD-RW (Photo CD)"); + + break; + case MediumTypes.CDRW_80: + sb.AppendLine("80 mm CD-RW with data only"); + + break; + case MediumTypes.CDRW_DA_80: + sb.AppendLine("80 mm CD-RW with audio only"); + + break; + case MediumTypes.CDRW_Mixed_80: + sb.AppendLine("80 mm CD-RW with data and audio"); + + break; + case MediumTypes.HybridCDRW_80: + sb.AppendLine("80 mm Hybrid CD-RW (Photo CD)"); + + break; + case MediumTypes.Unknown_HD: + sb.AppendLine("Unknown size HD disc"); + + break; + case MediumTypes.HD: + sb.AppendLine("120 mm HD disc"); + + break; + case MediumTypes.HD_80: + sb.AppendLine("80 mm HD disc"); + + break; + case MediumTypes.NoDisc: + sb.AppendLine("No disc inserted, tray closed or caddy inserted"); + + break; + case MediumTypes.TrayOpen: + sb.AppendLine("Tray open or no caddy inserted"); + + break; + case MediumTypes.MediumError: + sb.AppendLine("Tray closed or caddy inserted but medium error"); + + break; + case MediumTypes.UnknownBlockDevice: + sb.AppendLine("Unknown block device"); + + break; + case MediumTypes.ReadOnlyBlockDevice: + sb.AppendLine("Read-only block device"); + + break; + case MediumTypes.ReadWriteBlockDevice: + sb.AppendLine("Read/Write block device"); + + break; + case MediumTypes.LTOCD: + sb.AppendLine("LTO in CD-ROM emulation mode"); + + break; + default: + sb.AppendFormat("Unknown medium type 0x{0:X2}", (byte)header.Value.MediumType).AppendLine(); + + break; + } + + if(header.Value.WriteProtected) + sb.AppendLine("\tMedium is write protected"); + + if(header.Value.DPOFUA) + sb.AppendLine("\tDrive supports DPO and FUA bits"); + + if(header.Value.BlockDescriptors != null) + foreach(BlockDescriptor descriptor in header.Value.BlockDescriptors) + { + string density = ""; + + switch(descriptor.Density) + { + case DensityType.Default: break; + case DensityType.User: + density = "user data only"; + + break; + case DensityType.UserAuxiliary: + density = "user data plus auxiliary data"; + + break; + case DensityType.UserAuxiliaryTag: + density = "4-byte tag, user data plus auxiliary data"; + + break; + case DensityType.Audio: + density = "audio information only"; + + break; + case DensityType.LTO2: + density = "LTO Ultrium-2"; + + break; + case DensityType.LTO3: + density = "LTO Ultrium-3"; + + break; + case DensityType.LTO4: + density = "LTO Ultrium-4"; + + break; + case DensityType.LTO5: + density = "LTO Ultrium-5"; + + break; + default: + density = $"with unknown density code 0x{(byte)descriptor.Density:X2}"; + + break; + } + + if(density != "") + if(descriptor.Blocks == 0) + sb.AppendFormat("\tAll remaining blocks have {0} and are {1} bytes each", density, + descriptor.BlockLength).AppendLine(); + else + sb.AppendFormat("\t{0} blocks have {1} and are {2} bytes each", descriptor.Blocks, + density, descriptor.BlockLength).AppendLine(); + else if(descriptor.Blocks == 0) + sb.AppendFormat("\tAll remaining blocks are {0} bytes each", descriptor.BlockLength). + AppendLine(); + else + sb.AppendFormat("\t{0} blocks are {1} bytes each", descriptor.Blocks, + descriptor.BlockLength).AppendLine(); + } + + break; + } + #endregion Multimedia device mode header } + + return sb.ToString(); } } \ No newline at end of file diff --git a/SCSI/Modes/Mode10.cs b/SCSI/Modes/Mode10.cs index f2b3cb3..68025f0 100644 --- a/SCSI/Modes/Mode10.cs +++ b/SCSI/Modes/Mode10.cs @@ -36,327 +36,326 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Aaru.CommonTypes.Structs.Devices.SCSI; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + public static ModeHeader? DecodeModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType) { - public static ModeHeader? DecodeModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType) + 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; + + var header = new ModeHeader { - if(modeResponse == null || - modeResponse.Length < 8) - return null; + MediumType = (MediumTypes)modeResponse[2] + }; - ushort modeLength = (ushort)((modeResponse[0] << 8) + modeResponse[1]); - ushort blockDescLength = (ushort)((modeResponse[6] << 8) + modeResponse[7]); + bool longLBA = (modeResponse[4] & 0x01) == 0x01; - if(modeResponse.Length < modeLength) - return null; - - var header = new ModeHeader + if(blockDescLength > 0) + if(longLBA) { - MediumType = (MediumTypes)modeResponse[2] - }; + header.BlockDescriptors = new BlockDescriptor[blockDescLength / 16]; - bool longLBA = (modeResponse[4] & 0x01) == 0x01; - - if(blockDescLength > 0) - if(longLBA) + for(int i = 0; i < header.BlockDescriptors.Length; i++) { - header.BlockDescriptors = new BlockDescriptor[blockDescLength / 16]; + if(12 + (i * 16) + 8 >= modeResponse.Length) + break; - for(int i = 0; i < header.BlockDescriptors.Length; i++) + header.BlockDescriptors[i] = new BlockDescriptor { - if(12 + (i * 16) + 8 >= modeResponse.Length) - break; + 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]; - temp[2] = modeResponse[5 + (i * 16) + 8]; - temp[3] = modeResponse[4 + (i * 16) + 8]; - temp[4] = modeResponse[3 + (i * 16) + 8]; - temp[5] = modeResponse[2 + (i * 16) + 8]; - temp[6] = modeResponse[1 + (i * 16) + 8]; - temp[7] = modeResponse[0 + (i * 16) + 8]; - header.BlockDescriptors[i].Blocks = BitConverter.ToUInt64(temp, 0); - header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[15 + (i * 16) + 8] << 24); - header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[14 + (i * 16) + 8] << 16); - header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[13 + (i * 16) + 8] << 8); - header.BlockDescriptors[i].BlockLength += modeResponse[12 + (i * 16) + 8]; - } + byte[] temp = new byte[8]; + temp[0] = modeResponse[7 + (i * 16) + 8]; + temp[1] = modeResponse[6 + (i * 16) + 8]; + temp[2] = modeResponse[5 + (i * 16) + 8]; + temp[3] = modeResponse[4 + (i * 16) + 8]; + temp[4] = modeResponse[3 + (i * 16) + 8]; + temp[5] = modeResponse[2 + (i * 16) + 8]; + temp[6] = modeResponse[1 + (i * 16) + 8]; + temp[7] = modeResponse[0 + (i * 16) + 8]; + header.BlockDescriptors[i].Blocks = BitConverter.ToUInt64(temp, 0); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[15 + (i * 16) + 8] << 24); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[14 + (i * 16) + 8] << 16); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[13 + (i * 16) + 8] << 8); + header.BlockDescriptors[i].BlockLength += modeResponse[12 + (i * 16) + 8]; } - else - { - header.BlockDescriptors = new BlockDescriptor[blockDescLength / 8]; - - for(int i = 0; i < header.BlockDescriptors.Length; i++) - { - 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 - { - header.BlockDescriptors[i].Density = DensityType.Default; - header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[0 + (i * 8) + 8] << 24); - } - - header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + (i * 8) + 8] << 16); - header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + (i * 8) + 8] << 8); - header.BlockDescriptors[i].Blocks += modeResponse[3 + (i * 8) + 8]; - header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + (i * 8) + 8] << 16); - header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + (i * 8) + 8] << 8); - header.BlockDescriptors[i].BlockLength += modeResponse[7 + (i * 8) + 8]; - } - } - - switch(deviceType) + } + else { - case PeripheralDeviceTypes.DirectAccess: - case PeripheralDeviceTypes.MultiMediaDevice: - header.WriteProtected = (modeResponse[3] & 0x80) == 0x80; - header.DPOFUA = (modeResponse[3] & 0x10) == 0x10; + header.BlockDescriptors = new BlockDescriptor[blockDescLength / 8]; - break; - case PeripheralDeviceTypes.SequentialAccess: - header.WriteProtected = (modeResponse[3] & 0x80) == 0x80; - header.Speed = (byte)(modeResponse[3] & 0x0F); - header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4); + for(int i = 0; i < header.BlockDescriptors.Length; i++) + { + if(7 + (i * 8) + 8 >= modeResponse.Length) + break; - break; - case PeripheralDeviceTypes.PrinterDevice: - header.BufferedMode = (byte)((modeResponse[3] & 0x70) >> 4); + header.BlockDescriptors[i] = new BlockDescriptor(); - break; - case PeripheralDeviceTypes.OpticalDevice: - header.WriteProtected = (modeResponse[3] & 0x80) == 0x80; - header.EBC = (modeResponse[3] & 0x01) == 0x01; - header.DPOFUA = (modeResponse[3] & 0x10) == 0x10; + if(deviceType != PeripheralDeviceTypes.DirectAccess) + header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + (i * 8) + 8]; + else + { + header.BlockDescriptors[i].Density = DensityType.Default; + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[0 + (i * 8) + 8] << 24); + } - break; + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + (i * 8) + 8] << 16); + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + (i * 8) + 8] << 8); + header.BlockDescriptors[i].Blocks += modeResponse[3 + (i * 8) + 8]; + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + (i * 8) + 8] << 16); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + (i * 8) + 8] << 8); + header.BlockDescriptors[i].BlockLength += modeResponse[7 + (i * 8) + 8]; + } } - return header; + switch(deviceType) + { + case PeripheralDeviceTypes.DirectAccess: + 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; } - public static string PrettifyModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType) => - PrettifyModeHeader(DecodeModeHeader10(modeResponse, deviceType), deviceType); + return header; + } - public static DecodedMode? DecodeMode10(byte[] modeResponse, PeripheralDeviceTypes deviceType) + public static string PrettifyModeHeader10(byte[] modeResponse, PeripheralDeviceTypes deviceType) => + PrettifyModeHeader(DecodeModeHeader10(modeResponse, deviceType), deviceType); + + public static DecodedMode? DecodeMode10(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + ModeHeader? hdr = DecodeModeHeader10(modeResponse, deviceType); + + if(!hdr.HasValue) + return null; + + var decoded = new DecodedMode { - ModeHeader? hdr = DecodeModeHeader10(modeResponse, deviceType); + Header = hdr.Value + }; - if(!hdr.HasValue) - return null; + bool longlba = (modeResponse[4] & 0x01) == 0x01; + int offset; + int blkDrLength = 0; - var decoded = new DecodedMode + if(decoded.Header.BlockDescriptors != null) + blkDrLength = decoded.Header.BlockDescriptors.Length; + + 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; + + List listpages = new(); + + while(offset < modeResponse.Length) + { + bool isSubpage = (modeResponse[offset] & 0x40) == 0x40; + var pg = new ModePage(); + byte pageNo = (byte)(modeResponse[offset] & 0x3F); + + if(pageNo == 0) { - 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); + pg.PageResponse = new byte[modeResponse.Length - offset]; + Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); + pg.Page = 0; + pg.Subpage = 0; + offset += pg.PageResponse.Length; + } else - offset = 8 + (blkDrLength * 8); - - int length = modeResponse[0] << 8; - length += modeResponse[1]; - length += 2; - - if(length != modeResponse.Length) - return decoded; - - List listpages = new(); - - while(offset < modeResponse.Length) { - bool isSubpage = (modeResponse[offset] & 0x40) == 0x40; - var pg = new ModePage(); - byte pageNo = (byte)(modeResponse[offset] & 0x3F); - - if(pageNo == 0) + if(isSubpage && offset + 3 < modeResponse.Length) { - pg.PageResponse = new byte[modeResponse.Length - offset]; - Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); - pg.Page = 0; + pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4]; + int copyLen = pg.PageResponse.Length; + + if(pg.PageResponse.Length + offset > modeResponse.Length) + copyLen = modeResponse.Length - offset; + + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); + pg.Subpage = modeResponse[offset + 1]; + offset += pg.PageResponse.Length; + } + else if(isSubpage && offset + 1 < modeResponse.Length) + { + pg.PageResponse = new byte[modeResponse[offset + 1] + 2]; + int copyLen = pg.PageResponse.Length; + + if(pg.PageResponse.Length + offset > modeResponse.Length) + copyLen = modeResponse.Length - offset; + + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); pg.Subpage = 0; offset += pg.PageResponse.Length; } else - { - if(isSubpage && offset + 3 < modeResponse.Length) - { - pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4]; - int copyLen = pg.PageResponse.Length; - - if(pg.PageResponse.Length + offset > modeResponse.Length) - copyLen = modeResponse.Length - offset; - - Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); - pg.Page = (byte)(modeResponse[offset] & 0x3F); - pg.Subpage = modeResponse[offset + 1]; - offset += pg.PageResponse.Length; - } - else if(isSubpage && offset + 1 < modeResponse.Length) - { - pg.PageResponse = new byte[modeResponse[offset + 1] + 2]; - int copyLen = pg.PageResponse.Length; - - if(pg.PageResponse.Length + offset > modeResponse.Length) - copyLen = modeResponse.Length - offset; - - Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); - pg.Page = (byte)(modeResponse[offset] & 0x3F); - pg.Subpage = 0; - offset += pg.PageResponse.Length; - } - else - offset = modeResponse.Length; - } - - listpages.Add(pg); + offset = modeResponse.Length; } - decoded.Pages = listpages.ToArray(); - - return decoded; + listpages.Add(pg); } - public static byte[] EncodeModeHeader10(ModeHeader header, PeripheralDeviceTypes deviceType, - bool longLBA = false) + decoded.Pages = listpages.ToArray(); + + return decoded; + } + + public static byte[] EncodeModeHeader10(ModeHeader header, PeripheralDeviceTypes deviceType, + 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[2] = (byte)header.MediumType; + + switch(deviceType) { - byte[] hdr; + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.MultiMediaDevice: + if(header.WriteProtected) + hdr[3] += 0x80; - 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]; + if(header.DPOFUA) + hdr[3] += 0x10; - hdr[2] = (byte)header.MediumType; + break; + case PeripheralDeviceTypes.SequentialAccess: + if(header.WriteProtected) + hdr[3] += 0x80; - switch(deviceType) - { - case PeripheralDeviceTypes.DirectAccess: - case PeripheralDeviceTypes.MultiMediaDevice: - if(header.WriteProtected) - hdr[3] += 0x80; + hdr[3] += (byte)(header.Speed & 0x0F); + hdr[3] += (byte)((header.BufferedMode << 4) & 0x70); - if(header.DPOFUA) - hdr[3] += 0x10; + break; + case PeripheralDeviceTypes.PrinterDevice: + hdr[3] += (byte)((header.BufferedMode << 4) & 0x70); - break; - case PeripheralDeviceTypes.SequentialAccess: - if(header.WriteProtected) - hdr[3] += 0x80; + break; + case PeripheralDeviceTypes.OpticalDevice: + if(header.WriteProtected) + hdr[3] += 0x80; - hdr[3] += (byte)(header.Speed & 0x0F); - hdr[3] += (byte)((header.BufferedMode << 4) & 0x70); + if(header.EBC) + hdr[3] += 0x01; - break; - case PeripheralDeviceTypes.PrinterDevice: - hdr[3] += (byte)((header.BufferedMode << 4) & 0x70); + if(header.DPOFUA) + hdr[3] += 0x10; - break; - case PeripheralDeviceTypes.OpticalDevice: - if(header.WriteProtected) - hdr[3] += 0x80; + break; + } - if(header.EBC) - hdr[3] += 0x01; - - if(header.DPOFUA) - hdr[3] += 0x10; - - break; - } - - if(longLBA) - hdr[4] += 0x01; - - if(header.BlockDescriptors == null) - return hdr; - - if(longLBA) - for(int i = 0; i < header.BlockDescriptors.Length; i++) - { - byte[] temp = BitConverter.GetBytes(header.BlockDescriptors[i].Blocks); - hdr[7 + (i * 16) + 8] = temp[0]; - hdr[6 + (i * 16) + 8] = temp[1]; - hdr[5 + (i * 16) + 8] = temp[2]; - hdr[4 + (i * 16) + 8] = temp[3]; - hdr[3 + (i * 16) + 8] = temp[4]; - hdr[2 + (i * 16) + 8] = temp[5]; - hdr[1 + (i * 16) + 8] = temp[6]; - hdr[0 + (i * 16) + 8] = temp[7]; - hdr[12 + (i * 16) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF000000) >> 24); - hdr[13 + (i * 16) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); - hdr[14 + (i * 16) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); - hdr[15 + (i * 16) + 8] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); - } - else - 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[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); - hdr[5 + (i * 8) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); - hdr[6 + (i * 8) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); - hdr[7 + (i * 8) + 8] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); - } + if(longLBA) + hdr[4] += 0x01; + if(header.BlockDescriptors == null) return hdr; - } - - public static byte[] EncodeMode10(DecodedMode mode, PeripheralDeviceTypes deviceType) - { - int modeSize = 0; - - if(mode.Pages != null) - modeSize += mode.Pages.Sum(page => page.PageResponse.Length); - - byte[] hdr = EncodeModeHeader10(mode.Header, deviceType); - modeSize += hdr.Length; - byte[] md = new byte[modeSize]; - - Array.Copy(hdr, 0, md, 0, hdr.Length); - - if(mode.Pages == null) - return md; + if(longLBA) + for(int i = 0; i < header.BlockDescriptors.Length; i++) { - int offset = hdr.Length; + byte[] temp = BitConverter.GetBytes(header.BlockDescriptors[i].Blocks); + hdr[7 + (i * 16) + 8] = temp[0]; + hdr[6 + (i * 16) + 8] = temp[1]; + hdr[5 + (i * 16) + 8] = temp[2]; + hdr[4 + (i * 16) + 8] = temp[3]; + hdr[3 + (i * 16) + 8] = temp[4]; + hdr[2 + (i * 16) + 8] = temp[5]; + hdr[1 + (i * 16) + 8] = temp[6]; + hdr[0 + (i * 16) + 8] = temp[7]; + hdr[12 + (i * 16) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF000000) >> 24); + hdr[13 + (i * 16) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); + hdr[14 + (i * 16) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); + hdr[15 + (i * 16) + 8] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); + } + else + 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); - foreach(ModePage page in mode.Pages) - { - Array.Copy(page.PageResponse, 0, md, offset, page.PageResponse.Length); - offset += page.PageResponse.Length; - } + 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); + hdr[5 + (i * 8) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); + hdr[6 + (i * 8) + 8] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); + hdr[7 + (i * 8) + 8] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); } + return hdr; + } + + public static byte[] EncodeMode10(DecodedMode mode, PeripheralDeviceTypes deviceType) + { + int modeSize = 0; + + if(mode.Pages != null) + modeSize += mode.Pages.Sum(page => page.PageResponse.Length); + + byte[] hdr = EncodeModeHeader10(mode.Header, deviceType); + modeSize += hdr.Length; + byte[] md = new byte[modeSize]; + + Array.Copy(hdr, 0, md, 0, hdr.Length); + + 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); + offset += page.PageResponse.Length; + } } + + return md; } } \ No newline at end of file diff --git a/SCSI/Modes/Mode6.cs b/SCSI/Modes/Mode6.cs index 2cf0e41..db349f5 100644 --- a/SCSI/Modes/Mode6.cs +++ b/SCSI/Modes/Mode6.cs @@ -36,244 +36,243 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Aaru.CommonTypes.Structs.Devices.SCSI; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + public static ModeHeader? DecodeModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) { - public static ModeHeader? DecodeModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) + if(modeResponse == null || + modeResponse.Length < 4 || + modeResponse.Length < modeResponse[0] + 1) + return null; + + var header = new ModeHeader { - if(modeResponse == null || - modeResponse.Length < 4 || - modeResponse.Length < modeResponse[0] + 1) - return null; + MediumType = (MediumTypes)modeResponse[1] + }; - var header = new ModeHeader + if(modeResponse[3] > 0) + { + header.BlockDescriptors = new BlockDescriptor[modeResponse[3] / 8]; + + for(int i = 0; i < header.BlockDescriptors.Length; i++) { - 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]; - header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + (i * 8) + 4] << 16); - header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + (i * 8) + 4] << 8); - header.BlockDescriptors[i].Blocks += modeResponse[3 + (i * 8) + 4]; - header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + (i * 8) + 4] << 16); - header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + (i * 8) + 4] << 8); - header.BlockDescriptors[i].BlockLength += modeResponse[7 + (i * 8) + 4]; - } + header.BlockDescriptors[i].Density = (DensityType)modeResponse[0 + (i * 8) + 4]; + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[1 + (i * 8) + 4] << 16); + header.BlockDescriptors[i].Blocks += (ulong)(modeResponse[2 + (i * 8) + 4] << 8); + header.BlockDescriptors[i].Blocks += modeResponse[3 + (i * 8) + 4]; + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[5 + (i * 8) + 4] << 16); + header.BlockDescriptors[i].BlockLength += (uint)(modeResponse[6 + (i * 8) + 4] << 8); + header.BlockDescriptors[i].BlockLength += modeResponse[7 + (i * 8) + 4]; } - - switch(deviceType) - { - case PeripheralDeviceTypes.DirectAccess: - 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; - } - - return header; } - public static string PrettifyModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) => - PrettifyModeHeader(DecodeModeHeader6(modeResponse, deviceType), deviceType); - - public static DecodedMode? DecodeMode6(byte[] modeResponse, PeripheralDeviceTypes deviceType) + switch(deviceType) { - ModeHeader? hdr = DecodeModeHeader6(modeResponse, deviceType); + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.MultiMediaDevice: + header.WriteProtected = (modeResponse[2] & 0x80) == 0x80; + header.DPOFUA = (modeResponse[2] & 0x10) == 0x10; - if(!hdr.HasValue) - return null; + break; + case PeripheralDeviceTypes.SequentialAccess: + header.WriteProtected = (modeResponse[2] & 0x80) == 0x80; + header.Speed = (byte)(modeResponse[2] & 0x0F); + header.BufferedMode = (byte)((modeResponse[2] & 0x70) >> 4); - var decoded = new DecodedMode + 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; + } + + return header; + } + + public static string PrettifyModeHeader6(byte[] modeResponse, PeripheralDeviceTypes deviceType) => + PrettifyModeHeader(DecodeModeHeader6(modeResponse, deviceType), deviceType); + + public static DecodedMode? DecodeMode6(byte[] modeResponse, PeripheralDeviceTypes deviceType) + { + ModeHeader? hdr = DecodeModeHeader6(modeResponse, deviceType); + + 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; + + List listpages = new List(); + + while(offset < modeResponse.Length) + { + bool isSubpage = (modeResponse[offset] & 0x40) == 0x40; + var pg = new ModePage(); + byte pageNo = (byte)(modeResponse[offset] & 0x3F); + + if(pageNo == 0) { - 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; - - List listpages = new List(); - - while(offset < modeResponse.Length) + pg.PageResponse = new byte[modeResponse.Length - offset]; + Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); + pg.Page = 0; + pg.Subpage = 0; + offset += pg.PageResponse.Length; + } + else { - bool isSubpage = (modeResponse[offset] & 0x40) == 0x40; - var pg = new ModePage(); - byte pageNo = (byte)(modeResponse[offset] & 0x3F); - - if(pageNo == 0) + if(isSubpage) { - pg.PageResponse = new byte[modeResponse.Length - offset]; - Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); - pg.Page = 0; - pg.Subpage = 0; + if(offset + 3 >= modeResponse.Length) + break; + + pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4]; + int copyLen = pg.PageResponse.Length; + + if(pg.PageResponse.Length + offset > modeResponse.Length) + copyLen = modeResponse.Length - offset; + + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); + pg.Subpage = modeResponse[offset + 1]; offset += pg.PageResponse.Length; } else { - if(isSubpage) - { - if(offset + 3 >= modeResponse.Length) - break; + if(offset + 1 >= modeResponse.Length) + break; - pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4]; - int copyLen = pg.PageResponse.Length; + pg.PageResponse = new byte[modeResponse[offset + 1] + 2]; + int copyLen = pg.PageResponse.Length; - if(pg.PageResponse.Length + offset > modeResponse.Length) - copyLen = modeResponse.Length - offset; + if(pg.PageResponse.Length + offset > modeResponse.Length) + copyLen = modeResponse.Length - offset; - Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); - pg.Page = (byte)(modeResponse[offset] & 0x3F); - pg.Subpage = modeResponse[offset + 1]; - offset += pg.PageResponse.Length; - } - else - { - if(offset + 1 >= modeResponse.Length) - break; - - pg.PageResponse = new byte[modeResponse[offset + 1] + 2]; - int copyLen = pg.PageResponse.Length; - - if(pg.PageResponse.Length + offset > modeResponse.Length) - copyLen = modeResponse.Length - offset; - - Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); - pg.Page = (byte)(modeResponse[offset] & 0x3F); - pg.Subpage = 0; - offset += pg.PageResponse.Length; - } + Array.Copy(modeResponse, offset, pg.PageResponse, 0, copyLen); + pg.Page = (byte)(modeResponse[offset] & 0x3F); + pg.Subpage = 0; + offset += pg.PageResponse.Length; } - - listpages.Add(pg); } - decoded.Pages = listpages.ToArray(); - - return decoded; + listpages.Add(pg); } - public static byte[] EncodeModeHeader6(ModeHeader header, PeripheralDeviceTypes deviceType) + decoded.Pages = listpages.ToArray(); + + return decoded; + } + + public static byte[] EncodeModeHeader6(ModeHeader header, PeripheralDeviceTypes deviceType) + { + byte[] hdr = header.BlockDescriptors != null ? new byte[4 + (header.BlockDescriptors.Length * 8)] + : new byte[4]; + + hdr[1] = (byte)header.MediumType; + + switch(deviceType) { - byte[] hdr = header.BlockDescriptors != null ? new byte[4 + (header.BlockDescriptors.Length * 8)] - : new byte[4]; + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.MultiMediaDevice: + if(header.WriteProtected) + hdr[2] += 0x80; - hdr[1] = (byte)header.MediumType; + if(header.DPOFUA) + hdr[2] += 0x10; - switch(deviceType) - { - case PeripheralDeviceTypes.DirectAccess: - case PeripheralDeviceTypes.MultiMediaDevice: - if(header.WriteProtected) - hdr[2] += 0x80; + break; + case PeripheralDeviceTypes.SequentialAccess: + if(header.WriteProtected) + hdr[2] += 0x80; - if(header.DPOFUA) - hdr[2] += 0x10; + hdr[2] += (byte)(header.Speed & 0x0F); + hdr[2] += (byte)((header.BufferedMode << 4) & 0x70); - break; - case PeripheralDeviceTypes.SequentialAccess: - if(header.WriteProtected) - hdr[2] += 0x80; + break; + case PeripheralDeviceTypes.PrinterDevice: + hdr[2] += (byte)((header.BufferedMode << 4) & 0x70); - hdr[2] += (byte)(header.Speed & 0x0F); - hdr[2] += (byte)((header.BufferedMode << 4) & 0x70); + break; + case PeripheralDeviceTypes.OpticalDevice: + if(header.WriteProtected) + hdr[2] += 0x80; - break; - case PeripheralDeviceTypes.PrinterDevice: - hdr[2] += (byte)((header.BufferedMode << 4) & 0x70); + if(header.EBC) + hdr[2] += 0x01; - break; - case PeripheralDeviceTypes.OpticalDevice: - if(header.WriteProtected) - hdr[2] += 0x80; + if(header.DPOFUA) + hdr[2] += 0x10; - if(header.EBC) - hdr[2] += 0x01; - - if(header.DPOFUA) - hdr[2] += 0x10; - - break; - } - - if(header.BlockDescriptors == null) - return hdr; - - hdr[3] = (byte)(header.BlockDescriptors.Length * 8); - - for(int i = 0; i < header.BlockDescriptors.Length; i++) - { - hdr[0 + (i * 8) + 4] = (byte)header.BlockDescriptors[i].Density; - hdr[1 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF0000) >> 16); - hdr[2 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF00) >> 8); - hdr[3 + (i * 8) + 4] = (byte)(header.BlockDescriptors[i].Blocks & 0xFF); - hdr[5 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); - hdr[6 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); - hdr[7 + (i * 8) + 4] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); - } + break; + } + if(header.BlockDescriptors == null) return hdr; - } - public static byte[] EncodeMode6(DecodedMode mode, PeripheralDeviceTypes deviceType) + hdr[3] = (byte)(header.BlockDescriptors.Length * 8); + + for(int i = 0; i < header.BlockDescriptors.Length; i++) { - int modeSize = 0; - - if(mode.Pages != null) - modeSize += mode.Pages.Sum(page => page.PageResponse.Length); - - byte[] hdr = EncodeModeHeader6(mode.Header, deviceType); - modeSize += hdr.Length; - byte[] md = new byte[modeSize]; - - Array.Copy(hdr, 0, md, 0, hdr.Length); - - 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); - offset += page.PageResponse.Length; - } - } - - return md; + hdr[0 + (i * 8) + 4] = (byte)header.BlockDescriptors[i].Density; + hdr[1 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF0000) >> 16); + hdr[2 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].Blocks & 0xFF00) >> 8); + hdr[3 + (i * 8) + 4] = (byte)(header.BlockDescriptors[i].Blocks & 0xFF); + hdr[5 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF0000) >> 16); + hdr[6 + (i * 8) + 4] = (byte)((header.BlockDescriptors[i].BlockLength & 0xFF00) >> 8); + hdr[7 + (i * 8) + 4] = (byte)(header.BlockDescriptors[i].BlockLength & 0xFF); } + + return hdr; + } + + public static byte[] EncodeMode6(DecodedMode mode, PeripheralDeviceTypes deviceType) + { + int modeSize = 0; + + if(mode.Pages != null) + modeSize += mode.Pages.Sum(page => page.PageResponse.Length); + + byte[] hdr = EncodeModeHeader6(mode.Header, deviceType); + modeSize += hdr.Length; + byte[] md = new byte[modeSize]; + + Array.Copy(hdr, 0, md, 0, hdr.Length); + + 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); + offset += page.PageResponse.Length; + } + } + + return md; } } \ No newline at end of file diff --git a/SCSI/Modes/Structs.cs b/SCSI/Modes/Structs.cs index f297d74..84f0114 100644 --- a/SCSI/Modes/Structs.cs +++ b/SCSI/Modes/Structs.cs @@ -32,41 +32,40 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Modes { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Modes + public struct BlockDescriptor { - public struct BlockDescriptor - { - public DensityType Density; - public ulong Blocks; - public uint BlockLength; - } + public DensityType Density; + public ulong Blocks; + public uint BlockLength; + } - public struct ModeHeader - { - public MediumTypes MediumType; - public bool WriteProtected; - public BlockDescriptor[] BlockDescriptors; - public byte Speed; - public byte BufferedMode; - public bool EBC; - public bool DPOFUA; - } + public struct ModeHeader + { + public MediumTypes MediumType; + public bool WriteProtected; + public BlockDescriptor[] BlockDescriptors; + public byte Speed; + public byte BufferedMode; + public bool EBC; + public bool DPOFUA; + } - public struct ModePage - { - public byte Page; - public byte Subpage; - public byte[] PageResponse; - } + public struct ModePage + { + public byte Page; + public byte Subpage; + public byte[] PageResponse; + } - public struct DecodedMode - { - public ModeHeader Header; - public ModePage[] Pages; - } + public struct DecodedMode + { + public ModeHeader Header; + public ModePage[] Pages; } } \ No newline at end of file diff --git a/SCSI/SSC/BlockLimits.cs b/SCSI/SSC/BlockLimits.cs index bd84e12..c49883a 100644 --- a/SCSI/SSC/BlockLimits.cs +++ b/SCSI/SSC/BlockLimits.cs @@ -34,61 +34,60 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SCSI.SSC +namespace Aaru.Decoders.SCSI.SSC; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class BlockLimits { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class BlockLimits + public static BlockLimitsData? Decode(byte[] response) { - public static BlockLimitsData? Decode(byte[] response) + if(response?.Length != 6) + return null; + + return new BlockLimitsData { - if(response?.Length != 6) - return null; + granularity = (byte)(response[0] & 0x1F), + maxBlockLen = (uint)((response[1] << 16) + (response[2] << 8) + response[3]), + minBlockLen = (ushort)((response[4] << 8) + response[5]) + }; + } - return new BlockLimitsData - { - granularity = (byte)(response[0] & 0x1F), - maxBlockLen = (uint)((response[1] << 16) + (response[2] << 8) + response[3]), - minBlockLen = (ushort)((response[4] << 8) + response[5]) - }; - } + public static string Prettify(BlockLimitsData? decoded) + { + if(decoded == null) + return null; - public static string Prettify(BlockLimitsData? decoded) + var sb = new StringBuilder(); + + if(decoded.Value.maxBlockLen == decoded.Value.minBlockLen) + sb.AppendFormat("Device's block size is fixed at {0} bytes", decoded.Value.minBlockLen).AppendLine(); + else { - if(decoded == null) - return null; - - var sb = new StringBuilder(); - - if(decoded.Value.maxBlockLen == decoded.Value.minBlockLen) - sb.AppendFormat("Device's block size is fixed at {0} bytes", decoded.Value.minBlockLen).AppendLine(); + if(decoded.Value.maxBlockLen > 0) + sb.AppendFormat("Device's maximum block size is {0} bytes", decoded.Value.maxBlockLen).AppendLine(); else - { - if(decoded.Value.maxBlockLen > 0) - sb.AppendFormat("Device's maximum block size is {0} bytes", decoded.Value.maxBlockLen).AppendLine(); - else - sb.AppendLine("Device does not specify a maximum block size"); + sb.AppendLine("Device does not specify a maximum block size"); - sb.AppendFormat("Device's minimum block size is {0} bytes", decoded.Value.minBlockLen).AppendLine(); + sb.AppendFormat("Device's minimum block size is {0} bytes", decoded.Value.minBlockLen).AppendLine(); - if(decoded.Value.granularity > 0) - sb.AppendFormat("Device's needs a block size granularity of 2^{0} ({1}) bytes", - decoded.Value.granularity, Math.Pow(2, decoded.Value.granularity)).AppendLine(); - } - - return sb.ToString(); + if(decoded.Value.granularity > 0) + sb.AppendFormat("Device's needs a block size granularity of 2^{0} ({1}) bytes", + decoded.Value.granularity, Math.Pow(2, decoded.Value.granularity)).AppendLine(); } - public static string Prettify(byte[] response) => Prettify(Decode(response)); + return sb.ToString(); + } - public struct BlockLimitsData - { - /// All blocks size must be multiple of 2^ - public byte granularity; - /// Maximum block length in bytes - public uint maxBlockLen; - /// Minimum block length in bytes - public ushort minBlockLen; - } + public static string Prettify(byte[] response) => Prettify(Decode(response)); + + public struct BlockLimitsData + { + /// All blocks size must be multiple of 2^ + public byte granularity; + /// Maximum block length in bytes + public uint maxBlockLen; + /// Minimum block length in bytes + public ushort minBlockLen; } } \ No newline at end of file diff --git a/SCSI/SSC/DensitySupport.cs b/SCSI/SSC/DensitySupport.cs index 37516c4..7fcaffe 100644 --- a/SCSI/SSC/DensitySupport.cs +++ b/SCSI/SSC/DensitySupport.cs @@ -36,259 +36,258 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SCSI.SSC +namespace Aaru.Decoders.SCSI.SSC; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DensitySupport { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class DensitySupport + public static DensitySupportHeader? DecodeDensity(byte[] response) { - public static DensitySupportHeader? DecodeDensity(byte[] response) + if(response == null) + return null; + + if(response.Length <= 56) + return null; + + ushort responseLen = (ushort)((response[0] << 8) + response[1] + 2); + + if(response.Length != responseLen) + return null; + + List descriptors = new List(); + int offset = 4; + + while(offset < response.Length) { - if(response == null) - return null; - - if(response.Length <= 56) - return null; - - ushort responseLen = (ushort)((response[0] << 8) + response[1] + 2); - - if(response.Length != responseLen) - return null; - - List descriptors = new List(); - int offset = 4; - - while(offset < response.Length) + var descriptor = new DensitySupportDescriptor { - var descriptor = new DensitySupportDescriptor - { - primaryCode = response[offset + 0], - secondaryCode = response[offset + 1], - writable = (response[offset + 2] & 0x80) == 0x80, - duplicate = (response[offset + 2] & 0x40) == 0x40, - defaultDensity = (response[offset + 2] & 0x20) == 0x20, - reserved = (byte)((response[offset + 2] & 0x1E) >> 1), - lenvalid = (response[offset + 2] & 0x01) == 0x01, - len = (ushort)((response[offset + 3] << 8) + response[offset + 4]), - bpmm = (uint)((response[offset + 5] << 16) + (response[offset + 6] << 8) + response[offset + 7]), - width = (ushort)((response[offset + 8] << 8) + response[offset + 9]), - tracks = (ushort)((response[offset + 10] << 8) + response[offset + 11]), - capacity = (uint)((response[offset + 12] << 24) + (response[offset + 13] << 16) + - (response[offset + 14] << 8) + response[offset + 15]) - }; - - byte[] tmp = new byte[8]; - Array.Copy(response, offset + 16, tmp, 0, 8); - descriptor.organization = StringHandlers.CToString(tmp).Trim(); - tmp = new byte[8]; - Array.Copy(response, offset + 24, tmp, 0, 8); - descriptor.name = StringHandlers.CToString(tmp).Trim(); - tmp = new byte[20]; - Array.Copy(response, offset + 32, tmp, 0, 20); - descriptor.description = StringHandlers.CToString(tmp).Trim(); - - if(descriptor.lenvalid) - offset += descriptor.len + 5; - else - offset += 52; - - descriptors.Add(descriptor); - } - - var decoded = new DensitySupportHeader - { - length = responseLen, - reserved = (ushort)((response[2] << 8) + response[3] + 2), - descriptors = descriptors.ToArray() + primaryCode = response[offset + 0], + secondaryCode = response[offset + 1], + writable = (response[offset + 2] & 0x80) == 0x80, + duplicate = (response[offset + 2] & 0x40) == 0x40, + defaultDensity = (response[offset + 2] & 0x20) == 0x20, + reserved = (byte)((response[offset + 2] & 0x1E) >> 1), + lenvalid = (response[offset + 2] & 0x01) == 0x01, + len = (ushort)((response[offset + 3] << 8) + response[offset + 4]), + bpmm = (uint)((response[offset + 5] << 16) + (response[offset + 6] << 8) + response[offset + 7]), + width = (ushort)((response[offset + 8] << 8) + response[offset + 9]), + tracks = (ushort)((response[offset + 10] << 8) + response[offset + 11]), + capacity = (uint)((response[offset + 12] << 24) + (response[offset + 13] << 16) + + (response[offset + 14] << 8) + response[offset + 15]) }; - return decoded; + byte[] tmp = new byte[8]; + Array.Copy(response, offset + 16, tmp, 0, 8); + descriptor.organization = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[8]; + Array.Copy(response, offset + 24, tmp, 0, 8); + descriptor.name = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[20]; + Array.Copy(response, offset + 32, tmp, 0, 20); + descriptor.description = StringHandlers.CToString(tmp).Trim(); + + if(descriptor.lenvalid) + offset += descriptor.len + 5; + else + offset += 52; + + descriptors.Add(descriptor); } - public static string PrettifyDensity(DensitySupportHeader? density) + var decoded = new DensitySupportHeader { - if(density == null) + length = responseLen, + reserved = (ushort)((response[2] << 8) + response[3] + 2), + descriptors = descriptors.ToArray() + }; + + return decoded; + } + + public static string PrettifyDensity(DensitySupportHeader? density) + { + if(density == null) + return null; + + DensitySupportHeader decoded = density.Value; + var sb = new StringBuilder(); + + foreach(DensitySupportDescriptor descriptor in decoded.descriptors) + { + sb.AppendFormat("Density \"{0}\" defined by \"{1}\".", descriptor.name, descriptor.organization). + AppendLine(); + + sb.AppendFormat("\tPrimary code: {0:X2}h", descriptor.primaryCode).AppendLine(); + + if(descriptor.primaryCode != descriptor.secondaryCode) + sb.AppendFormat("\tSecondary code: {0:X2}h", descriptor.secondaryCode).AppendLine(); + + if(descriptor.writable) + sb.AppendLine("\tDrive can write this density"); + + if(descriptor.duplicate) + sb.AppendLine("\tThis descriptor is duplicated"); + + if(descriptor.defaultDensity) + sb.AppendLine("\tThis is the default density on the drive"); + + sb.AppendFormat("\tDensity has {0} bits per mm, with {1} tracks in a {2} mm width tape", + descriptor.bpmm, descriptor.tracks, descriptor.width / (double)10).AppendLine(); + + sb.AppendFormat("\tDensity maximum capacity is {0} megabytes", descriptor.capacity).AppendLine(); + sb.AppendFormat("\tDensity description: {0}", descriptor.description).AppendLine(); + sb.AppendLine(); + } + + return sb.ToString(); + } + + public static string PrettifyDensity(byte[] response) => PrettifyDensity(DecodeDensity(response)); + + public static MediaTypeSupportHeader? DecodeMediumType(byte[] response) + { + if(response == null) + return null; + + if(response.Length <= 60) + return null; + + ushort responseLen = (ushort)((response[0] << 8) + response[1] + 2); + + if(response.Length != responseLen) + return null; + + List descriptors = new List(); + int offset = 4; + + while(offset < response.Length) + { + var descriptor = new MediaTypeSupportDescriptor + { + mediumType = response[offset + 0], + reserved1 = response[offset + 1], + len = (ushort)((response[offset + 2] << 8) + response[offset + 3]) + }; + + if(descriptor.len != 52) return null; - DensitySupportHeader decoded = density.Value; - var sb = new StringBuilder(); + descriptor.numberOfCodes = response[offset + 4]; + descriptor.densityCodes = new byte[9]; + Array.Copy(response, offset + 5, descriptor.densityCodes, 0, 9); + descriptor.width = (ushort)((response[offset + 14] << 8) + response[offset + 15]); + descriptor.length = (ushort)((response[offset + 16] << 8) + response[offset + 17]); + descriptor.reserved1 = response[offset + 18]; + descriptor.reserved1 = response[offset + 19]; + byte[] tmp = new byte[8]; + Array.Copy(response, offset + 20, tmp, 0, 8); + descriptor.organization = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[8]; + Array.Copy(response, offset + 28, tmp, 0, 8); + descriptor.name = StringHandlers.CToString(tmp).Trim(); + tmp = new byte[20]; + Array.Copy(response, offset + 36, tmp, 0, 20); + descriptor.description = StringHandlers.CToString(tmp).Trim(); - foreach(DensitySupportDescriptor descriptor in decoded.descriptors) + offset += 56; + + descriptors.Add(descriptor); + } + + var decoded = new MediaTypeSupportHeader + { + length = responseLen, + reserved = (ushort)((response[2] << 8) + response[3] + 2), + descriptors = descriptors.ToArray() + }; + + return decoded; + } + + public static string PrettifyMediumType(MediaTypeSupportHeader? mediumType) + { + if(mediumType == null) + return null; + + MediaTypeSupportHeader decoded = mediumType.Value; + var sb = new StringBuilder(); + + foreach(MediaTypeSupportDescriptor descriptor in decoded.descriptors) + { + sb.AppendFormat("Medium type \"{0}\" defined by \"{1}\".", descriptor.name, descriptor.organization). + AppendLine(); + + sb.AppendFormat("\tMedium type code: {0:X2}h", descriptor.mediumType).AppendLine(); + + if(descriptor.numberOfCodes > 0) { - sb.AppendFormat("Density \"{0}\" defined by \"{1}\".", descriptor.name, descriptor.organization). - AppendLine(); + sb.AppendFormat("\tMedium supports following density codes:"); - sb.AppendFormat("\tPrimary code: {0:X2}h", descriptor.primaryCode).AppendLine(); + for(int i = 0; i < descriptor.numberOfCodes; i++) + sb.AppendFormat(" {0:X2}h", descriptor.densityCodes[i]); - if(descriptor.primaryCode != descriptor.secondaryCode) - sb.AppendFormat("\tSecondary code: {0:X2}h", descriptor.secondaryCode).AppendLine(); - - if(descriptor.writable) - sb.AppendLine("\tDrive can write this density"); - - if(descriptor.duplicate) - sb.AppendLine("\tThis descriptor is duplicated"); - - if(descriptor.defaultDensity) - sb.AppendLine("\tThis is the default density on the drive"); - - sb.AppendFormat("\tDensity has {0} bits per mm, with {1} tracks in a {2} mm width tape", - descriptor.bpmm, descriptor.tracks, descriptor.width / (double)10).AppendLine(); - - sb.AppendFormat("\tDensity maximum capacity is {0} megabytes", descriptor.capacity).AppendLine(); - sb.AppendFormat("\tDensity description: {0}", descriptor.description).AppendLine(); sb.AppendLine(); } - return sb.ToString(); + sb.AppendFormat("\tMedium has a nominal length of {0} m in a {1} mm width tape", descriptor.length, + descriptor.width / (double)10).AppendLine(); + + sb.AppendFormat("\tMedium description: {0}", descriptor.description).AppendLine(); + sb.AppendLine(); } - public static string PrettifyDensity(byte[] response) => PrettifyDensity(DecodeDensity(response)); + return sb.ToString(); + } - public static MediaTypeSupportHeader? DecodeMediumType(byte[] response) - { - if(response == null) - return null; + public static string PrettifyMediumType(byte[] response) => PrettifyMediumType(DecodeMediumType(response)); - if(response.Length <= 60) - return null; + public struct DensitySupportHeader + { + public ushort length; + public ushort reserved; + public DensitySupportDescriptor[] descriptors; + } - ushort responseLen = (ushort)((response[0] << 8) + response[1] + 2); + public struct MediaTypeSupportHeader + { + public ushort length; + public ushort reserved; + public MediaTypeSupportDescriptor[] descriptors; + } - if(response.Length != responseLen) - return null; + public struct DensitySupportDescriptor + { + public byte primaryCode; + public byte secondaryCode; + public bool writable; + public bool duplicate; + public bool defaultDensity; + public byte reserved; + public bool lenvalid; + public ushort len; + public uint bpmm; + public ushort width; + public ushort tracks; + public uint capacity; + public string organization; + public string name; + public string description; + } - List descriptors = new List(); - int offset = 4; - - while(offset < response.Length) - { - var descriptor = new MediaTypeSupportDescriptor - { - mediumType = response[offset + 0], - reserved1 = response[offset + 1], - len = (ushort)((response[offset + 2] << 8) + response[offset + 3]) - }; - - if(descriptor.len != 52) - return null; - - descriptor.numberOfCodes = response[offset + 4]; - descriptor.densityCodes = new byte[9]; - Array.Copy(response, offset + 5, descriptor.densityCodes, 0, 9); - descriptor.width = (ushort)((response[offset + 14] << 8) + response[offset + 15]); - descriptor.length = (ushort)((response[offset + 16] << 8) + response[offset + 17]); - descriptor.reserved1 = response[offset + 18]; - descriptor.reserved1 = response[offset + 19]; - byte[] tmp = new byte[8]; - Array.Copy(response, offset + 20, tmp, 0, 8); - descriptor.organization = StringHandlers.CToString(tmp).Trim(); - tmp = new byte[8]; - Array.Copy(response, offset + 28, tmp, 0, 8); - descriptor.name = StringHandlers.CToString(tmp).Trim(); - tmp = new byte[20]; - Array.Copy(response, offset + 36, tmp, 0, 20); - descriptor.description = StringHandlers.CToString(tmp).Trim(); - - offset += 56; - - descriptors.Add(descriptor); - } - - var decoded = new MediaTypeSupportHeader - { - length = responseLen, - reserved = (ushort)((response[2] << 8) + response[3] + 2), - descriptors = descriptors.ToArray() - }; - - return decoded; - } - - public static string PrettifyMediumType(MediaTypeSupportHeader? mediumType) - { - if(mediumType == null) - return null; - - MediaTypeSupportHeader decoded = mediumType.Value; - var sb = new StringBuilder(); - - foreach(MediaTypeSupportDescriptor descriptor in decoded.descriptors) - { - sb.AppendFormat("Medium type \"{0}\" defined by \"{1}\".", descriptor.name, descriptor.organization). - AppendLine(); - - sb.AppendFormat("\tMedium type code: {0:X2}h", descriptor.mediumType).AppendLine(); - - if(descriptor.numberOfCodes > 0) - { - sb.AppendFormat("\tMedium supports following density codes:"); - - for(int i = 0; i < descriptor.numberOfCodes; i++) - sb.AppendFormat(" {0:X2}h", descriptor.densityCodes[i]); - - sb.AppendLine(); - } - - sb.AppendFormat("\tMedium has a nominal length of {0} m in a {1} mm width tape", descriptor.length, - descriptor.width / (double)10).AppendLine(); - - sb.AppendFormat("\tMedium description: {0}", descriptor.description).AppendLine(); - sb.AppendLine(); - } - - return sb.ToString(); - } - - public static string PrettifyMediumType(byte[] response) => PrettifyMediumType(DecodeMediumType(response)); - - public struct DensitySupportHeader - { - public ushort length; - public ushort reserved; - public DensitySupportDescriptor[] descriptors; - } - - public struct MediaTypeSupportHeader - { - public ushort length; - public ushort reserved; - public MediaTypeSupportDescriptor[] descriptors; - } - - public struct DensitySupportDescriptor - { - public byte primaryCode; - public byte secondaryCode; - public bool writable; - public bool duplicate; - public bool defaultDensity; - public byte reserved; - public bool lenvalid; - public ushort len; - public uint bpmm; - public ushort width; - public ushort tracks; - public uint capacity; - public string organization; - public string name; - public string description; - } - - public struct MediaTypeSupportDescriptor - { - public byte mediumType; - public byte reserved1; - public ushort len; - public byte numberOfCodes; - public byte[] densityCodes; - public ushort width; - public ushort length; - public byte reserved2; - public byte reserved3; - public string organization; - public string name; - public string description; - } + public struct MediaTypeSupportDescriptor + { + public byte mediumType; + public byte reserved1; + public ushort len; + public byte numberOfCodes; + public byte[] densityCodes; + public ushort width; + public ushort length; + public byte reserved2; + public byte reserved3; + public string organization; + public string name; + public string description; } } \ No newline at end of file diff --git a/SCSI/Sense.cs b/SCSI/Sense.cs index c5be1a5..0d417fd 100644 --- a/SCSI/Sense.cs +++ b/SCSI/Sense.cs @@ -36,1966 +36,1965 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Decoders.ATA; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +public enum SenseType { - public enum SenseType + StandardSense, ExtendedSenseFixedCurrent, ExtendedSenseFixedPast, + ExtendedSenseDescriptorCurrent, ExtendedSenseDescriptorPast, Invalid, + Unknown +} + +public struct DecodedSense +{ + public FixedSense? Fixed; + public DescriptorSense? Descriptor; + public readonly byte ASC => Descriptor?.ASC ?? (Fixed?.ASC ?? 0); + public readonly byte ASCQ => Descriptor?.ASCQ ?? (Fixed?.ASCQ ?? 0); + public readonly SenseKeys SenseKey => Descriptor?.SenseKey ?? (Fixed?.SenseKey ?? SenseKeys.NoSense); + public readonly string Description => Sense.GetSenseDescription(ASC, ASCQ); +} + +[SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "NotAccessedField.Global"), + SuppressMessage("ReSharper", "InconsistentNaming")] +public struct StandardSense +{ + /// If set, is valid + public bool AddressValid; + /// Error class, 0 to 6 + public byte ErrorClass; + /// Error type + public byte ErrorType; + /// Private usage + public byte Private; + /// LBA where error happened + public uint LBA; +} + +public enum SenseKeys : byte +{ + /// No information to be reported, but bits should be checked + NoSense = 0, + /// Target performed some recovery to successfully complete last command + RecoveredError = 1, + /// Target is not ready + NotReady = 2, + /// Non-recoverable medium error occurred + MediumError = 3, + /// Non-recoverable hardware error occurred + HardwareError = 4, + /// Target has received an illegal request + IllegalRequest = 5, + /// Target requires initiator attention + UnitAttention = 6, + /// A protected command has been denied + DataProtect = 7, + /// A blank block has been tried to read or a non-rewritable one to write + BlankCheck = 8, + /// For private/vendor usage + PrivateUse = 9, + /// COPY command aborted + CopyAborted = 0xA, + /// Command aborted + AbortedCommand = 0xB, + /// SEARCH command has been satisfied + Equal = 0xC, + /// End-of-medium reached with data remaining in buffer + VolumeOverflow = 0xD, + /// COMPARE failed + Miscompare = 0xE, + /// Complated + Completed = 0xF +} + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct FixedSense +{ + /// If set, is valid + public bool InformationValid; + /// Contains number of current segment descriptor + public byte SegmentNumber; + /// If set indicates current command has read a filemark or a setmark + public bool Filemark; + /// If set indicates device has arrived end-of-medium + public bool EOM; + /// Means the requested logical block length did not match the logical block length on the medium + public bool ILI; + /// Contains the sense key + public SenseKeys SenseKey; + /// Additional information + public uint Information; + /// Additional sense length + public byte AdditionalLength; + /// Command specific information field + public uint CommandSpecific; + /// Additional sense code + public byte ASC; + /// Additional sense code qualifier + public byte ASCQ; + public byte FieldReplaceable; + /// If set, is valid + public bool SKSV; + public uint SenseKeySpecific; + public byte[] AdditionalSense; +} + +[SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "InconsistentNaming"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct DescriptorSense +{ + /// Contains the sense key + public SenseKeys SenseKey; + /// Additional sense code + public byte ASC; + /// Additional sense code qualifier + public byte ASCQ; + public bool Overflow; + /// The descriptors, indexed by type + public Dictionary Descriptors; +} + +[SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "InconsistentNaming"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public struct AnotherProgressIndicationSenseDescriptor +{ + public SenseKeys SenseKey; + public byte ASC; + public byte ASCQ; + public ushort Progress; +} + +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Sense +{ + /// Gets the SCSI SENSE type to help chosing the correct decoding function + /// The type. + /// Sense bytes. + public static SenseType GetType(byte[] sense) { - StandardSense, ExtendedSenseFixedCurrent, ExtendedSenseFixedPast, - ExtendedSenseDescriptorCurrent, ExtendedSenseDescriptorPast, Invalid, - Unknown + if(sense == null) + return SenseType.Invalid; + + if(sense.Length < 4) + return SenseType.Invalid; + + if((sense[0] & 0x70) != 0x70) + return sense.Length != 4 ? SenseType.Invalid : SenseType.StandardSense; + + switch(sense[0] & 0x0F) + { + case 0: return SenseType.ExtendedSenseFixedCurrent; + case 1: return SenseType.ExtendedSenseFixedPast; + case 2: return SenseType.ExtendedSenseDescriptorCurrent; + case 3: return SenseType.ExtendedSenseDescriptorPast; + default: return SenseType.Unknown; + } } - public struct DecodedSense + public static StandardSense? DecodeStandard(byte[] sense) { - public FixedSense? Fixed; - public DescriptorSense? Descriptor; - public readonly byte ASC => Descriptor?.ASC ?? (Fixed?.ASC ?? 0); - public readonly byte ASCQ => Descriptor?.ASCQ ?? (Fixed?.ASCQ ?? 0); - public readonly SenseKeys SenseKey => Descriptor?.SenseKey ?? (Fixed?.SenseKey ?? SenseKeys.NoSense); - public readonly string Description => Sense.GetSenseDescription(ASC, ASCQ); + if(GetType(sense) != SenseType.StandardSense) + return null; + + var decoded = new StandardSense(); + decoded.AddressValid |= (sense[0] & 0x80) == 0x80; + decoded.ErrorClass = (byte)((sense[0] & 0x70) >> 4); + decoded.ErrorType = (byte)(sense[0] & 0x0F); + decoded.Private = (byte)((sense[1] & 0x80) >> 4); + decoded.LBA = (uint)(((sense[1] & 0x0F) << 16) + (sense[2] << 8) + sense[3]); + + return decoded; } - [SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "NotAccessedField.Global"), - SuppressMessage("ReSharper", "InconsistentNaming")] - public struct StandardSense + public static DecodedSense? Decode(byte[] sense) { - /// If set, is valid - public bool AddressValid; - /// Error class, 0 to 6 - public byte ErrorClass; - /// Error type - public byte ErrorType; - /// Private usage - public byte Private; - /// LBA where error happened - public uint LBA; + var decoded = new DecodedSense(); + + switch(sense[0]) + { + case 0x70: + case 0x71: + decoded.Fixed = DecodeFixed(sense); + + break; + case 0x72: + case 0x73: + decoded.Descriptor = DecodeDescriptor(sense); + + break; + } + + return decoded.Fixed is null && decoded.Descriptor is null ? (DecodedSense?)null : decoded; } - public enum SenseKeys : byte + public static FixedSense? DecodeFixed(byte[] sense) => DecodeFixed(sense, out _); + + public static FixedSense? DecodeFixed(byte[] sense, out string senseDescription) { - /// No information to be reported, but bits should be checked - NoSense = 0, - /// Target performed some recovery to successfully complete last command - RecoveredError = 1, - /// Target is not ready - NotReady = 2, - /// Non-recoverable medium error occurred - MediumError = 3, - /// Non-recoverable hardware error occurred - HardwareError = 4, - /// Target has received an illegal request - IllegalRequest = 5, - /// Target requires initiator attention - UnitAttention = 6, - /// A protected command has been denied - DataProtect = 7, - /// A blank block has been tried to read or a non-rewritable one to write - BlankCheck = 8, - /// For private/vendor usage - PrivateUse = 9, - /// COPY command aborted - CopyAborted = 0xA, - /// Command aborted - AbortedCommand = 0xB, - /// SEARCH command has been satisfied - Equal = 0xC, - /// End-of-medium reached with data remaining in buffer - VolumeOverflow = 0xD, - /// COMPARE failed - Miscompare = 0xE, - /// Complated - Completed = 0xF - } + senseDescription = null; - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct FixedSense - { - /// If set, is valid - public bool InformationValid; - /// Contains number of current segment descriptor - public byte SegmentNumber; - /// If set indicates current command has read a filemark or a setmark - public bool Filemark; - /// If set indicates device has arrived end-of-medium - public bool EOM; - /// Means the requested logical block length did not match the logical block length on the medium - public bool ILI; - /// Contains the sense key - public SenseKeys SenseKey; - /// Additional information - public uint Information; - /// Additional sense length - public byte AdditionalLength; - /// Command specific information field - public uint CommandSpecific; - /// Additional sense code - public byte ASC; - /// Additional sense code qualifier - public byte ASCQ; - public byte FieldReplaceable; - /// If set, is valid - public bool SKSV; - public uint SenseKeySpecific; - public byte[] AdditionalSense; - } + if(sense is null || + sense.Length == 0) + return null; - [SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "InconsistentNaming"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct DescriptorSense - { - /// Contains the sense key - public SenseKeys SenseKey; - /// Additional sense code - public byte ASC; - /// Additional sense code qualifier - public byte ASCQ; - public bool Overflow; - /// The descriptors, indexed by type - public Dictionary Descriptors; - } + if((sense[0] & 0x7F) != 0x70 && + (sense[0] & 0x7F) != 0x71) + return null; - [SuppressMessage("ReSharper", "MemberCanBeInternal"), SuppressMessage("ReSharper", "InconsistentNaming"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public struct AnotherProgressIndicationSenseDescriptor - { - public SenseKeys SenseKey; - public byte ASC; - public byte ASCQ; - public ushort Progress; - } + if(sense.Length < 8) + return null; - [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Sense - { - /// Gets the SCSI SENSE type to help chosing the correct decoding function - /// The type. - /// Sense bytes. - public static SenseType GetType(byte[] sense) + var decoded = new FixedSense { - if(sense == null) - return SenseType.Invalid; - - if(sense.Length < 4) - return SenseType.Invalid; - - if((sense[0] & 0x70) != 0x70) - return sense.Length != 4 ? SenseType.Invalid : SenseType.StandardSense; - - switch(sense[0] & 0x0F) - { - case 0: return SenseType.ExtendedSenseFixedCurrent; - case 1: return SenseType.ExtendedSenseFixedPast; - case 2: return SenseType.ExtendedSenseDescriptorCurrent; - case 3: return SenseType.ExtendedSenseDescriptorPast; - default: return SenseType.Unknown; - } - } - - public static StandardSense? DecodeStandard(byte[] sense) - { - if(GetType(sense) != SenseType.StandardSense) - return null; - - var decoded = new StandardSense(); - decoded.AddressValid |= (sense[0] & 0x80) == 0x80; - decoded.ErrorClass = (byte)((sense[0] & 0x70) >> 4); - decoded.ErrorType = (byte)(sense[0] & 0x0F); - decoded.Private = (byte)((sense[1] & 0x80) >> 4); - decoded.LBA = (uint)(((sense[1] & 0x0F) << 16) + (sense[2] << 8) + sense[3]); - - return decoded; - } - - public static DecodedSense? Decode(byte[] sense) - { - var decoded = new DecodedSense(); - - switch(sense[0]) - { - case 0x70: - case 0x71: - decoded.Fixed = DecodeFixed(sense); - - break; - case 0x72: - case 0x73: - decoded.Descriptor = DecodeDescriptor(sense); - - break; - } - - return decoded.Fixed is null && decoded.Descriptor is null ? (DecodedSense?)null : decoded; - } - - public static FixedSense? DecodeFixed(byte[] sense) => DecodeFixed(sense, out _); - - public static FixedSense? DecodeFixed(byte[] sense, out string senseDescription) - { - senseDescription = null; - - if(sense is null || - sense.Length == 0) - return null; - - if((sense[0] & 0x7F) != 0x70 && - (sense[0] & 0x7F) != 0x71) - return null; - - if(sense.Length < 8) - return null; - - var decoded = new FixedSense - { - InformationValid = (sense[0] & 0x80) == 0x80, - SegmentNumber = sense[1], - Filemark = (sense[2] & 0x80) == 0x80, - EOM = (sense[2] & 0x40) == 0x40, - ILI = (sense[2] & 0x20) == 0x20, - SenseKey = (SenseKeys)(sense[2] & 0x0F), - Information = (uint)((sense[3] << 24) + (sense[4] << 16) + (sense[5] << 8) + sense[6]), - AdditionalLength = sense[7] - }; - - if(sense.Length >= 12) - decoded.CommandSpecific = (uint)((sense[8] << 24) + (sense[9] << 16) + (sense[10] << 8) + sense[11]); - - if(sense.Length >= 14) - { - decoded.ASC = sense[12]; - decoded.ASCQ = sense[13]; - senseDescription = GetSenseDescription(decoded.ASC, decoded.ASCQ); - } - - if(sense.Length >= 15) - decoded.FieldReplaceable = sense[14]; - - if(sense.Length >= 18) - decoded.SenseKeySpecific = (uint)((sense[15] << 16) + (sense[16] << 8) + sense[17]); - - if(sense.Length <= 18) - return decoded; - - decoded.AdditionalSense = new byte[sense.Length - 18]; - Array.Copy(sense, 18, decoded.AdditionalSense, 0, decoded.AdditionalSense.Length); - - return decoded; - } - - public static DescriptorSense? DecodeDescriptor(byte[] sense) => DecodeDescriptor(sense, out _); - - public static DescriptorSense? DecodeDescriptor(byte[] sense, out string senseDescription) - { - senseDescription = null; - - if(sense == null) - return null; - - if(sense.Length < 8) - return null; - - // Fixed sense - if((sense[0] & 0x7F) == 0x70 || - (sense[0] & 0x7F) == 0x71) - return null; - - var decoded = new DescriptorSense - { - SenseKey = (SenseKeys)(sense[1] & 0x0F), - ASC = sense[2], - ASCQ = sense[3], - Overflow = (sense[4] & 0x80) == 0x80, - Descriptors = new Dictionary() - }; - - senseDescription = GetSenseDescription(decoded.ASC, decoded.ASCQ); - - int offset = 8; - - while(offset < sense.Length) - if(offset + 2 < sense.Length) - { - byte descType = sense[offset]; - int descLen = sense[offset + 1] + 2; - - byte[] desc = new byte[descLen]; - - if(offset + descLen >= sense.Length) - descLen = sense.Length - offset; - - Array.Copy(sense, offset, desc, 0, descLen); - - if(!decoded.Descriptors.ContainsKey(descType)) - decoded.Descriptors.Add(descType, desc); - - offset += descLen; - } - else - break; - - return decoded; - } - - public static string PrettifySense(byte[] sense) - { - SenseType type = GetType(sense); - - switch(type) - { - case SenseType.StandardSense: return PrettifySense(DecodeStandard(sense)); - case SenseType.ExtendedSenseFixedCurrent: - case SenseType.ExtendedSenseFixedPast: return PrettifySense(DecodeFixed(sense)); - case SenseType.ExtendedSenseDescriptorCurrent: - case SenseType.ExtendedSenseDescriptorPast: return PrettifySense(DecodeDescriptor(sense)); - default: return null; - } - } - - public static string PrettifySense(StandardSense? sense) - { - if(!sense.HasValue) - return null; - - return sense.Value.AddressValid - ? $"Error class {sense.Value.ErrorClass} type {sense.Value.ErrorType} happened on block {sense.Value.LBA}\n" - : $"Error class {sense.Value.ErrorClass} type {sense.Value.ErrorType}\n"; - } - - public static string PrettifySense(FixedSense? sense) - { - if(!sense.HasValue) - return null; - - FixedSense decoded = sense.Value; - - var sb = new StringBuilder(); - - sb.AppendFormat("SCSI SENSE: {0}", GetSenseKey(decoded.SenseKey)).AppendLine(); - - if(decoded.SegmentNumber > 0) - sb.AppendFormat("On segment {0}", decoded.SegmentNumber).AppendLine(); - - if(decoded.Filemark) - sb.AppendLine("Filemark or setmark found"); - - if(decoded.EOM) - sb.AppendLine("End-of-medium/partition found"); - - if(decoded.ILI) - sb.AppendLine("Incorrect length indicator"); - - if(decoded.InformationValid) - sb.AppendFormat("On logical block {0}", decoded.Information).AppendLine(); - - if(decoded.AdditionalLength < 6) - return sb.ToString(); - - sb.AppendLine(GetSenseDescription(decoded.ASC, decoded.ASCQ)); - - if(decoded.AdditionalLength < 10) - return sb.ToString(); - - if(!decoded.SKSV) - return sb.ToString(); - - switch(decoded.SenseKey) - { - case SenseKeys.IllegalRequest: - { - sb.AppendLine((decoded.SenseKeySpecific & 0x400000) == 0x400000 ? "Illegal field in CDB" - : "Illegal field in data parameters"); - - if((decoded.SenseKeySpecific & 0x200000) == 0x200000) - sb.AppendFormat("Invalid value in bit {0} in field {1} of CDB", - (decoded.SenseKeySpecific & 0x70000) >> 16, decoded.SenseKeySpecific & 0xFFFF). - AppendLine(); - else - sb.AppendFormat("Invalid value in field {0} of CDB", decoded.SenseKeySpecific & 0xFFFF). - AppendLine(); - } - - break; - case SenseKeys.NotReady: - sb.AppendFormat("Format progress {0:P}", (double)(decoded.SenseKeySpecific & 0xFFFF) / 65536). - AppendLine(); - - break; - case SenseKeys.RecoveredError: - case SenseKeys.HardwareError: - case SenseKeys.MediumError: - sb.AppendFormat("Actual retry count is {0}", decoded.SenseKeySpecific & 0xFFFF).AppendLine(); - - break; - } - - return sb.ToString(); - } - - public static string PrettifySense(DescriptorSense? sense) - { - if(!sense.HasValue) - return null; - - DescriptorSense decoded = sense.Value; - - var sb = new StringBuilder(); - - sb.AppendFormat("SCSI SENSE: {0}", GetSenseKey(decoded.SenseKey)).AppendLine(); - sb.AppendLine(GetSenseDescription(decoded.ASC, decoded.ASCQ)); - - if(decoded.Descriptors == null || - decoded.Descriptors.Count == 0) - return sb.ToString(); - - foreach(KeyValuePair kvp in decoded.Descriptors) - switch(kvp.Key) - { - case 0x00: - sb.AppendLine(PrettifyDescriptor00(kvp.Value)); - - break; - } - - return sb.ToString(); - } - - /// Decodes the information sense data descriptor - /// The information value - /// Descriptor. - public static ulong DecodeDescriptor00(byte[] descriptor) - { - if(descriptor.Length != 12 || - descriptor[0] != 0x00) - return 0; - - byte[] temp = new byte[8]; - - temp[0] = descriptor[11]; - temp[1] = descriptor[10]; - temp[2] = descriptor[9]; - temp[3] = descriptor[8]; - temp[4] = descriptor[7]; - temp[5] = descriptor[6]; - temp[6] = descriptor[5]; - temp[7] = descriptor[4]; - - return BitConverter.ToUInt64(temp, 0); - } - - /// Decodes the command-specific information sense data descriptor - /// The command-specific information sense data descriptor. - /// Descriptor. - public static ulong DecodeDescriptor01(byte[] descriptor) - { - if(descriptor.Length != 12 || - descriptor[0] != 0x01) - return 0; - - byte[] temp = new byte[8]; - - temp[0] = descriptor[11]; - temp[1] = descriptor[10]; - temp[2] = descriptor[9]; - temp[3] = descriptor[8]; - temp[4] = descriptor[7]; - temp[5] = descriptor[6]; - temp[6] = descriptor[5]; - temp[7] = descriptor[4]; - - return BitConverter.ToUInt64(temp, 0); - } - - /// Decodes the sense key specific sense data descriptor - /// The sense key specific sense data descriptor. - /// Descriptor. - public static byte[] DecodeDescriptor02(byte[] descriptor) - { - if(descriptor.Length != 8 || - descriptor[0] != 0x02) - return null; - - byte[] temp = new byte[3]; - Array.Copy(descriptor, 4, temp, 0, 3); - - return temp; - } - - /// Decodes the field replaceable unit sense data descriptor - /// The field replaceable unit sense data descriptor. - /// Descriptor. - public static byte DecodeDescriptor03(byte[] descriptor) - { - if(descriptor.Length != 4 || - descriptor[0] != 0x03) - return 0; - - return descriptor[3]; - } - - /// Decodes the another progress indication sense data descriptor - /// The another progress indication sense data descriptor. - /// Descriptor. - public static AnotherProgressIndicationSenseDescriptor? DecodeDescriptor0A(byte[] descriptor) - { - if(descriptor.Length != 8 || - descriptor[0] != 0x0A) - return null; - - return new AnotherProgressIndicationSenseDescriptor - { - SenseKey = (SenseKeys)descriptor[2], - ASC = descriptor[3], - ASCQ = descriptor[4], - Progress = (ushort)((descriptor[6] << 8) + descriptor[7]) - }; - } - - public static void DecodeDescriptor04(byte[] descriptor, out bool filemark, out bool eom, out bool ili) - { - filemark = (descriptor[3] & 0x80) > 0; - eom = (descriptor[3] & 0x40) > 0; - ili = (descriptor[3] & 0x20) > 0; - } - - public static void DecodeDescriptor05(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); - - public static void DecodeDescriptor06(byte[] descriptor) => throw new NotImplementedException("Check OSD"); - - public static void DecodeDescriptor07(byte[] descriptor) => throw new NotImplementedException("Check OSD"); - - public static void DecodeDescriptor08(byte[] descriptor) => throw new NotImplementedException("Check OSD"); - - public static AtaErrorRegistersLba48 DecodeDescriptor09(byte[] descriptor) => new AtaErrorRegistersLba48 - { - Error = descriptor[3], - SectorCount = (ushort)((descriptor[4] << 8) + descriptor[5]), - LbaLowCurrent = descriptor[6], - LbaLowPrevious = descriptor[7], - LbaMidCurrent = descriptor[8], - LbaMidPrevious = descriptor[9], - LbaHighCurrent = descriptor[10], - LbaHighPrevious = descriptor[11], - DeviceHead = descriptor[12], - Status = descriptor[13] + InformationValid = (sense[0] & 0x80) == 0x80, + SegmentNumber = sense[1], + Filemark = (sense[2] & 0x80) == 0x80, + EOM = (sense[2] & 0x40) == 0x40, + ILI = (sense[2] & 0x20) == 0x20, + SenseKey = (SenseKeys)(sense[2] & 0x0F), + Information = (uint)((sense[3] << 24) + (sense[4] << 16) + (sense[5] << 8) + sense[6]), + AdditionalLength = sense[7] }; - public static void DecodeDescriptor0B(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); + if(sense.Length >= 12) + decoded.CommandSpecific = (uint)((sense[8] << 24) + (sense[9] << 16) + (sense[10] << 8) + sense[11]); - public static void DecodeDescriptor0D(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); - - public static string PrettifyDescriptor00(ulong information) => $"On logical block {information}\n"; - - public static string PrettifyDescriptor00(byte[] descriptor) => - PrettifyDescriptor00(DecodeDescriptor00(descriptor)); - - public static string GetSenseKey(SenseKeys key) + if(sense.Length >= 14) { - switch(key) - { - case SenseKeys.AbortedCommand: return "ABORTED COMMAND"; - case SenseKeys.BlankCheck: return "BLANK CHECK"; - case SenseKeys.CopyAborted: return "COPY ABORTED"; - case SenseKeys.DataProtect: return "DATA PROTECT"; - case SenseKeys.Equal: return "EQUAL"; - case SenseKeys.HardwareError: return "HARDWARE ERROR"; - case SenseKeys.IllegalRequest: return "ILLEGAL REQUEST"; - case SenseKeys.MediumError: return "MEDIUM ERROR"; - case SenseKeys.Miscompare: return "MISCOMPARE"; - case SenseKeys.NoSense: return "NO SENSE"; - case SenseKeys.PrivateUse: return "PRIVATE USE"; - case SenseKeys.RecoveredError: return "RECOVERED ERROR"; - case SenseKeys.Completed: return "COMPLETED"; - case SenseKeys.UnitAttention: return "UNIT ATTENTION"; - case SenseKeys.VolumeOverflow: return "VOLUME OVERFLOW"; - default: return "UNKNOWN"; - } + decoded.ASC = sense[12]; + decoded.ASCQ = sense[13]; + senseDescription = GetSenseDescription(decoded.ASC, decoded.ASCQ); } - [SuppressMessage("ReSharper", "InconsistentNaming")] - public static string GetSenseDescription(byte ASC, byte ASCQ) + if(sense.Length >= 15) + decoded.FieldReplaceable = sense[14]; + + if(sense.Length >= 18) + decoded.SenseKeySpecific = (uint)((sense[15] << 16) + (sense[16] << 8) + sense[17]); + + if(sense.Length <= 18) + return decoded; + + decoded.AdditionalSense = new byte[sense.Length - 18]; + Array.Copy(sense, 18, decoded.AdditionalSense, 0, decoded.AdditionalSense.Length); + + return decoded; + } + + public static DescriptorSense? DecodeDescriptor(byte[] sense) => DecodeDescriptor(sense, out _); + + public static DescriptorSense? DecodeDescriptor(byte[] sense, out string senseDescription) + { + senseDescription = null; + + if(sense == null) + return null; + + if(sense.Length < 8) + return null; + + // Fixed sense + if((sense[0] & 0x7F) == 0x70 || + (sense[0] & 0x7F) == 0x71) + return null; + + var decoded = new DescriptorSense { - switch(ASC) + SenseKey = (SenseKeys)(sense[1] & 0x0F), + ASC = sense[2], + ASCQ = sense[3], + Overflow = (sense[4] & 0x80) == 0x80, + Descriptors = new Dictionary() + }; + + senseDescription = GetSenseDescription(decoded.ASC, decoded.ASCQ); + + int offset = 8; + + while(offset < sense.Length) + if(offset + 2 < sense.Length) { - case 0x00: - switch(ASCQ) - { - case 0x00: return "NO ADDITIONAL SENSE INFORMATION"; - case 0x01: return "FILEMARK DETECTED"; - case 0x02: return "END-OF-PARTITION/MEDIUM DETECTED"; - case 0x03: return "SETMARK DETECTED"; - case 0x04: return "BEGINNING-OF-PARTITION/MEDIUM DETECTED"; - case 0x05: return "END-OF-DATA DETECTED"; - case 0x06: return "I/O PROCESS TERMINATED"; - case 0x07: return "PROGRAMMABLE EARLY WARNING DETECTED"; - case 0x11: return "AUDIO PLAY OPERATION IN PROGRESS"; - case 0x12: return "AUDIO PLAY OPERATION PAUSED"; - case 0x13: return "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"; - case 0x14: return "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"; - case 0x15: return "NO CURRENT AUDIO STATUS TO RETURN"; - case 0x16: return "OPERATION IN PROGRESS"; - case 0x17: return "CLEANING REQUESTED"; - case 0x18: return "ERASE OPERATION IN PROGRESS"; - case 0x19: return "LOCATE OPERATION IN PROGRESS"; - case 0x1A: return "REWIND OPERATION IN PROGRESS"; - case 0x1B: return "SET CAPACITY OPERATION IN PROGRESS"; - case 0x1C: return "VERIFY OPERATION IN PROGRESS"; - case 0x1D: return "ATA PASS THROUGH INFORMATION AVAILABLE"; - case 0x1E: return "CONFLICTING SA CREATION REQUEST"; - case 0x1F: return "LOGICAL UNIT TRANSITIONING TO ANOTHER POWER CONDITION"; - case 0x20: return "EXTENDED COPY INFORMATION AVAILABLE"; - case 0x21: return "ATOMIC COMMAND ABORTED DUE TO ACA"; - } + byte descType = sense[offset]; + int descLen = sense[offset + 1] + 2; - break; - case 0x01: - switch(ASCQ) - { - case 0x00: return "NO INDEX/SECTOR SIGNAL"; - } + byte[] desc = new byte[descLen]; - break; - case 0x02: - switch(ASCQ) - { - case 0x00: return "NO SEEK COMPLETE"; - } + if(offset + descLen >= sense.Length) + descLen = sense.Length - offset; - break; - case 0x03: - switch(ASCQ) - { - case 0x00: return "PERIPHERAL DEVICE WRITE FAULT"; - case 0x01: return "NO WRITE CURRENT"; - case 0x02: return "EXCESSIVE WRITE ERRORS"; - } + Array.Copy(sense, offset, desc, 0, descLen); - break; - case 0x04: - switch(ASCQ) - { - case 0x00: return "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"; - case 0x01: return "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"; - case 0x02: return "LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED"; - case 0x03: return "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"; - case 0x04: return "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"; - case 0x05: return "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS"; - case 0x06: return "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS"; - case 0x07: return "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS"; - case 0x08: return "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS"; - case 0x09: return "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS"; - case 0x0A: return "LOGICAL UNIT NOT ACCESSIBLE, ASYMMETRIC ACCESS STATE TRANSITION"; - case 0x0B: return "LOGICAL UNIT NOT ACCESSIBLE, TARGET IN STANDBY STATE"; - case 0x0C: return "LOGICAL UNIT NOT ACCESSIBLE, TARGET PORT IN UNAVAILABLE STATE"; - case 0x0D: return "LOGICAL UNIT NOT READY, STRUCTURE CHECK REQUIRED"; - case 0x0E: return "LOGICAL UNIT NOT READY, SECURITY SESSION IN PROGRESS"; - case 0x10: return "LOGICAL UNIT NOT READY, AUXILIARY MEMORY NOT ACCESSIBLE"; - case 0x11: return "LOGICAL UNIT NOT READY, NOTIFY (ENABLE SPINUP) REQUIRED"; - case 0x12: return "LOGICAL UNIT NOT READY, OFFLINE"; - case 0x13: return "LOGICAL UNIT NOT READY, SA CREATION IN PROGRESS"; - case 0x14: return "LOGICAL UNIT NOT READY, SPACE ALLOCATION IN PROGRESS"; - case 0x15: return "LOGICAL UNIT NOT READY, ROBOTICS DISABLED"; - case 0x16: return "LOGICAL UNIT NOT READY, CONFIGURATION REQUIRED"; - case 0x17: return "LOGICAL UNIT NOT READY, CALIBRATION REQUIRED"; - case 0x18: return "LOGICAL UNIT NOT READY, A DOOR IS OPEN"; - case 0x19: return "LOGICAL UNIT NOT READY, OPERATING IN SEQUENTIAL MODE"; - case 0x1A: return "LOGICAL UNIT NOT READY, START STOP UNIT IN PROGRESS"; - case 0x1B: return "LOGICAL UNIT NOT READY, SANITIZE IN PROGRESS"; - case 0x1C: return "LOGICAL UNIT NOT READY, ADDITIONAL POWER USE NOT YET GRANTED"; - case 0x1D: return "LOGICAL UNIT NOT READY, CONFIGURATION IN PROGRESS"; - case 0x1E: return "LOGICAL UNIT NOT READY, MICROCODE ACTIVATION REQUIRED"; - case 0x1F: return "LOGICAL UNIT NOT READY, MICROCODE DOWNLOAD REQUIRED"; - case 0x20: return "LOGICAL UNIT NOT READY, LOGICAL UNIT RESET REQUIRED"; - case 0x21: return "LOGICAL UNIT NOT READY, HARD RESET REQUIRED"; - case 0x22: return "LOGICAL UNIT NOT READY, POWER CYCLE REQUIRED"; - } + if(!decoded.Descriptors.ContainsKey(descType)) + decoded.Descriptors.Add(descType, desc); - break; - case 0x05: - switch(ASCQ) - { - case 0x00: return "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"; - } - - break; - case 0x06: - switch(ASCQ) - { - case 0x00: return "NO REFERENCE POSITION FOUND"; - } - - break; - case 0x07: - switch(ASCQ) - { - case 0x00: return "MULTIPLE PERIPHERAL DEVICES SELECTED"; - } - - break; - case 0x08: - switch(ASCQ) - { - case 0x00: return "LOGICAL UNIT COMMUNICATION FAILURE"; - case 0x01: return "LOGICAL UNIT COMMUNICATION TIME-OUT"; - case 0x02: return "LOGICAL UNIT COMMUNICATION PARITY ERROR"; - case 0x03: return "LOGICAL UNIT COMMUNICATION CRC ERROR"; - case 0x04: return "UNREACHABLE COPY TARGET"; - } - - break; - case 0x09: - switch(ASCQ) - { - case 0x00: return "TRACK FLOLLOWING ERROR"; - case 0x01: return "TRACKING SERVO FAILURE"; - case 0x02: return "FOCUS SERVO FAILURE"; - case 0x03: return "SPINDLE SERVO FAILURE"; - case 0x04: return "HEAD SELECT FAULT"; - case 0x05: return "VIBRATION INDUCED TRACKING ERROR"; - } - - break; - case 0x0A: - switch(ASCQ) - { - case 0x00: return "ERROR LOG OVERFLOW"; - } - - break; - case 0x0B: - switch(ASCQ) - { - case 0x00: return "WARNING"; - case 0x01: return "WARNING - SPECIFIED TEMPERATURE EXCEEDED"; - case 0x02: return "WARNING - ENCLOSURE DEGRADED"; - case 0x03: return "WARNING - BACKGROUND SELF-TEST FAILED"; - case 0x04: return "WARNING - BACKGROUND PRE-SCAN DETECTED MEDIUM ERROR"; - case 0x05: return "WARNING - BACKGROUND MEDIUM SCAN DETECTED MEDIUM ERROR"; - case 0x06: return "WARNING - NON-VOLATILE CACHE NOW VOLATILE"; - case 0x07: return "WARNING - DEGRADED POWER TO NON-VOLATILE CACHE"; - case 0x08: return "WARNING - POWER LOSS EXPECTED"; - case 0x09: return "WARNING - DEVICE STATISTICS NOTIFICATION ACTIVE"; - case 0x0A: return "WARNING - HIGH CRITICAL TEMPERATURE LIMIT EXCEEDED"; - case 0x0B: return "WARNING - LOW CRITICAL TEMPERATURE LIMIT EXCEEDED"; - case 0x0C: return "WARNING - HIGH OPERATING TEMPERATURE LIMIT EXCEEDED"; - case 0x0D: return "WARNING - LOW OPERATING TEMPERATURE LIMIT EXCEEDED"; - case 0x0E: return "WARNING - HIGH CRITICAL HUMIDITY LIMIT EXCEEDED"; - case 0x0F: return "WARNING - LOW CRITICAL HUMIDITY LIMIT EXCEEDED"; - case 0x10: return "WARNING - HIGH OPERATING HUMIDITY LIMIT EXCEEDED"; - case 0x11: return "WARNING - LOW OPERATING HUMIDITY LIMIT EXCEEDED"; - } - - break; - case 0x0C: - switch(ASCQ) - { - case 0x00: return "WRITE ERROR"; - case 0x01: return "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION"; - case 0x02: return "WRITE ERROR - AUTO REALLOCATION FAILED"; - case 0x03: return "WRITE ERROR - RECOMMENDED REASSIGNMENT"; - case 0x04: return "COMPRESSION CHECK MISCOMPARE ERROR"; - case 0x05: return "DATA EXPANSION OCCURRED DURING COMPRESSION"; - case 0x06: return "BLOCK NOT COMPRESSIBLE"; - case 0x07: return "WRITE ERROR - RECOVERY NEEDED"; - case 0x08: return "WRITE ERROR - RECOVERY FAILED"; - case 0x09: return "WRITE ERROR - LOSS OF STREAMING"; - case 0x0A: return "WRITE ERROR - PADDING BLOCKS ADDED"; - case 0x0B: return "AUXILIARY MEMORY WRITE ERROR"; - case 0x0C: return "WRITE ERROR - UNEXPECTED UNSOLICITED DATA"; - case 0x0D: return "WRITE ERROR - NOT ENOUGH UNSOLICITED DATA"; - case 0x0E: return "MULTIPLE WRITE ERRORS"; - case 0x0F: return "DEFECTS IN ERROR WINDOW"; - case 0x10: return "INCOMPLETE MULTIPLE ATOMIC WRITE OPERATIONS"; - case 0x11: return "WRITE ERROR - RECOVERY SCAN NEEDED"; - case 0x12: return "WRITE ERROR - INSUFFICIENT ZONE RESOURCES"; - } - - break; - case 0x0D: - switch(ASCQ) - { - case 0x00: return "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR"; - case 0x01: return "THIRD PARTY DEVICE FAILURE"; - case 0x02: return "COPY TARGET DEVICE NOT REACHABLE"; - case 0x03: return "INCORRECT COPY TARGET DEVICE TYPE"; - case 0x04: return "COPY TARGET DEVICE DATA UNDERRUN"; - case 0x05: return "COPY TARGET DEVICE DATA OVERRUN"; - } - - break; - case 0x0E: - switch(ASCQ) - { - case 0x00: return "INVALID INFORMATION UNIT"; - case 0x01: return "INFORMATION UNIT TOO SHORT"; - case 0x02: return "INFORMATION UNIT TOO LONG"; - case 0x03: return "INVALID FIELD IN COMMAND INFORMATION UNIT"; - } - - break; - case 0x10: - switch(ASCQ) - { - case 0x00: return "ID CRC OR ECC ERROR"; - case 0x01: return "LOGICAL BLOCK GUARD CHECK FAILED"; - case 0x02: return "LOGICAL BLOCK APPLICATION TAG CHECK FAILED"; - case 0x03: return "LOGICAL BLOCK REFERENCE TAG CHECK FAILED"; - case 0x04: return "LOGICAL BLOCK PROTECTION ERROR ON RECOVER BUFFERED DATA"; - case 0x05: return "LOGICAL BLOCK PROTECTION METHOD ERROR"; - } - - break; - case 0x11: - switch(ASCQ) - { - case 0x00: return "UNRECOVERED READ ERROR"; - case 0x01: return "READ RETRIES EXHAUSTED"; - case 0x02: return "ERROR TOO LONG TO CORRECT"; - case 0x03: return "MULTIPLE READ ERRORS"; - case 0x04: return "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"; - case 0x05: return "L-EC UNCORRECTABLE ERROR"; - case 0x06: return "CIRC UNRECOVERED ERROR"; - case 0x07: return "DATA RESYNCHRONIZATION ERROR"; - case 0x08: return "INCOMPLETE BLOCK READ"; - case 0x09: return "NO GAP FOUND"; - case 0x0A: return "MISCORRECTED ERROR"; - case 0x0B: return "UNRECOVERED READ ERROR - RECOMMENDED REASSIGNMENT"; - case 0x0C: return "UNRECOVERED READ ERROR - RECOMMENDED REWRITE THE DATA"; - case 0x0D: return "DE-COMPRESSION CRC ERROR"; - case 0x0E: return "CANNOT DECOMPRESS USING DECLARED ALGORITHM"; - case 0x0F: return "ERROR READING UPC/EAN NUMBER"; - case 0x10: return "ERROR READING ISRC NUMBER"; - case 0x11: return "READ ERROR - LOSS OF STREAMING"; - case 0x12: return "AUXILIARY MEMORY READ ERROR"; - case 0x13: return "READ ERROR - FAILED RETRANSMISSITION REQUEST"; - case 0x14: return "READ ERROR - LBA MARKED BAD BY APPLICATION CLIENT"; - case 0x15: return "WRITE AFTER SANITIZE REQUIRED"; - } - - break; - case 0x12: - switch(ASCQ) - { - case 0x00: return "ADDRESS MARK NOT FOUND FOR ID FIELD"; - } - - break; - case 0x13: - switch(ASCQ) - { - case 0x00: return "ADDRESS MARK NOT FOUND FOR DATA FIELD"; - } - - break; - case 0x14: - switch(ASCQ) - { - case 0x00: return "RECORDED ENTITY NOT FOUND"; - case 0x01: return "RECORD NOT FOUND"; - case 0x02: return "FILEMARK OR SETMARK NOT FOUND"; - case 0x03: return "END-OF-DATA NOT FOUND"; - case 0x04: return "BLOCK SEQUENCE ERROR"; - case 0x05: return "RECORD NOT FOUND - RECOMMENDAD REASSIGNMENT"; - case 0x06: return "RECORD NOT FOUND - DATA AUTO-REALLOCATED"; - case 0x07: return "LOCATE OPERATION FAILURE"; - } - - break; - case 0x15: - switch(ASCQ) - { - case 0x00: return "RANDOM POSITIONING ERROR"; - case 0x01: return "MECHANICAL POSITIONING ERROR"; - case 0x02: return "POSITIONING ERROR DETECTED BY READ OF MEDIUM"; - } - - break; - case 0x16: - switch(ASCQ) - { - case 0x00: return "DATA SYNCHRONIZATION MARK ERROR"; - case 0x01: return "DATA SYNC ERROR - DATA REWRITTEN"; - case 0x02: return "DATA SYNC ERROR - RECOMMENDED REWRITE"; - case 0x03: return "DATA SYNC ERROR - DATA AUTO-REALLOCATED"; - case 0x04: return "DATA SYNC ERROR - RECOMMENDED REASSIGNMENT"; - } - - break; - case 0x17: - switch(ASCQ) - { - case 0x00: return "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"; - case 0x01: return "RECOVERED DATA WITH RETRIES"; - case 0x02: return "RECOVERED DATA WITH POSITIVE HEAD OFFSET"; - case 0x03: return "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"; - case 0x04: return "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"; - case 0x05: return "RECOVERED DATA USING PREVIOUS SECTOR ID"; - case 0x06: return "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"; - case 0x07: return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REASSIGNMENT"; - case 0x08: return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REWRITE"; - case 0x09: return "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN"; - } - - break; - case 0x18: - switch(ASCQ) - { - case 0x00: return "RECOVERED DATA WITH ERROR CORRECTION APPLIED"; - case 0x01: return "RECOVERED DATA WITH ERROR CORRECTION & RETRIES APPLIED"; - case 0x02: return "RECOVERED DATA - DATA AUTO-REALLOCATED"; - case 0x03: return "RECOVERED DATA WITH CIRC"; - case 0x04: return "RECOVERED DATA WITH L-EC"; - case 0x05: return "RECOVERED DATA - RECOMMENDED REASSIGNMENT"; - case 0x06: return "RECOVERED DATA - RECOMMENDED REWRITE"; - case 0x07: return "RECOVERED DATA WITH ECC - DATA REWRITTEN"; - case 0x08: return "RECOVERED DATA WITH LINKING"; - } - - break; - case 0x19: - switch(ASCQ) - { - case 0x00: return "DEFECT LIST ERROR"; - case 0x01: return "DEFECT LIST NOT AVAILABLE"; - case 0x02: return "DEFECT LIST ERROR IN PRIMARY LIST"; - case 0x03: return "DEFECT LIST ERROR IN GROWN LIST"; - } - - break; - case 0x1A: - switch(ASCQ) - { - case 0x00: return "PARAMETER LIST LENGTH ERROR"; - } - - break; - case 0x1B: - switch(ASCQ) - { - case 0x00: return "SYNCHRONOUS DATA TRANSFER ERROR"; - } - - break; - case 0x1C: - switch(ASCQ) - { - case 0x00: return "DEFECT LIST NOT FOUND"; - case 0x01: return "PRIMARY DEFECT LIST NOT FOUND"; - case 0x02: return "GROWN DEFECT LIST NOT FOUND"; - } - - break; - case 0x1D: - switch(ASCQ) - { - case 0x00: return "MISCOMPARE DURING VERIFY OPERATION"; - case 0x01: return "MISCOMPARE VERIFY OF UNMAPPED LBA"; - } - - break; - case 0x1E: - switch(ASCQ) - { - case 0x00: return "RECOVERED ID WITH ECC CORRECTION"; - } - - break; - case 0x1F: - switch(ASCQ) - { - case 0x00: return "PARTIAL DEFECT LIST TRANSFER"; - } - - break; - case 0x20: - switch(ASCQ) - { - case 0x00: return "INVALID COMMAND OPERATION CODE"; - case 0x01: return "ACCESS DENIED - INITIATOR PENDING-ENROLLED"; - case 0x02: return "ACCESS DENIED - NO ACCESS RIGHTS"; - case 0x03: return "ACCESS DENIED - INVALID MGMT ID KEY"; - case 0x04: return "ILLEGAL COMMAND WHILE IN WRITE CAPABLE STATE"; - case 0x05: return "ILLEGAL COMMAND WHILE IN READ CAPABLE STATE"; - case 0x06: return "ILLEGAL COMMAND WHILE IN EXPLICIT ADDRESS MODE"; - case 0x07: return "ILLEGAL COMMAND WHILE IN IMPLICIT ADDRESS MODE"; - case 0x08: return "ACCESS DENIED - ENROLLMENT CONFLICT"; - case 0x09: return "ACCESS DENIED - INVALID LUN IDENTIFIER"; - case 0x0A: return "ACCESS DENIED - INVALID PROXY TOKEN"; - case 0x0B: return "ACCESS DENIED - ACL LUN CONFLICT"; - case 0x0C: return "ILLEGAL COMMAND WHEN NOT IN APPEND-ONLY MODE"; - } - - break; - case 0x21: - switch(ASCQ) - { - case 0x00: return "LOGICAL BLOCK ADDRESS OUT OF RANGE"; - case 0x01: return "INVALID ELEMENT ADDRESS"; - case 0x02: return "INVALID ADDRESS FOR WRITE"; - case 0x03: return "INVALID WRITE CROSSING LAYER JUMP"; - case 0x04: return "UNALIGNED WRITE COMMAND"; - case 0x05: return "WRITE BOUNDARY VIOLATION"; - case 0x06: return "ATTEMPT TO READ INVALID DATA"; - case 0x07: return "READ BOUNDARY VIOLATION"; - } - - break; - case 0x22: - switch(ASCQ) - { - case 0x00: return "ILLEGAL FUNCTION"; - } - - break; - case 0x23: - switch(ASCQ) - { - case 0x00: return "INVALID TOKEN OPERATION, CAUSE NOT REPORTABLE"; - case 0x01: return "INVALID TOKEN OPERATION, UNSUPPORTED TOKEN TYPE"; - case 0x02: return "INVALID TOKEN OPERATION, REMOTE TOKEN USAGE NOT SUPPORTED"; - case 0x03: return "INVALID TOKEN OPERATION, REMOTE ROD TOKEN CREATION NOT SUPPORTED"; - case 0x04: return "INVALID TOKEN OPERATION, TOKEN UNKNOWN"; - case 0x05: return "INVALID TOKEN OPERATION, TOKEN CORRUPT"; - case 0x06: return "INVALID TOKEN OPERATION, TOKEN REVOKED"; - case 0x07: return "INVALID TOKEN OPERATION, TOKEN EXPIRED"; - case 0x08: return "INVALID TOKEN OPERATION, TOKEN CANCELLED"; - case 0x09: return "INVALID TOKEN OPERATION, TOKEN DELETED"; - case 0x0A: return "INVALID TOKEN OPERATION, INVALID TOKEN LENGTH"; - } - - break; - case 0x24: - switch(ASCQ) - { - case 0x00: return "ILLEGAL FIELD IN CDB"; - case 0x01: return "CDB DECRYPTION ERROR"; - case 0x02: return "INVALID CDB FIELD WHILE IN EXPLICIT BLOCK ADDRESS MODEL"; - case 0x03: return "INVALID CDB FIELD WHILE IN IMPLICIT BLOCK ADDRESS MODEL"; - case 0x04: return "SECURITY AUDIT VALUE FROZEN"; - case 0x05: return "SECURITY WORKING KEY FROZEN"; - case 0x06: return "NONCE NOT UNIQUE"; - case 0x07: return "NONCE TIMESTAMP OUT OF RANGE"; - case 0x08: return "INVALID XCDB"; - } - - break; - case 0x25: - switch(ASCQ) - { - case 0x00: return "LOGICAL UNIT NOT SUPPORTED"; - } - - break; - case 0x26: - switch(ASCQ) - { - case 0x00: return "INVALID FIELD IN PARAMETER LIST"; - case 0x01: return "PARAMETER NOT SUPPORTED"; - case 0x02: return "PARAMETER VALUE INVALID"; - case 0x03: return "THRESHOLD PARAMETERS NOT SUPPORTED"; - case 0x04: return "INVALID RELEASE OF PERSISTENT RESERVATION"; - case 0x05: return "DATA DECRYPTION ERROR"; - case 0x06: return "TOO MANY TARGET DESCRIPTORS"; - case 0x07: return "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE"; - case 0x08: return "TOO MANY SEGMENT DESCRIPTORS"; - case 0x09: return "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE"; - case 0x0A: return "UNEXPECTED INEXACT SEGMENT"; - case 0x0B: return "INLINE DATA LENGTH EXCEEDED"; - case 0x0C: return "INVALID OPERATION FOR COPY SOURCE OR DESTINATION"; - case 0x0D: return "COPY SEGMENT GRANULARITY VIOLATION"; - case 0x0E: return "INVALID PARAMETER WHILE PORT IS ENABLED"; - case 0x0F: return "INVALID DATA-OUT BUFFER INTEGRITY CHECK VALUE"; - case 0x10: return "DATA DECRYPTION KEY FAIL LIMIT REACHED"; - case 0x11: return "INCOMPLETE KEY-ASSOCIATED DATA SET"; - case 0x12: return "VENDOR SPECIFIC KEY REFERENCE NOT FOUND"; - case 0x13: return "APPLICATION TAG MODE PAGE IS INVALID"; - } - - break; - case 0x27: - switch(ASCQ) - { - case 0x00: return "WRITE PROTECTED"; - case 0x01: return "HARDWARE WRITE PROTECTED"; - case 0x02: return "LOGICAL UNIT SOFTWARE WRITE PROTECTED"; - case 0x03: return "ASSOCIATED WRITE PROTECT"; - case 0x04: return "PERSISTENT WRITE PROTECT"; - case 0x05: return "PERMANENT WRITE PROTECT"; - case 0x06: return "CONDITIONAL WRITE PROTECT"; - case 0x07: return "SPACE ALLOCATION FAILED WRITE PROTECT"; - case 0x08: return "ZONE IS READ ONLY"; - } - - break; - case 0x28: - switch(ASCQ) - { - case 0x00: return "NOT READY TO READY CHANGE (MEDIUM MAY HAVE CHANGED)"; - case 0x01: return "IMPORT OR EXPORT ELEMENT ACCESSED"; - case 0x02: return "FORMAT-LAYER MAY HAVE CHANGED"; - case 0x03: return "IMPORT/EXPORT ELEMENT ACCESSED, MEDIUM CHANGED"; - } - - break; - case 0x29: - switch(ASCQ) - { - case 0x00: return "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"; - case 0x01: return "POWER ON OCCURRED"; - case 0x02: return "SCSI BUS RESET OCCURRED"; - case 0x03: return "BUS DEVICE RESET FUNCTION OCCURRED"; - case 0x04: return "DEVICE INTERNAL RESET"; - case 0x05: return "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED"; - case 0x06: return "TRANSCEIVER MODE CHANGED TO LVD"; - case 0x07: return "I_T NEXUS LOSS OCCURRED"; - } - - break; - case 0x2A: - switch(ASCQ) - { - case 0x00: return "PARAMETERS CHANGED"; - case 0x01: return "MODE PARAMETERS CHANGED"; - case 0x02: return "LOG PARAMETERS CHANGED"; - case 0x03: return "RESERVATIONS PREEMPTED"; - case 0x04: return "RESERVATIONS RELEASED"; - case 0x05: return "REGISTRATIONS PREEMPTED"; - case 0x06: return "ASYMMETRIC ACCESS STATE CHANGED"; - case 0x07: return "IMPLICIT ASYMMETRIC ACCESS STATE TRANSITION FAILED"; - case 0x08: return "PRIORITY CHANGED"; - case 0x09: return "CAPACITY DATA HAS CHANGED"; - case 0x0A: return "ERROR HISTORY I_T NEXUS CLEARED"; - case 0x0B: return "ERROR HISTORY SNAPSHOT RELEASED"; - case 0x0C: return "ERROR RECOVERY ATTRIBUTES HAVE CHANGED"; - case 0x0D: return "DATA ENCRYPTION CAPABILITIES CHANGED"; - case 0x10: return "TIMESTAMP CHANGED"; - case 0x11: return "DATA ENCRYPTION PARAMETERS CHANGED BY ANOTHER I_T NEXUS"; - case 0x12: return "DATA ENCRYPTION PARAMETERS CHANGED BY VENDOR SPECIFIC EVENT"; - case 0x13: return "DATA ENCRYPTION KEY INSTANCE COUNTER HAS CHANGED"; - case 0x14: return "SA CREATION CAPABILITIES DATA HAS CHANGED"; - case 0x15: return "MEDIUM REMOVAL PREVENTION PREEMPTED"; - } - - break; - case 0x2B: - switch(ASCQ) - { - case 0x00: return "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"; - } - - break; - case 0x2C: - switch(ASCQ) - { - case 0x00: return "COMMAND SEQUENCE ERROR"; - case 0x01: return "TOO MANY WINDOWS SPECIFIED"; - case 0x02: return "INVALID COMBINATION OF WINDOWS SPECIFIED"; - case 0x03: return "CURRENT PROGRAM AREA IS NOT EMPTY"; - case 0x04: return "CURRENT PROGRAM AREA IS EMPTY"; - case 0x05: return "ILLEGAL POWER CONDITION REQUEST"; - case 0x06: return "PERSISTENT PREVENT CONFLICT"; - case 0x07: return "PREVIOUS BUSY STATUS"; - case 0x08: return "PREVIOUS TASK SET FULL STATUS"; - case 0x09: return "PREVIOUS RESERVATION CONFLICT STATUS"; - case 0x0A: return "PARTITION OR COLLECTION CONTAINS USER OBJECTS"; - case 0x0B: return "NOT RESERVED"; - case 0x0C: return "ORWRITE GENERATION DOES NOT MATCH"; - case 0x0D: return "RESET WRITE POINTER NOT ALLOWED"; - case 0x0E: return "ZONE IS OFFLINE"; - case 0x0F: return "STREAM NOT OPEN"; - case 0x10: return "UNWRITTEN DATA IN ZONE"; - } - - break; - case 0x2D: - switch(ASCQ) - { - case 0x00: return "OVERWRITE ERROR ON UPDATE IN PLACE"; - } - - break; - case 0x2E: - switch(ASCQ) - { - case 0x00: return "INSUFFICIENT TIME FOR OPERATION"; - case 0x01: return "COMMAND TIMEOUT BEFORE PROCESSING"; - case 0x02: return "COMMAND TIMEOUT DURING PROCESSING"; - case 0x03: return "COMMAND TIMEOUT DURING PROCESSING DUE TO ERROR RECOVERY"; - } - - break; - case 0x2F: - switch(ASCQ) - { - case 0x00: return "COMMANDS CLEARED BY ANOTHER INITIATOR"; - case 0x01: return "COMMANDS CLEARED BY POWER LOSS NOTIFICATION"; - case 0x02: return "COMMANDS CLEARED BY DEVICE SERVER"; - case 0x03: return "SOME COMMANDS CLEARED BY QUEUING LAYER EVENT"; - } - - break; - case 0x30: - switch(ASCQ) - { - case 0x00: return "INCOMPATIBLE MEDIUM INSTALLED"; - case 0x01: return "CANNOT READ MEDIUM - UNKNOWN FORMAT"; - case 0x02: return "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"; - case 0x03: return "CLEANING CARTRIDGE INSTALLED"; - case 0x04: return "CANNOT WRITE MEDIUM - UNKNOWN FORMAT"; - case 0x05: return "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT"; - case 0x06: return "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM"; - case 0x07: return "CLEANING FAILURE"; - case 0x08: return "CANNOT WRITE - APPLICATION CODE MISMATCH"; - case 0x09: return "CURRENT SESSION NOT FIXATED FOR APPEND"; - case 0x0A: return "CLEANING REQUEST REJECTED"; - case 0x0C: return "WORM MEDIUM - OVERWRITE ATTEMPTED"; - case 0x0D: return "WORM MEDIUM - INTEGRITY CHECK"; - case 0x10: return "MEDIUM NOT FORMATTED"; - case 0x11: return "INCOMPATIBLE VOLUME TYPE"; - case 0x12: return "INCOMPATIBLE VOLUME QUALIFIER"; - case 0x13: return "CLEANING VOLUME EXPIRED"; - } - - break; - case 0x31: - switch(ASCQ) - { - case 0x00: return "MEDIUM FORMAT CORRUPTED"; - case 0x01: return "FORMAT COMMAND FAILED"; - case 0x02: return "ZONED FORMATTING FAILED DUE TO SPARE LINKING"; - case 0x03: return "SANITIZE COMMAND FAILED"; - } - - break; - case 0x32: - switch(ASCQ) - { - case 0x00: return "NO DEFECT SPARE LOCATION AVAILABLE"; - case 0x01: return "DEFECT LIST UPDATE FAILURE"; - } - - break; - case 0x33: - switch(ASCQ) - { - case 0x00: return "TAPE LENGTH ERROR"; - } - - break; - case 0x34: - switch(ASCQ) - { - case 0x00: return "ENCLOSURE FAILURE"; - } - - break; - case 0x35: - switch(ASCQ) - { - case 0x00: return "ENCLOSURE SERVICES FAILURE"; - case 0x01: return "UNSUPPORTED ENCLOSURE FUNCTION"; - case 0x02: return "ENCLOSURE SERVICES UNAVAILABLE"; - case 0x03: return "ENCLOSURE SERVICES TRANSFER FAILURE"; - case 0x04: return "ENCLOSURE SERVICES TRANSFER REFUSED"; - case 0x05: return "ENCLOSURE SERVICES CHECKSUM ERROR"; - } - - break; - case 0x36: - switch(ASCQ) - { - case 0x00: return "RIBBON, INK, OR TONER FAILURE"; - } - - break; - case 0x37: - switch(ASCQ) - { - case 0x00: return "ROUNDED PARAMETER"; - } - - break; - case 0x38: - switch(ASCQ) - { - case 0x00: return "EVENT STATUS NOTIFICATION"; - case 0x02: return "ESN - POWER MANAGEMENT CLASS EVENT"; - case 0x04: return "ESN - MEDIA CLASS EVENT"; - case 0x06: return "ESN - DEVICE BUSY CLASS EVENT"; - case 0x07: return "THIN PROVISIONING SOFT THRESHOLD REACHED"; - } - - break; - case 0x39: - switch(ASCQ) - { - case 0x00: return "SAVING PARAMETERS NOT SUPPORTED"; - } - - break; - case 0x3A: - switch(ASCQ) - { - case 0x00: return "MEDIUM NOT PRESENT"; - case 0x01: return "MEDIUM NOT PRESENT - TRAY CLOSED"; - case 0x02: return "MEDIUM NOT PRESENT - TRAY OPEN"; - case 0x03: return "MEDIUM NOT PRESENT - LOADABLE"; - case 0x04: return "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE"; - } - - break; - case 0x3B: - switch(ASCQ) - { - case 0x00: return "SEQUENTIAL POSITIONING ERROR"; - case 0x01: return "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"; - case 0x02: return "TAPE POSITION ERROR AT END-OF-MEDIUM"; - case 0x03: return "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"; - case 0x04: return "SLEW FAILURE"; - case 0x05: return "PAPER JAM"; - case 0x06: return "FAILED TO SENSE TOP-OF-FORM"; - case 0x07: return "FAILED TO SENSE BOTTOM-OF-FORM"; - case 0x08: return "REPOSITION ERROR"; - case 0x09: return "READ PAST END OF MEDIUM"; - case 0x0A: return "READ PAST BEGINNING OF MEDIUM"; - case 0x0B: return "POSITION PAST END OF MEDIUM"; - case 0x0C: return "POSITION PAST BEGINNING OF MEDIUM"; - case 0x0D: return "MEDIUM DESTINATION ELEMENT FULL"; - case 0x0E: return "MEDIUM SOURCE ELEMENT EMPTY"; - case 0x0F: return "END OF MEDIUM REACHED"; - case 0x11: return "MEDIUM MAGAZINE NOT ACCESSIBLE"; - case 0x12: return "MEDIUM MAGAZINE REMOVED"; - case 0x13: return "MEDIUM MAGAZINE INSERTED"; - case 0x14: return "MEDIUM MAGAZINE LOCKED"; - case 0x15: return "MEDIUM MAGAZINE UNLOCKED"; - case 0x16: return "MECHANICAL POSITIONING OR CHANGER ERROR"; - case 0x17: return "READ PAST END OF USER OBJECT"; - case 0x18: return "ELEMENT DISABLED"; - case 0x19: return "ELEMENT ENABLED"; - case 0x1A: return "DATA TRANSFER DEVICE REMOVED"; - case 0x1B: return "DATA TRANSFER DEVICE INSERTED"; - case 0x1C: return "TOO MANY LOGICAL OBJECTS ON PARTITION TO SUPPORT OPERATION"; - } - - break; - case 0x3D: - switch(ASCQ) - { - case 0x00: return "INVALID BITS IN IDENTIFY MESSAGE"; - } - - break; - case 0x3E: - switch(ASCQ) - { - case 0x00: return "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"; - case 0x01: return "LOGICAL UNIT FAILURE"; - case 0x02: return "TIMEOUT ON LOGICAL UNIT"; - case 0x03: return "LOGICAL UNIT FAILED SELF-TEST"; - case 0x04: return "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG"; - } - - break; - case 0x3F: - switch(ASCQ) - { - case 0x00: return "TARGET OPERATING CONDITIONS HAVE CHANGED"; - case 0x01: return "MICROCODE HAS BEEN CHANGED"; - case 0x02: return "CHANGED OPERATING DEFINITION"; - case 0x03: return "INQUIRY DATA HAS CHANGED"; - case 0x04: return "COMPONENT DEVICE ATTACHED"; - case 0x05: return "DEVICE IDENTIFIED CHANGED"; - case 0x06: return "REDUNDANCY GROUP CREATED OR MODIFIED"; - case 0x07: return "REDUNDANCY GROUP DELETED"; - case 0x08: return "SPARE CREATED OR MODIFIED"; - case 0x09: return "SPARE DELETED"; - case 0x0A: return "VOLUME SET CREATED OR MODIFIED"; - case 0x0B: return "VOLUME SET DELETED"; - case 0x0C: return "VOLUME SET DEASSIGNED"; - case 0x0D: return "VOLUME SET REASSIGNED"; - case 0x0E: return "REPORTED LUNS DATA HAS CHANGED"; - case 0x0F: return "ECHO BUFFER OVERWRITTEN"; - case 0x10: return "MEDIUM LOADABLE"; - case 0x11: return "MEDIUM AUXILIARY MEMORY ACCESSIBLE"; - case 0x12: return "iSCSI IP ADDRESS ADDED"; - case 0x13: return "iSCSI IP ADDRESS REMOVED"; - case 0x14: return "iSCSI IP ADDRESS CHANGED"; - case 0x15: return "INSPECT REFERRALS SENSE DESCRIPTORS"; - case 0x16: return "MICROCODE HAS BEEN CHANGED WITHOUT RESET"; - case 0x17: return "ZONE TRANSITION TO FULL"; - } - - break; - case 0x40: - switch(ASCQ) - { - case 0x00: return "RAM FAILURE"; - default: return $"DIAGNOSTIC FAILURE ON COMPONENT {ASCQ:X2}h"; - } - case 0x41: - switch(ASCQ) - { - case 0x00: return "DATA PATH FAILURE"; - } - - break; - case 0x42: - switch(ASCQ) - { - case 0x00: return "POWER-ON OR SELF-TEST FAILURE"; - } - - break; - case 0x43: - switch(ASCQ) - { - case 0x00: return "MESSAGE ERROR"; - } - - break; - case 0x44: - switch(ASCQ) - { - case 0x00: return "INTERNAL TARGET FAILURE"; - case 0x01: return "PERSISTENT RESERVATION INFORMATION LOST"; - case 0x71: return "ATA DEVICE FAILED SET FEATURES"; - } - - break; - case 0x45: - switch(ASCQ) - { - case 0x00: return "SELECT OR RESELECT FAILURE"; - } - - break; - case 0x46: - switch(ASCQ) - { - case 0x00: return "UNSUCCESSFUL SOFT RESET"; - } - - break; - case 0x47: - switch(ASCQ) - { - case 0x00: return "SCSI PARITY ERROR"; - case 0x01: return "DATA PHASE CRC ERROR DETECTED"; - case 0x02: return "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE"; - case 0x03: return "INFORMATION UNIT iuCRC ERROR DETECTED"; - case 0x04: return "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED"; - case 0x05: return "PROTOCOL SERVICE CRC ERROR"; - case 0x06: return "PHY TEST FUNCTION IN PROGRESS"; - case 0x7F: return "SOME COMMANDS CLEARED BY iSCSI PROTOCOL EVENT"; - } - - break; - case 0x48: - switch(ASCQ) - { - case 0x00: return "INITIATOR DETECTED ERROR MESSAGE RECEIVED"; - } - - break; - case 0x49: - switch(ASCQ) - { - case 0x00: return "INVALID MESSAGE ERROR"; - } - - break; - case 0x4A: - switch(ASCQ) - { - case 0x00: return "COMMAND PHASE ERROR"; - } - - break; - case 0x4B: - switch(ASCQ) - { - case 0x00: return "DATA PHASE ERROR"; - case 0x01: return "INVALID TARGET PORT TRANSFER TAG RECEIVED"; - case 0x02: return "TOO MUCH WRITE DATA"; - case 0x03: return "ACK/NAK TIMEOUT"; - case 0x04: return "NAK RECEIVED"; - case 0x05: return "DATA OFFSET ERROR"; - case 0x06: return "INITIATOR RESPONSE TIMEOUT"; - case 0x07: return "CONNECTION LOST"; - case 0x08: return "DATA-IN BUFFER OVERFLOW - DATA BUFFER SIZE"; - case 0x09: return "DATA-IN BUFFER OVERFLOW - DATA BUFFER DESCRIPTOR AREA"; - case 0x0A: return "DATA-IN BUFFER ERROR"; - case 0x0B: return "DATA-OUT BUFFER OVERFLOW - DATA BUFFER SIZE"; - case 0x0C: return "DATA-OUT BUFFER OVERFLOW - DATA BUFFER DESCRIPTOR AREA"; - case 0x0D: return "DATA-OUT BUFFER ERROR"; - case 0x0E: return "PCIe FABRIC ERROR"; - case 0x0F: return "PCIe COMPLETION TIMEOUT"; - case 0x10: return "PCIe COMPLETION ABORT"; - case 0x11: return "PCIe POISONED TLP RECEIVED"; - case 0x12: return "PCIe ECRC CHECK FAILED"; - case 0x13: return "PCIe UNSUPPORTED REQUEST"; - case 0x14: return "PCIe ACS VIOLATION"; - case 0x15: return "PCIe TLP PREFIX BLOCKED"; - } - - break; - case 0x4C: - switch(ASCQ) - { - case 0x00: return "LOGICAL UNIT FAILED SELF-CONFIGURATION"; - } - - break; - case 0x4E: return $"OVERLAPPED COMMANDS ATTEMPTED FOR TASK TAG {ASCQ:X2}h"; - case 0x50: - switch(ASCQ) - { - case 0x00: return "WRITE APPEND ERROR"; - case 0x01: return "WRITE APPEND POSITION ERROR"; - case 0x02: return "POSITION ERROR RELATED TO TIMING"; - } - - break; - case 0x51: - switch(ASCQ) - { - case 0x00: return "ERASE FAILURE"; - case 0x01: return "ERASE FAILURE - INCOMPLETE ERASE OPERATION DETECTED"; - } - - break; - case 0x52: - switch(ASCQ) - { - case 0x00: return "CARTRIDGE FAULT"; - } - - break; - case 0x53: - switch(ASCQ) - { - case 0x00: return "MEDIA LOAD OR EJECT FAILED"; - case 0x01: return "UNLOAD TAPE FAILURE"; - case 0x02: return "MEDIUM REMOVAL PREVENTED"; - case 0x03: return "MEDIUM REMOVAL PREVENTED BY DATA TRANSFER ELEMENT"; - case 0x04: return "MEDIUM THREAD OR UNTHREAD FAILURE"; - case 0x05: return "VOLUME IDENTIFIER INVALID"; - case 0x06: return "VOLUME IDENTIFIED MISSING"; - case 0x07: return "DUPLICATE VOLUME IDENTIFIER"; - case 0x08: return "ELEMENT STATUS UNKNOWN"; - case 0x09: return "DATA TRANSFER DEVICE ERROR - LOAD FAILED"; - case 0x0A: return "DATA TRANSFER DEVICE ERROR - UNLOAD FAILED"; - case 0x0B: return "DATA TRANSFER DEVICE ERROR - UNLOAD MISSING"; - case 0x0C: return "DATA TRANSFER DEVICE ERROR - EJECT FAILED"; - case 0x0D: return "DATA TRANSFER DEVICE ERROR - LIBRARY COMMUNICATION FAILED"; - } - - break; - case 0x54: - switch(ASCQ) - { - case 0x00: return "SCSI TO HOST SYSTEM INTERFACE FAILURE"; - } - - break; - case 0x55: - switch(ASCQ) - { - case 0x00: return "SYSTEM RESOURCE FAILURE"; - case 0x01: return "SYSTEM BUFFER FULL"; - case 0x02: return "INSUFFICIENT RESERVATION RESOURCES"; - case 0x03: return "INSUFFICIENT RESOURCES"; - case 0x04: return "INSUFFICIENT REGISTRATION RESOURCES"; - case 0x05: return "INSUFFICIENT ACCESS CONTROL RESOURCES"; - case 0x06: return "AUXILIARY MEMORY OUT OF SPACE"; - case 0x07: return "QUOTA ERROR"; - case 0x08: return "MAXIMUM NUMBER OF SUPPLEMENTAL DECRYPTION KEYS EXCEEDED"; - case 0x09: return "MEDIUM AUXILIARY MEMORY NOT ACCESSIBLE"; - case 0x0A: return "DATA CURRENTLY UNAVAILABLE"; - case 0x0B: return "INSUFFICIENT POWER FOR OPERATION"; - case 0x0C: return "INSUFFICIENT RESOURCES TO CREATE ROD"; - case 0x0D: return "INSUFFICIENT RESOURCES TO CREATE ROD TOKEN"; - case 0x0E: return "INSUFFICIENT ZONE RESOURCES"; - case 0x0F: return "INSUFFICIENT ZONE RESOURCES TO COMPLETE WRITE"; - case 0x10: return "MAXIMUM NUMBER OF STREAMS OPEN"; - } - - break; - case 0x57: - switch(ASCQ) - { - case 0x00: return "UNABLE TO RECOVER TABLE-OF-CONTENTS"; - } - - break; - case 0x58: - switch(ASCQ) - { - case 0x00: return "GENERATION DOES NOT EXIST"; - } - - break; - case 0x59: - switch(ASCQ) - { - case 0x00: return "UPDATED BLOCK READ"; - } - - break; - case 0x5A: - switch(ASCQ) - { - case 0x00: return "OPERATOR REQUEST OR STATE CHANGE INPUT"; - case 0x01: return "OPERATOR MEDIUM REMOVAL REQUEST"; - case 0x02: return "OPERATOR SELECTED WRITE PROTECT"; - case 0x03: return "OPERATOR SELECTED WRITE PERMIT"; - } - - break; - case 0x5B: - switch(ASCQ) - { - case 0x00: return "LOG EXCEPTION"; - case 0x01: return "THRESHOLD CONDITION MET"; - case 0x02: return "LOG COUNTER AT MAXIMUM"; - case 0x03: return "LOG LIST CODES EXHAUSTED"; - } - - break; - case 0x5C: - switch(ASCQ) - { - case 0x00: return "RPL STATUS CHANGE"; - case 0x01: return "SPINDLES SYNCHRONIZED"; - case 0x02: return "SPINDLES NOT SYNCHRONIZED"; - case 0x03: return "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED"; - case 0x10: return "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; - case 0x11: return "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; - case 0x12: return "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; - case 0x13: return "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; - case 0x14: return "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; - case 0x15: return "HARDWARE IMPENDING FAILURE ACCESS TIME TOO HIGH"; - case 0x16: return "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; - case 0x17: return "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS"; - case 0x18: return "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED"; - case 0x19: return "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; - case 0x1A: return "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"; - case 0x1B: return "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"; - case 0x1C: return "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; - case 0x20: return "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; - case 0x21: return "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; - case 0x22: return "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; - case 0x23: return "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; - case 0x24: return "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; - case 0x25: return "CONTROLLER IMPENDING FAILURE ACCESS TIME TOO HIGH"; - case 0x26: return "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH"; - case 0x27: return "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS"; - case 0x28: return "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED"; - case 0x29: return "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE"; - case 0x2A: return "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE"; - case 0x2B: return "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT"; - case 0x2C: return "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; - case 0x30: return "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; - case 0x31: return "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; - case 0x32: return "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; - case 0x33: return "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; - case 0x34: return "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; - case 0x35: return "DATA CHANNEL IMPENDING FAILURE ACCESS TIME TOO HIGH"; - case 0x36: return "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH"; - case 0x37: return "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS"; - case 0x38: return "DATA CHANNEL IMPENDING FAILURE DATA CHANNEL DETECTED"; - case 0x39: return "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE"; - case 0x3A: return "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE"; - case 0x3B: return "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT"; - case 0x3C: return "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; - case 0x40: return "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; - case 0x41: return "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; - case 0x42: return "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; - case 0x43: return "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; - case 0x44: return "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; - case 0x45: return "SERVO IMPENDING FAILURE ACCESS TIME TOO HIGH"; - case 0x46: return "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH"; - case 0x47: return "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS"; - case 0x48: return "SERVO IMPENDING FAILURE SERVO DETECTED"; - case 0x49: return "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE"; - case 0x4A: return "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE"; - case 0x4B: return "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT"; - case 0x4C: return "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; - case 0x50: return "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; - case 0x51: return "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; - case 0x52: return "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; - case 0x53: return "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; - case 0x54: return "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; - case 0x55: return "SPINDLE IMPENDING FAILURE ACCESS TIME TOO HIGH"; - case 0x56: return "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; - case 0x57: return "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS"; - case 0x58: return "SPINDLE IMPENDING FAILURE SPINDLE DETECTED"; - case 0x59: return "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; - case 0x5A: return "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE"; - case 0x5B: return "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT"; - case 0x5C: return "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; - case 0x60: return "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; - case 0x61: return "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; - case 0x62: return "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; - case 0x63: return "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; - case 0x64: return "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; - case 0x65: return "FIRMWARE IMPENDING FAILURE ACCESS TIME TOO HIGH"; - case 0x66: return "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; - case 0x67: return "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS"; - case 0x68: return "FIRMWARE IMPENDING FAILURE FIRMWARE DETECTED"; - case 0x69: return "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; - case 0x6A: return "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"; - case 0x6B: return "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"; - case 0x6C: return "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; - case 0xFF: return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"; - } - - break; - case 0x5E: - switch(ASCQ) - { - case 0x00: return "LOW POWER CONDITION ON"; - case 0x01: return "IDLE CONDITION ACTIVATED BY TIMER"; - case 0x02: return "STANDBY CONDITION ACTIVATED BY TIMER"; - case 0x03: return "IDLE CONDITION ACTIVATED BY COMMAND"; - case 0x04: return "STANDBY CONDITION ACTIVATED BY COMMAND"; - case 0x05: return "IDLE_B CONDITION ACTIVATED BY TIMER"; - case 0x06: return "IDLE_B CONDITION ACTIVATED BY COMMAND"; - case 0x07: return "IDLE_C CONDITION ACTIVATED BY TIMER"; - case 0x08: return "IDLE_C CONDITION ACTIVATED BY COMMAND"; - case 0x09: return "STANDBY_Y CONDITION ACTIVATED BY TIMER"; - case 0x0A: return "STANDBY_Y CONDITION ACTIVATED BY COMMAND"; - case 0x41: return "POWER STATE CHANGED TO ACTIVE"; - case 0x42: return "POWER STATE CHANGED TO IDLE"; - case 0x43: return "POWER STATE CHANGED TO STANDBY"; - case 0x45: return "POWER STATE CHANGED TO SLEEP"; - case 0x47: return "POWER STATE CHANGED TO DEVICE CONTROL"; - } - - break; - case 0x60: - switch(ASCQ) - { - case 0x00: return "LAMP FAILURE"; - } - - break; - case 0x61: - switch(ASCQ) - { - case 0x00: return "VIDEO ACQUISTION ERROR"; - case 0x01: return "UNABLE TO ACQUIRE VIDEO"; - case 0x02: return "OUT OF FOCUS"; - } - - break; - case 0x62: - switch(ASCQ) - { - case 0x00: return "SCAN HEAD POSITIONING ERROR"; - } - - break; - case 0x63: - switch(ASCQ) - { - case 0x00: return "END OF USER AREA ENCOUNTERED ON THIS TRACK"; - case 0x01: return "PACKET DOES NOT FIT IN AVAILABLE SPACE"; - } - - break; - case 0x64: - switch(ASCQ) - { - case 0x00: return "ILLEGAL MODE FOR THIS TRACK"; - case 0x01: return "INVALID PACKET SIZE"; - } - - break; - case 0x65: - switch(ASCQ) - { - case 0x00: return "VOLTAGE FAULT"; - } - - break; - case 0x66: - switch(ASCQ) - { - case 0x00: return "AUTOMATIC DOCUMENT FEEDER COVER UP"; - case 0x01: return "AUTOMATIC DOCUMENT FEEDER LIFT UP"; - case 0x02: return "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER"; - case 0x03: return "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER"; - } - - break; - case 0x67: - switch(ASCQ) - { - case 0x00: return "CONFIGURATION FAILURE"; - case 0x01: return "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED"; - case 0x02: return "ADD LOGICAL UNIT FAILED"; - case 0x03: return "MODIFICATION OF LOGICAL UNIT FAILED"; - case 0x04: return "EXCHANGE OF LOGICAL UNIT FAILED"; - case 0x05: return "REMOVE OF LOGICAL UNIT FAILED"; - case 0x06: return "ATTACHMENT OF LOGICAL UNIT FAILED"; - case 0x07: return "CREATION OF LOGICAL UNIT FAILED"; - case 0x08: return "ASSIGN FAILURE OCCURRED"; - case 0x09: return "MULTIPLY ASSIGNED LOGICAL UNIT"; - case 0x0A: return "SET TARGET PORT GROUPS COMMAND FAILED"; - case 0x0B: return "ATA DEVICE FEATURE NOT ENABLED"; - } - - break; - case 0x68: - switch(ASCQ) - { - case 0x00: return "LOGICAL UNIT NOT CONFIGURED"; - case 0x01: return "SUBSIDIARY LOGICAL UNIT NOT CONFIGURED"; - } - - break; - case 0x69: - switch(ASCQ) - { - case 0x00: return "DATA LOSS ON LOGICAL UNIT"; - case 0x01: return "MULTIPLE LOGICAL UNIT FAILURES"; - case 0x02: return "PARITY/DATA MISMATCH"; - } - - break; - case 0x6A: - switch(ASCQ) - { - case 0x00: return "INFORMATIONAL, REFER TO LOG"; - } - - break; - case 0x6B: - switch(ASCQ) - { - case 0x00: return "STATE CHANGE HAS OCCURRED"; - case 0x01: return "REDUNDANCY LEVEL GOT BETTER"; - case 0x02: return "REDUNDANCY LEVEL GOT WORSE"; - } - - break; - case 0x6C: - switch(ASCQ) - { - case 0x00: return "REBUILD FAILURE OCCURRED"; - } - - break; - case 0x6D: - switch(ASCQ) - { - case 0x00: return "RECALCULATE FAILURE OCCURRED"; - } - - break; - case 0x6E: - switch(ASCQ) - { - case 0x00: return "COMMAND TO LOGICAL UNIT FAILED"; - } - - break; - case 0x6F: - switch(ASCQ) - { - case 0x00: return "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE"; - case 0x01: return "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT"; - case 0x02: return "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED"; - case 0x03: return "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION"; - case 0x04: return "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION"; - case 0x05: return "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR"; - case 0x06: return "INSUFFICIENT BLOCK COUNT FOR BINDING NONCE RECORDING"; - case 0x07: return "CONFLICT IN BINDING NONCE RECORDING"; - } - - break; - case 0x70: return $"DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF {ASCQ:X2}h"; - case 0x71: - switch(ASCQ) - { - case 0x00: return "DECOMPRESSIONG EXCEPTION LONG ALGORITHM ID"; - } - - break; - case 0x72: - switch(ASCQ) - { - case 0x00: return "SESSION FIXATION ERROR"; - case 0x01: return "SESSION FIXATION ERROR WRITING LEAD-IN"; - case 0x02: return "SESSION FIXATION ERROR WRITING LEAD-OUT"; - case 0x03: return "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION"; - case 0x04: return "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK"; - case 0x05: return "NO MORE TRACK RESERVATIONS ALLOWED"; - case 0x06: return "RMZ EXTENSION IS NOT ALLOWED"; - case 0x07: return "NO MORE TEST ZONE EXTENSIONS ARE ALLOWED"; - } - - break; - case 0x73: - switch(ASCQ) - { - case 0x00: return "CD CONTROL ERROR"; - case 0x01: return "POWER CALIBRATION AREA ALMOST FULL"; - case 0x02: return "POWER CALIBRATION AREA IS FULL"; - case 0x03: return "POWER CALIBRATION AREA ERROR"; - case 0x04: return "PROGRAM MEMORY AREA UPDATE FAILURE"; - case 0x05: return "PROGRAM MEMORY AREA IS FULL"; - case 0x06: return "RMA/PMA IS ALMOST FULL"; - case 0x10: return "CURRENT POWER CALIBRATION AREA ALMOST FULL"; - case 0x11: return "CURRENT POWER CALIBRATION AREA IS FULL"; - case 0x17: return "RDZ IS FULL"; - } - - break; - case 0x74: - switch(ASCQ) - { - case 0x00: return "SECURITY ERROR"; - case 0x01: return "UNABLE TO DECRYPT DATA"; - case 0x02: return "UNENCRYPTED DATA ENCOUNTERED WHILE DECRYPTING"; - case 0x03: return "INCORRECT DATA ENCRYPTION KEY"; - case 0x04: return "CRYPTOGRAPHIC INTEGRITY VALIDATION FAILED"; - case 0x05: return "ERROR DECRYPTING DATA"; - case 0x06: return "UNKNOWN SIGNATURE VERIFICATION KEY"; - case 0x07: return "ENCRYPTION PARAMETERS NOT USEABLE"; - case 0x08: return "DIGITAL SIGNATURE VALIDATION FAILURE"; - case 0x09: return "ENCRYPTION MODE MISMATCH ON READ"; - case 0x0A: return "ENCRYPTED BLOCK NOT RAW READ ENABLED"; - case 0x0B: return "INCORRECT ENCRYPTION PARAMETERS"; - case 0x0C: return "UNABLE TO DECRYPT PARAMETER LIST"; - case 0x0D: return "ENCRYPTION ALGORITHM DISABLED"; - case 0x10: return "SA CREATION PARAMETER VALUE INVALID"; - case 0x11: return "SA CREATION PARAMETER VALUE REJECTED"; - case 0x12: return "INVALID SA USAGE"; - case 0x21: return "DATA ENCRYPTION CONFIGURATION PREVENTED"; - case 0x30: return "SA CREATION PARAMETER NOT SUPPORTED"; - case 0x40: return "AUTHENTICATION FAILED"; - case 0x61: return "EXTERNAL DATA ENCRYPTION KEY MANAGER ACCESS ERROR"; - case 0x62: return "EXTERNAL DATA ENCRYPTION KEY MANAGER ERROR"; - case 0x63: return "EXTERNAL DATA ENCRYPTION KEY NOT FOUND"; - case 0x64: return "EXTERNAL DATA ENCRYPTION REQUEST NOT AUTHORIZED"; - case 0x6E: return "EXTERNAL DATA ENCRYPTION CONTROL TIMEOUT"; - case 0x6F: return "EXTERNAL DATA ENCRYPTION CONTROL ERROR"; - case 0x71: return "LOGICAL UNIT ACCESS NOT AUTHORIZED"; - case 0x79: return "SECURITY CONFLICT IN TRANSLATED DEVICE"; - } - - break; + offset += descLen; } + else + break; - return ASC >= 0x80 - ? ASCQ >= 0x80 - ? $"VENDOR-SPECIFIC ASC {ASC:X2}h WITH VENDOR-SPECIFIC ASCQ {ASCQ:X2}h" - : $"VENDOR-SPECIFIC ASC {ASC:X2}h WITH ASCQ {ASCQ:X2}h" - : ASCQ >= 0x80 - ? $"ASC {ASC:X2}h WITH VENDOR-SPECIFIC ASCQ {ASCQ:X2}h" - : $"ASC {ASC:X2}h WITH ASCQ {ASCQ:X2}h"; + return decoded; + } + + public static string PrettifySense(byte[] sense) + { + SenseType type = GetType(sense); + + switch(type) + { + case SenseType.StandardSense: return PrettifySense(DecodeStandard(sense)); + case SenseType.ExtendedSenseFixedCurrent: + case SenseType.ExtendedSenseFixedPast: return PrettifySense(DecodeFixed(sense)); + case SenseType.ExtendedSenseDescriptorCurrent: + case SenseType.ExtendedSenseDescriptorPast: return PrettifySense(DecodeDescriptor(sense)); + default: return null; } } + + public static string PrettifySense(StandardSense? sense) + { + if(!sense.HasValue) + return null; + + return sense.Value.AddressValid + ? $"Error class {sense.Value.ErrorClass} type {sense.Value.ErrorType} happened on block {sense.Value.LBA}\n" + : $"Error class {sense.Value.ErrorClass} type {sense.Value.ErrorType}\n"; + } + + public static string PrettifySense(FixedSense? sense) + { + if(!sense.HasValue) + return null; + + FixedSense decoded = sense.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat("SCSI SENSE: {0}", GetSenseKey(decoded.SenseKey)).AppendLine(); + + if(decoded.SegmentNumber > 0) + sb.AppendFormat("On segment {0}", decoded.SegmentNumber).AppendLine(); + + if(decoded.Filemark) + sb.AppendLine("Filemark or setmark found"); + + if(decoded.EOM) + sb.AppendLine("End-of-medium/partition found"); + + if(decoded.ILI) + sb.AppendLine("Incorrect length indicator"); + + if(decoded.InformationValid) + sb.AppendFormat("On logical block {0}", decoded.Information).AppendLine(); + + if(decoded.AdditionalLength < 6) + return sb.ToString(); + + sb.AppendLine(GetSenseDescription(decoded.ASC, decoded.ASCQ)); + + if(decoded.AdditionalLength < 10) + return sb.ToString(); + + if(!decoded.SKSV) + return sb.ToString(); + + switch(decoded.SenseKey) + { + case SenseKeys.IllegalRequest: + { + sb.AppendLine((decoded.SenseKeySpecific & 0x400000) == 0x400000 ? "Illegal field in CDB" + : "Illegal field in data parameters"); + + if((decoded.SenseKeySpecific & 0x200000) == 0x200000) + sb.AppendFormat("Invalid value in bit {0} in field {1} of CDB", + (decoded.SenseKeySpecific & 0x70000) >> 16, decoded.SenseKeySpecific & 0xFFFF). + AppendLine(); + else + sb.AppendFormat("Invalid value in field {0} of CDB", decoded.SenseKeySpecific & 0xFFFF). + AppendLine(); + } + + break; + case SenseKeys.NotReady: + sb.AppendFormat("Format progress {0:P}", (double)(decoded.SenseKeySpecific & 0xFFFF) / 65536). + AppendLine(); + + break; + case SenseKeys.RecoveredError: + case SenseKeys.HardwareError: + case SenseKeys.MediumError: + sb.AppendFormat("Actual retry count is {0}", decoded.SenseKeySpecific & 0xFFFF).AppendLine(); + + break; + } + + return sb.ToString(); + } + + public static string PrettifySense(DescriptorSense? sense) + { + if(!sense.HasValue) + return null; + + DescriptorSense decoded = sense.Value; + + var sb = new StringBuilder(); + + sb.AppendFormat("SCSI SENSE: {0}", GetSenseKey(decoded.SenseKey)).AppendLine(); + sb.AppendLine(GetSenseDescription(decoded.ASC, decoded.ASCQ)); + + if(decoded.Descriptors == null || + decoded.Descriptors.Count == 0) + return sb.ToString(); + + foreach(KeyValuePair kvp in decoded.Descriptors) + switch(kvp.Key) + { + case 0x00: + sb.AppendLine(PrettifyDescriptor00(kvp.Value)); + + break; + } + + return sb.ToString(); + } + + /// Decodes the information sense data descriptor + /// The information value + /// Descriptor. + public static ulong DecodeDescriptor00(byte[] descriptor) + { + if(descriptor.Length != 12 || + descriptor[0] != 0x00) + return 0; + + byte[] temp = new byte[8]; + + temp[0] = descriptor[11]; + temp[1] = descriptor[10]; + temp[2] = descriptor[9]; + temp[3] = descriptor[8]; + temp[4] = descriptor[7]; + temp[5] = descriptor[6]; + temp[6] = descriptor[5]; + temp[7] = descriptor[4]; + + return BitConverter.ToUInt64(temp, 0); + } + + /// Decodes the command-specific information sense data descriptor + /// The command-specific information sense data descriptor. + /// Descriptor. + public static ulong DecodeDescriptor01(byte[] descriptor) + { + if(descriptor.Length != 12 || + descriptor[0] != 0x01) + return 0; + + byte[] temp = new byte[8]; + + temp[0] = descriptor[11]; + temp[1] = descriptor[10]; + temp[2] = descriptor[9]; + temp[3] = descriptor[8]; + temp[4] = descriptor[7]; + temp[5] = descriptor[6]; + temp[6] = descriptor[5]; + temp[7] = descriptor[4]; + + return BitConverter.ToUInt64(temp, 0); + } + + /// Decodes the sense key specific sense data descriptor + /// The sense key specific sense data descriptor. + /// Descriptor. + public static byte[] DecodeDescriptor02(byte[] descriptor) + { + if(descriptor.Length != 8 || + descriptor[0] != 0x02) + return null; + + byte[] temp = new byte[3]; + Array.Copy(descriptor, 4, temp, 0, 3); + + return temp; + } + + /// Decodes the field replaceable unit sense data descriptor + /// The field replaceable unit sense data descriptor. + /// Descriptor. + public static byte DecodeDescriptor03(byte[] descriptor) + { + if(descriptor.Length != 4 || + descriptor[0] != 0x03) + return 0; + + return descriptor[3]; + } + + /// Decodes the another progress indication sense data descriptor + /// The another progress indication sense data descriptor. + /// Descriptor. + public static AnotherProgressIndicationSenseDescriptor? DecodeDescriptor0A(byte[] descriptor) + { + if(descriptor.Length != 8 || + descriptor[0] != 0x0A) + return null; + + return new AnotherProgressIndicationSenseDescriptor + { + SenseKey = (SenseKeys)descriptor[2], + ASC = descriptor[3], + ASCQ = descriptor[4], + Progress = (ushort)((descriptor[6] << 8) + descriptor[7]) + }; + } + + public static void DecodeDescriptor04(byte[] descriptor, out bool filemark, out bool eom, out bool ili) + { + filemark = (descriptor[3] & 0x80) > 0; + eom = (descriptor[3] & 0x40) > 0; + ili = (descriptor[3] & 0x20) > 0; + } + + public static void DecodeDescriptor05(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); + + public static void DecodeDescriptor06(byte[] descriptor) => throw new NotImplementedException("Check OSD"); + + public static void DecodeDescriptor07(byte[] descriptor) => throw new NotImplementedException("Check OSD"); + + public static void DecodeDescriptor08(byte[] descriptor) => throw new NotImplementedException("Check OSD"); + + public static AtaErrorRegistersLba48 DecodeDescriptor09(byte[] descriptor) => new AtaErrorRegistersLba48 + { + Error = descriptor[3], + SectorCount = (ushort)((descriptor[4] << 8) + descriptor[5]), + LbaLowCurrent = descriptor[6], + LbaLowPrevious = descriptor[7], + LbaMidCurrent = descriptor[8], + LbaMidPrevious = descriptor[9], + LbaHighCurrent = descriptor[10], + LbaHighPrevious = descriptor[11], + DeviceHead = descriptor[12], + Status = descriptor[13] + }; + + public static void DecodeDescriptor0B(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); + + public static void DecodeDescriptor0D(byte[] descriptor) => throw new NotImplementedException("Check SBC-3"); + + public static string PrettifyDescriptor00(ulong information) => $"On logical block {information}\n"; + + public static string PrettifyDescriptor00(byte[] descriptor) => + PrettifyDescriptor00(DecodeDescriptor00(descriptor)); + + public static string GetSenseKey(SenseKeys key) + { + switch(key) + { + case SenseKeys.AbortedCommand: return "ABORTED COMMAND"; + case SenseKeys.BlankCheck: return "BLANK CHECK"; + case SenseKeys.CopyAborted: return "COPY ABORTED"; + case SenseKeys.DataProtect: return "DATA PROTECT"; + case SenseKeys.Equal: return "EQUAL"; + case SenseKeys.HardwareError: return "HARDWARE ERROR"; + case SenseKeys.IllegalRequest: return "ILLEGAL REQUEST"; + case SenseKeys.MediumError: return "MEDIUM ERROR"; + case SenseKeys.Miscompare: return "MISCOMPARE"; + case SenseKeys.NoSense: return "NO SENSE"; + case SenseKeys.PrivateUse: return "PRIVATE USE"; + case SenseKeys.RecoveredError: return "RECOVERED ERROR"; + case SenseKeys.Completed: return "COMPLETED"; + case SenseKeys.UnitAttention: return "UNIT ATTENTION"; + case SenseKeys.VolumeOverflow: return "VOLUME OVERFLOW"; + default: return "UNKNOWN"; + } + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + public static string GetSenseDescription(byte ASC, byte ASCQ) + { + switch(ASC) + { + case 0x00: + switch(ASCQ) + { + case 0x00: return "NO ADDITIONAL SENSE INFORMATION"; + case 0x01: return "FILEMARK DETECTED"; + case 0x02: return "END-OF-PARTITION/MEDIUM DETECTED"; + case 0x03: return "SETMARK DETECTED"; + case 0x04: return "BEGINNING-OF-PARTITION/MEDIUM DETECTED"; + case 0x05: return "END-OF-DATA DETECTED"; + case 0x06: return "I/O PROCESS TERMINATED"; + case 0x07: return "PROGRAMMABLE EARLY WARNING DETECTED"; + case 0x11: return "AUDIO PLAY OPERATION IN PROGRESS"; + case 0x12: return "AUDIO PLAY OPERATION PAUSED"; + case 0x13: return "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED"; + case 0x14: return "AUDIO PLAY OPERATION STOPPED DUE TO ERROR"; + case 0x15: return "NO CURRENT AUDIO STATUS TO RETURN"; + case 0x16: return "OPERATION IN PROGRESS"; + case 0x17: return "CLEANING REQUESTED"; + case 0x18: return "ERASE OPERATION IN PROGRESS"; + case 0x19: return "LOCATE OPERATION IN PROGRESS"; + case 0x1A: return "REWIND OPERATION IN PROGRESS"; + case 0x1B: return "SET CAPACITY OPERATION IN PROGRESS"; + case 0x1C: return "VERIFY OPERATION IN PROGRESS"; + case 0x1D: return "ATA PASS THROUGH INFORMATION AVAILABLE"; + case 0x1E: return "CONFLICTING SA CREATION REQUEST"; + case 0x1F: return "LOGICAL UNIT TRANSITIONING TO ANOTHER POWER CONDITION"; + case 0x20: return "EXTENDED COPY INFORMATION AVAILABLE"; + case 0x21: return "ATOMIC COMMAND ABORTED DUE TO ACA"; + } + + break; + case 0x01: + switch(ASCQ) + { + case 0x00: return "NO INDEX/SECTOR SIGNAL"; + } + + break; + case 0x02: + switch(ASCQ) + { + case 0x00: return "NO SEEK COMPLETE"; + } + + break; + case 0x03: + switch(ASCQ) + { + case 0x00: return "PERIPHERAL DEVICE WRITE FAULT"; + case 0x01: return "NO WRITE CURRENT"; + case 0x02: return "EXCESSIVE WRITE ERRORS"; + } + + break; + case 0x04: + switch(ASCQ) + { + case 0x00: return "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE"; + case 0x01: return "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"; + case 0x02: return "LOGICAL UNIT NOT READY, INITIALIZING COMMAND REQUIRED"; + case 0x03: return "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED"; + case 0x04: return "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS"; + case 0x05: return "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS"; + case 0x06: return "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS"; + case 0x07: return "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS"; + case 0x08: return "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS"; + case 0x09: return "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS"; + case 0x0A: return "LOGICAL UNIT NOT ACCESSIBLE, ASYMMETRIC ACCESS STATE TRANSITION"; + case 0x0B: return "LOGICAL UNIT NOT ACCESSIBLE, TARGET IN STANDBY STATE"; + case 0x0C: return "LOGICAL UNIT NOT ACCESSIBLE, TARGET PORT IN UNAVAILABLE STATE"; + case 0x0D: return "LOGICAL UNIT NOT READY, STRUCTURE CHECK REQUIRED"; + case 0x0E: return "LOGICAL UNIT NOT READY, SECURITY SESSION IN PROGRESS"; + case 0x10: return "LOGICAL UNIT NOT READY, AUXILIARY MEMORY NOT ACCESSIBLE"; + case 0x11: return "LOGICAL UNIT NOT READY, NOTIFY (ENABLE SPINUP) REQUIRED"; + case 0x12: return "LOGICAL UNIT NOT READY, OFFLINE"; + case 0x13: return "LOGICAL UNIT NOT READY, SA CREATION IN PROGRESS"; + case 0x14: return "LOGICAL UNIT NOT READY, SPACE ALLOCATION IN PROGRESS"; + case 0x15: return "LOGICAL UNIT NOT READY, ROBOTICS DISABLED"; + case 0x16: return "LOGICAL UNIT NOT READY, CONFIGURATION REQUIRED"; + case 0x17: return "LOGICAL UNIT NOT READY, CALIBRATION REQUIRED"; + case 0x18: return "LOGICAL UNIT NOT READY, A DOOR IS OPEN"; + case 0x19: return "LOGICAL UNIT NOT READY, OPERATING IN SEQUENTIAL MODE"; + case 0x1A: return "LOGICAL UNIT NOT READY, START STOP UNIT IN PROGRESS"; + case 0x1B: return "LOGICAL UNIT NOT READY, SANITIZE IN PROGRESS"; + case 0x1C: return "LOGICAL UNIT NOT READY, ADDITIONAL POWER USE NOT YET GRANTED"; + case 0x1D: return "LOGICAL UNIT NOT READY, CONFIGURATION IN PROGRESS"; + case 0x1E: return "LOGICAL UNIT NOT READY, MICROCODE ACTIVATION REQUIRED"; + case 0x1F: return "LOGICAL UNIT NOT READY, MICROCODE DOWNLOAD REQUIRED"; + case 0x20: return "LOGICAL UNIT NOT READY, LOGICAL UNIT RESET REQUIRED"; + case 0x21: return "LOGICAL UNIT NOT READY, HARD RESET REQUIRED"; + case 0x22: return "LOGICAL UNIT NOT READY, POWER CYCLE REQUIRED"; + } + + break; + case 0x05: + switch(ASCQ) + { + case 0x00: return "LOGICAL UNIT DOES NOT RESPOND TO SELECTION"; + } + + break; + case 0x06: + switch(ASCQ) + { + case 0x00: return "NO REFERENCE POSITION FOUND"; + } + + break; + case 0x07: + switch(ASCQ) + { + case 0x00: return "MULTIPLE PERIPHERAL DEVICES SELECTED"; + } + + break; + case 0x08: + switch(ASCQ) + { + case 0x00: return "LOGICAL UNIT COMMUNICATION FAILURE"; + case 0x01: return "LOGICAL UNIT COMMUNICATION TIME-OUT"; + case 0x02: return "LOGICAL UNIT COMMUNICATION PARITY ERROR"; + case 0x03: return "LOGICAL UNIT COMMUNICATION CRC ERROR"; + case 0x04: return "UNREACHABLE COPY TARGET"; + } + + break; + case 0x09: + switch(ASCQ) + { + case 0x00: return "TRACK FLOLLOWING ERROR"; + case 0x01: return "TRACKING SERVO FAILURE"; + case 0x02: return "FOCUS SERVO FAILURE"; + case 0x03: return "SPINDLE SERVO FAILURE"; + case 0x04: return "HEAD SELECT FAULT"; + case 0x05: return "VIBRATION INDUCED TRACKING ERROR"; + } + + break; + case 0x0A: + switch(ASCQ) + { + case 0x00: return "ERROR LOG OVERFLOW"; + } + + break; + case 0x0B: + switch(ASCQ) + { + case 0x00: return "WARNING"; + case 0x01: return "WARNING - SPECIFIED TEMPERATURE EXCEEDED"; + case 0x02: return "WARNING - ENCLOSURE DEGRADED"; + case 0x03: return "WARNING - BACKGROUND SELF-TEST FAILED"; + case 0x04: return "WARNING - BACKGROUND PRE-SCAN DETECTED MEDIUM ERROR"; + case 0x05: return "WARNING - BACKGROUND MEDIUM SCAN DETECTED MEDIUM ERROR"; + case 0x06: return "WARNING - NON-VOLATILE CACHE NOW VOLATILE"; + case 0x07: return "WARNING - DEGRADED POWER TO NON-VOLATILE CACHE"; + case 0x08: return "WARNING - POWER LOSS EXPECTED"; + case 0x09: return "WARNING - DEVICE STATISTICS NOTIFICATION ACTIVE"; + case 0x0A: return "WARNING - HIGH CRITICAL TEMPERATURE LIMIT EXCEEDED"; + case 0x0B: return "WARNING - LOW CRITICAL TEMPERATURE LIMIT EXCEEDED"; + case 0x0C: return "WARNING - HIGH OPERATING TEMPERATURE LIMIT EXCEEDED"; + case 0x0D: return "WARNING - LOW OPERATING TEMPERATURE LIMIT EXCEEDED"; + case 0x0E: return "WARNING - HIGH CRITICAL HUMIDITY LIMIT EXCEEDED"; + case 0x0F: return "WARNING - LOW CRITICAL HUMIDITY LIMIT EXCEEDED"; + case 0x10: return "WARNING - HIGH OPERATING HUMIDITY LIMIT EXCEEDED"; + case 0x11: return "WARNING - LOW OPERATING HUMIDITY LIMIT EXCEEDED"; + } + + break; + case 0x0C: + switch(ASCQ) + { + case 0x00: return "WRITE ERROR"; + case 0x01: return "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION"; + case 0x02: return "WRITE ERROR - AUTO REALLOCATION FAILED"; + case 0x03: return "WRITE ERROR - RECOMMENDED REASSIGNMENT"; + case 0x04: return "COMPRESSION CHECK MISCOMPARE ERROR"; + case 0x05: return "DATA EXPANSION OCCURRED DURING COMPRESSION"; + case 0x06: return "BLOCK NOT COMPRESSIBLE"; + case 0x07: return "WRITE ERROR - RECOVERY NEEDED"; + case 0x08: return "WRITE ERROR - RECOVERY FAILED"; + case 0x09: return "WRITE ERROR - LOSS OF STREAMING"; + case 0x0A: return "WRITE ERROR - PADDING BLOCKS ADDED"; + case 0x0B: return "AUXILIARY MEMORY WRITE ERROR"; + case 0x0C: return "WRITE ERROR - UNEXPECTED UNSOLICITED DATA"; + case 0x0D: return "WRITE ERROR - NOT ENOUGH UNSOLICITED DATA"; + case 0x0E: return "MULTIPLE WRITE ERRORS"; + case 0x0F: return "DEFECTS IN ERROR WINDOW"; + case 0x10: return "INCOMPLETE MULTIPLE ATOMIC WRITE OPERATIONS"; + case 0x11: return "WRITE ERROR - RECOVERY SCAN NEEDED"; + case 0x12: return "WRITE ERROR - INSUFFICIENT ZONE RESOURCES"; + } + + break; + case 0x0D: + switch(ASCQ) + { + case 0x00: return "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR"; + case 0x01: return "THIRD PARTY DEVICE FAILURE"; + case 0x02: return "COPY TARGET DEVICE NOT REACHABLE"; + case 0x03: return "INCORRECT COPY TARGET DEVICE TYPE"; + case 0x04: return "COPY TARGET DEVICE DATA UNDERRUN"; + case 0x05: return "COPY TARGET DEVICE DATA OVERRUN"; + } + + break; + case 0x0E: + switch(ASCQ) + { + case 0x00: return "INVALID INFORMATION UNIT"; + case 0x01: return "INFORMATION UNIT TOO SHORT"; + case 0x02: return "INFORMATION UNIT TOO LONG"; + case 0x03: return "INVALID FIELD IN COMMAND INFORMATION UNIT"; + } + + break; + case 0x10: + switch(ASCQ) + { + case 0x00: return "ID CRC OR ECC ERROR"; + case 0x01: return "LOGICAL BLOCK GUARD CHECK FAILED"; + case 0x02: return "LOGICAL BLOCK APPLICATION TAG CHECK FAILED"; + case 0x03: return "LOGICAL BLOCK REFERENCE TAG CHECK FAILED"; + case 0x04: return "LOGICAL BLOCK PROTECTION ERROR ON RECOVER BUFFERED DATA"; + case 0x05: return "LOGICAL BLOCK PROTECTION METHOD ERROR"; + } + + break; + case 0x11: + switch(ASCQ) + { + case 0x00: return "UNRECOVERED READ ERROR"; + case 0x01: return "READ RETRIES EXHAUSTED"; + case 0x02: return "ERROR TOO LONG TO CORRECT"; + case 0x03: return "MULTIPLE READ ERRORS"; + case 0x04: return "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED"; + case 0x05: return "L-EC UNCORRECTABLE ERROR"; + case 0x06: return "CIRC UNRECOVERED ERROR"; + case 0x07: return "DATA RESYNCHRONIZATION ERROR"; + case 0x08: return "INCOMPLETE BLOCK READ"; + case 0x09: return "NO GAP FOUND"; + case 0x0A: return "MISCORRECTED ERROR"; + case 0x0B: return "UNRECOVERED READ ERROR - RECOMMENDED REASSIGNMENT"; + case 0x0C: return "UNRECOVERED READ ERROR - RECOMMENDED REWRITE THE DATA"; + case 0x0D: return "DE-COMPRESSION CRC ERROR"; + case 0x0E: return "CANNOT DECOMPRESS USING DECLARED ALGORITHM"; + case 0x0F: return "ERROR READING UPC/EAN NUMBER"; + case 0x10: return "ERROR READING ISRC NUMBER"; + case 0x11: return "READ ERROR - LOSS OF STREAMING"; + case 0x12: return "AUXILIARY MEMORY READ ERROR"; + case 0x13: return "READ ERROR - FAILED RETRANSMISSITION REQUEST"; + case 0x14: return "READ ERROR - LBA MARKED BAD BY APPLICATION CLIENT"; + case 0x15: return "WRITE AFTER SANITIZE REQUIRED"; + } + + break; + case 0x12: + switch(ASCQ) + { + case 0x00: return "ADDRESS MARK NOT FOUND FOR ID FIELD"; + } + + break; + case 0x13: + switch(ASCQ) + { + case 0x00: return "ADDRESS MARK NOT FOUND FOR DATA FIELD"; + } + + break; + case 0x14: + switch(ASCQ) + { + case 0x00: return "RECORDED ENTITY NOT FOUND"; + case 0x01: return "RECORD NOT FOUND"; + case 0x02: return "FILEMARK OR SETMARK NOT FOUND"; + case 0x03: return "END-OF-DATA NOT FOUND"; + case 0x04: return "BLOCK SEQUENCE ERROR"; + case 0x05: return "RECORD NOT FOUND - RECOMMENDAD REASSIGNMENT"; + case 0x06: return "RECORD NOT FOUND - DATA AUTO-REALLOCATED"; + case 0x07: return "LOCATE OPERATION FAILURE"; + } + + break; + case 0x15: + switch(ASCQ) + { + case 0x00: return "RANDOM POSITIONING ERROR"; + case 0x01: return "MECHANICAL POSITIONING ERROR"; + case 0x02: return "POSITIONING ERROR DETECTED BY READ OF MEDIUM"; + } + + break; + case 0x16: + switch(ASCQ) + { + case 0x00: return "DATA SYNCHRONIZATION MARK ERROR"; + case 0x01: return "DATA SYNC ERROR - DATA REWRITTEN"; + case 0x02: return "DATA SYNC ERROR - RECOMMENDED REWRITE"; + case 0x03: return "DATA SYNC ERROR - DATA AUTO-REALLOCATED"; + case 0x04: return "DATA SYNC ERROR - RECOMMENDED REASSIGNMENT"; + } + + break; + case 0x17: + switch(ASCQ) + { + case 0x00: return "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED"; + case 0x01: return "RECOVERED DATA WITH RETRIES"; + case 0x02: return "RECOVERED DATA WITH POSITIVE HEAD OFFSET"; + case 0x03: return "RECOVERED DATA WITH NEGATIVE HEAD OFFSET"; + case 0x04: return "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED"; + case 0x05: return "RECOVERED DATA USING PREVIOUS SECTOR ID"; + case 0x06: return "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED"; + case 0x07: return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REASSIGNMENT"; + case 0x08: return "RECOVERED DATA WITHOUT ECC - RECOMMENDED REWRITE"; + case 0x09: return "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN"; + } + + break; + case 0x18: + switch(ASCQ) + { + case 0x00: return "RECOVERED DATA WITH ERROR CORRECTION APPLIED"; + case 0x01: return "RECOVERED DATA WITH ERROR CORRECTION & RETRIES APPLIED"; + case 0x02: return "RECOVERED DATA - DATA AUTO-REALLOCATED"; + case 0x03: return "RECOVERED DATA WITH CIRC"; + case 0x04: return "RECOVERED DATA WITH L-EC"; + case 0x05: return "RECOVERED DATA - RECOMMENDED REASSIGNMENT"; + case 0x06: return "RECOVERED DATA - RECOMMENDED REWRITE"; + case 0x07: return "RECOVERED DATA WITH ECC - DATA REWRITTEN"; + case 0x08: return "RECOVERED DATA WITH LINKING"; + } + + break; + case 0x19: + switch(ASCQ) + { + case 0x00: return "DEFECT LIST ERROR"; + case 0x01: return "DEFECT LIST NOT AVAILABLE"; + case 0x02: return "DEFECT LIST ERROR IN PRIMARY LIST"; + case 0x03: return "DEFECT LIST ERROR IN GROWN LIST"; + } + + break; + case 0x1A: + switch(ASCQ) + { + case 0x00: return "PARAMETER LIST LENGTH ERROR"; + } + + break; + case 0x1B: + switch(ASCQ) + { + case 0x00: return "SYNCHRONOUS DATA TRANSFER ERROR"; + } + + break; + case 0x1C: + switch(ASCQ) + { + case 0x00: return "DEFECT LIST NOT FOUND"; + case 0x01: return "PRIMARY DEFECT LIST NOT FOUND"; + case 0x02: return "GROWN DEFECT LIST NOT FOUND"; + } + + break; + case 0x1D: + switch(ASCQ) + { + case 0x00: return "MISCOMPARE DURING VERIFY OPERATION"; + case 0x01: return "MISCOMPARE VERIFY OF UNMAPPED LBA"; + } + + break; + case 0x1E: + switch(ASCQ) + { + case 0x00: return "RECOVERED ID WITH ECC CORRECTION"; + } + + break; + case 0x1F: + switch(ASCQ) + { + case 0x00: return "PARTIAL DEFECT LIST TRANSFER"; + } + + break; + case 0x20: + switch(ASCQ) + { + case 0x00: return "INVALID COMMAND OPERATION CODE"; + case 0x01: return "ACCESS DENIED - INITIATOR PENDING-ENROLLED"; + case 0x02: return "ACCESS DENIED - NO ACCESS RIGHTS"; + case 0x03: return "ACCESS DENIED - INVALID MGMT ID KEY"; + case 0x04: return "ILLEGAL COMMAND WHILE IN WRITE CAPABLE STATE"; + case 0x05: return "ILLEGAL COMMAND WHILE IN READ CAPABLE STATE"; + case 0x06: return "ILLEGAL COMMAND WHILE IN EXPLICIT ADDRESS MODE"; + case 0x07: return "ILLEGAL COMMAND WHILE IN IMPLICIT ADDRESS MODE"; + case 0x08: return "ACCESS DENIED - ENROLLMENT CONFLICT"; + case 0x09: return "ACCESS DENIED - INVALID LUN IDENTIFIER"; + case 0x0A: return "ACCESS DENIED - INVALID PROXY TOKEN"; + case 0x0B: return "ACCESS DENIED - ACL LUN CONFLICT"; + case 0x0C: return "ILLEGAL COMMAND WHEN NOT IN APPEND-ONLY MODE"; + } + + break; + case 0x21: + switch(ASCQ) + { + case 0x00: return "LOGICAL BLOCK ADDRESS OUT OF RANGE"; + case 0x01: return "INVALID ELEMENT ADDRESS"; + case 0x02: return "INVALID ADDRESS FOR WRITE"; + case 0x03: return "INVALID WRITE CROSSING LAYER JUMP"; + case 0x04: return "UNALIGNED WRITE COMMAND"; + case 0x05: return "WRITE BOUNDARY VIOLATION"; + case 0x06: return "ATTEMPT TO READ INVALID DATA"; + case 0x07: return "READ BOUNDARY VIOLATION"; + } + + break; + case 0x22: + switch(ASCQ) + { + case 0x00: return "ILLEGAL FUNCTION"; + } + + break; + case 0x23: + switch(ASCQ) + { + case 0x00: return "INVALID TOKEN OPERATION, CAUSE NOT REPORTABLE"; + case 0x01: return "INVALID TOKEN OPERATION, UNSUPPORTED TOKEN TYPE"; + case 0x02: return "INVALID TOKEN OPERATION, REMOTE TOKEN USAGE NOT SUPPORTED"; + case 0x03: return "INVALID TOKEN OPERATION, REMOTE ROD TOKEN CREATION NOT SUPPORTED"; + case 0x04: return "INVALID TOKEN OPERATION, TOKEN UNKNOWN"; + case 0x05: return "INVALID TOKEN OPERATION, TOKEN CORRUPT"; + case 0x06: return "INVALID TOKEN OPERATION, TOKEN REVOKED"; + case 0x07: return "INVALID TOKEN OPERATION, TOKEN EXPIRED"; + case 0x08: return "INVALID TOKEN OPERATION, TOKEN CANCELLED"; + case 0x09: return "INVALID TOKEN OPERATION, TOKEN DELETED"; + case 0x0A: return "INVALID TOKEN OPERATION, INVALID TOKEN LENGTH"; + } + + break; + case 0x24: + switch(ASCQ) + { + case 0x00: return "ILLEGAL FIELD IN CDB"; + case 0x01: return "CDB DECRYPTION ERROR"; + case 0x02: return "INVALID CDB FIELD WHILE IN EXPLICIT BLOCK ADDRESS MODEL"; + case 0x03: return "INVALID CDB FIELD WHILE IN IMPLICIT BLOCK ADDRESS MODEL"; + case 0x04: return "SECURITY AUDIT VALUE FROZEN"; + case 0x05: return "SECURITY WORKING KEY FROZEN"; + case 0x06: return "NONCE NOT UNIQUE"; + case 0x07: return "NONCE TIMESTAMP OUT OF RANGE"; + case 0x08: return "INVALID XCDB"; + } + + break; + case 0x25: + switch(ASCQ) + { + case 0x00: return "LOGICAL UNIT NOT SUPPORTED"; + } + + break; + case 0x26: + switch(ASCQ) + { + case 0x00: return "INVALID FIELD IN PARAMETER LIST"; + case 0x01: return "PARAMETER NOT SUPPORTED"; + case 0x02: return "PARAMETER VALUE INVALID"; + case 0x03: return "THRESHOLD PARAMETERS NOT SUPPORTED"; + case 0x04: return "INVALID RELEASE OF PERSISTENT RESERVATION"; + case 0x05: return "DATA DECRYPTION ERROR"; + case 0x06: return "TOO MANY TARGET DESCRIPTORS"; + case 0x07: return "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE"; + case 0x08: return "TOO MANY SEGMENT DESCRIPTORS"; + case 0x09: return "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE"; + case 0x0A: return "UNEXPECTED INEXACT SEGMENT"; + case 0x0B: return "INLINE DATA LENGTH EXCEEDED"; + case 0x0C: return "INVALID OPERATION FOR COPY SOURCE OR DESTINATION"; + case 0x0D: return "COPY SEGMENT GRANULARITY VIOLATION"; + case 0x0E: return "INVALID PARAMETER WHILE PORT IS ENABLED"; + case 0x0F: return "INVALID DATA-OUT BUFFER INTEGRITY CHECK VALUE"; + case 0x10: return "DATA DECRYPTION KEY FAIL LIMIT REACHED"; + case 0x11: return "INCOMPLETE KEY-ASSOCIATED DATA SET"; + case 0x12: return "VENDOR SPECIFIC KEY REFERENCE NOT FOUND"; + case 0x13: return "APPLICATION TAG MODE PAGE IS INVALID"; + } + + break; + case 0x27: + switch(ASCQ) + { + case 0x00: return "WRITE PROTECTED"; + case 0x01: return "HARDWARE WRITE PROTECTED"; + case 0x02: return "LOGICAL UNIT SOFTWARE WRITE PROTECTED"; + case 0x03: return "ASSOCIATED WRITE PROTECT"; + case 0x04: return "PERSISTENT WRITE PROTECT"; + case 0x05: return "PERMANENT WRITE PROTECT"; + case 0x06: return "CONDITIONAL WRITE PROTECT"; + case 0x07: return "SPACE ALLOCATION FAILED WRITE PROTECT"; + case 0x08: return "ZONE IS READ ONLY"; + } + + break; + case 0x28: + switch(ASCQ) + { + case 0x00: return "NOT READY TO READY CHANGE (MEDIUM MAY HAVE CHANGED)"; + case 0x01: return "IMPORT OR EXPORT ELEMENT ACCESSED"; + case 0x02: return "FORMAT-LAYER MAY HAVE CHANGED"; + case 0x03: return "IMPORT/EXPORT ELEMENT ACCESSED, MEDIUM CHANGED"; + } + + break; + case 0x29: + switch(ASCQ) + { + case 0x00: return "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"; + case 0x01: return "POWER ON OCCURRED"; + case 0x02: return "SCSI BUS RESET OCCURRED"; + case 0x03: return "BUS DEVICE RESET FUNCTION OCCURRED"; + case 0x04: return "DEVICE INTERNAL RESET"; + case 0x05: return "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED"; + case 0x06: return "TRANSCEIVER MODE CHANGED TO LVD"; + case 0x07: return "I_T NEXUS LOSS OCCURRED"; + } + + break; + case 0x2A: + switch(ASCQ) + { + case 0x00: return "PARAMETERS CHANGED"; + case 0x01: return "MODE PARAMETERS CHANGED"; + case 0x02: return "LOG PARAMETERS CHANGED"; + case 0x03: return "RESERVATIONS PREEMPTED"; + case 0x04: return "RESERVATIONS RELEASED"; + case 0x05: return "REGISTRATIONS PREEMPTED"; + case 0x06: return "ASYMMETRIC ACCESS STATE CHANGED"; + case 0x07: return "IMPLICIT ASYMMETRIC ACCESS STATE TRANSITION FAILED"; + case 0x08: return "PRIORITY CHANGED"; + case 0x09: return "CAPACITY DATA HAS CHANGED"; + case 0x0A: return "ERROR HISTORY I_T NEXUS CLEARED"; + case 0x0B: return "ERROR HISTORY SNAPSHOT RELEASED"; + case 0x0C: return "ERROR RECOVERY ATTRIBUTES HAVE CHANGED"; + case 0x0D: return "DATA ENCRYPTION CAPABILITIES CHANGED"; + case 0x10: return "TIMESTAMP CHANGED"; + case 0x11: return "DATA ENCRYPTION PARAMETERS CHANGED BY ANOTHER I_T NEXUS"; + case 0x12: return "DATA ENCRYPTION PARAMETERS CHANGED BY VENDOR SPECIFIC EVENT"; + case 0x13: return "DATA ENCRYPTION KEY INSTANCE COUNTER HAS CHANGED"; + case 0x14: return "SA CREATION CAPABILITIES DATA HAS CHANGED"; + case 0x15: return "MEDIUM REMOVAL PREVENTION PREEMPTED"; + } + + break; + case 0x2B: + switch(ASCQ) + { + case 0x00: return "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT"; + } + + break; + case 0x2C: + switch(ASCQ) + { + case 0x00: return "COMMAND SEQUENCE ERROR"; + case 0x01: return "TOO MANY WINDOWS SPECIFIED"; + case 0x02: return "INVALID COMBINATION OF WINDOWS SPECIFIED"; + case 0x03: return "CURRENT PROGRAM AREA IS NOT EMPTY"; + case 0x04: return "CURRENT PROGRAM AREA IS EMPTY"; + case 0x05: return "ILLEGAL POWER CONDITION REQUEST"; + case 0x06: return "PERSISTENT PREVENT CONFLICT"; + case 0x07: return "PREVIOUS BUSY STATUS"; + case 0x08: return "PREVIOUS TASK SET FULL STATUS"; + case 0x09: return "PREVIOUS RESERVATION CONFLICT STATUS"; + case 0x0A: return "PARTITION OR COLLECTION CONTAINS USER OBJECTS"; + case 0x0B: return "NOT RESERVED"; + case 0x0C: return "ORWRITE GENERATION DOES NOT MATCH"; + case 0x0D: return "RESET WRITE POINTER NOT ALLOWED"; + case 0x0E: return "ZONE IS OFFLINE"; + case 0x0F: return "STREAM NOT OPEN"; + case 0x10: return "UNWRITTEN DATA IN ZONE"; + } + + break; + case 0x2D: + switch(ASCQ) + { + case 0x00: return "OVERWRITE ERROR ON UPDATE IN PLACE"; + } + + break; + case 0x2E: + switch(ASCQ) + { + case 0x00: return "INSUFFICIENT TIME FOR OPERATION"; + case 0x01: return "COMMAND TIMEOUT BEFORE PROCESSING"; + case 0x02: return "COMMAND TIMEOUT DURING PROCESSING"; + case 0x03: return "COMMAND TIMEOUT DURING PROCESSING DUE TO ERROR RECOVERY"; + } + + break; + case 0x2F: + switch(ASCQ) + { + case 0x00: return "COMMANDS CLEARED BY ANOTHER INITIATOR"; + case 0x01: return "COMMANDS CLEARED BY POWER LOSS NOTIFICATION"; + case 0x02: return "COMMANDS CLEARED BY DEVICE SERVER"; + case 0x03: return "SOME COMMANDS CLEARED BY QUEUING LAYER EVENT"; + } + + break; + case 0x30: + switch(ASCQ) + { + case 0x00: return "INCOMPATIBLE MEDIUM INSTALLED"; + case 0x01: return "CANNOT READ MEDIUM - UNKNOWN FORMAT"; + case 0x02: return "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT"; + case 0x03: return "CLEANING CARTRIDGE INSTALLED"; + case 0x04: return "CANNOT WRITE MEDIUM - UNKNOWN FORMAT"; + case 0x05: return "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT"; + case 0x06: return "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM"; + case 0x07: return "CLEANING FAILURE"; + case 0x08: return "CANNOT WRITE - APPLICATION CODE MISMATCH"; + case 0x09: return "CURRENT SESSION NOT FIXATED FOR APPEND"; + case 0x0A: return "CLEANING REQUEST REJECTED"; + case 0x0C: return "WORM MEDIUM - OVERWRITE ATTEMPTED"; + case 0x0D: return "WORM MEDIUM - INTEGRITY CHECK"; + case 0x10: return "MEDIUM NOT FORMATTED"; + case 0x11: return "INCOMPATIBLE VOLUME TYPE"; + case 0x12: return "INCOMPATIBLE VOLUME QUALIFIER"; + case 0x13: return "CLEANING VOLUME EXPIRED"; + } + + break; + case 0x31: + switch(ASCQ) + { + case 0x00: return "MEDIUM FORMAT CORRUPTED"; + case 0x01: return "FORMAT COMMAND FAILED"; + case 0x02: return "ZONED FORMATTING FAILED DUE TO SPARE LINKING"; + case 0x03: return "SANITIZE COMMAND FAILED"; + } + + break; + case 0x32: + switch(ASCQ) + { + case 0x00: return "NO DEFECT SPARE LOCATION AVAILABLE"; + case 0x01: return "DEFECT LIST UPDATE FAILURE"; + } + + break; + case 0x33: + switch(ASCQ) + { + case 0x00: return "TAPE LENGTH ERROR"; + } + + break; + case 0x34: + switch(ASCQ) + { + case 0x00: return "ENCLOSURE FAILURE"; + } + + break; + case 0x35: + switch(ASCQ) + { + case 0x00: return "ENCLOSURE SERVICES FAILURE"; + case 0x01: return "UNSUPPORTED ENCLOSURE FUNCTION"; + case 0x02: return "ENCLOSURE SERVICES UNAVAILABLE"; + case 0x03: return "ENCLOSURE SERVICES TRANSFER FAILURE"; + case 0x04: return "ENCLOSURE SERVICES TRANSFER REFUSED"; + case 0x05: return "ENCLOSURE SERVICES CHECKSUM ERROR"; + } + + break; + case 0x36: + switch(ASCQ) + { + case 0x00: return "RIBBON, INK, OR TONER FAILURE"; + } + + break; + case 0x37: + switch(ASCQ) + { + case 0x00: return "ROUNDED PARAMETER"; + } + + break; + case 0x38: + switch(ASCQ) + { + case 0x00: return "EVENT STATUS NOTIFICATION"; + case 0x02: return "ESN - POWER MANAGEMENT CLASS EVENT"; + case 0x04: return "ESN - MEDIA CLASS EVENT"; + case 0x06: return "ESN - DEVICE BUSY CLASS EVENT"; + case 0x07: return "THIN PROVISIONING SOFT THRESHOLD REACHED"; + } + + break; + case 0x39: + switch(ASCQ) + { + case 0x00: return "SAVING PARAMETERS NOT SUPPORTED"; + } + + break; + case 0x3A: + switch(ASCQ) + { + case 0x00: return "MEDIUM NOT PRESENT"; + case 0x01: return "MEDIUM NOT PRESENT - TRAY CLOSED"; + case 0x02: return "MEDIUM NOT PRESENT - TRAY OPEN"; + case 0x03: return "MEDIUM NOT PRESENT - LOADABLE"; + case 0x04: return "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE"; + } + + break; + case 0x3B: + switch(ASCQ) + { + case 0x00: return "SEQUENTIAL POSITIONING ERROR"; + case 0x01: return "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM"; + case 0x02: return "TAPE POSITION ERROR AT END-OF-MEDIUM"; + case 0x03: return "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY"; + case 0x04: return "SLEW FAILURE"; + case 0x05: return "PAPER JAM"; + case 0x06: return "FAILED TO SENSE TOP-OF-FORM"; + case 0x07: return "FAILED TO SENSE BOTTOM-OF-FORM"; + case 0x08: return "REPOSITION ERROR"; + case 0x09: return "READ PAST END OF MEDIUM"; + case 0x0A: return "READ PAST BEGINNING OF MEDIUM"; + case 0x0B: return "POSITION PAST END OF MEDIUM"; + case 0x0C: return "POSITION PAST BEGINNING OF MEDIUM"; + case 0x0D: return "MEDIUM DESTINATION ELEMENT FULL"; + case 0x0E: return "MEDIUM SOURCE ELEMENT EMPTY"; + case 0x0F: return "END OF MEDIUM REACHED"; + case 0x11: return "MEDIUM MAGAZINE NOT ACCESSIBLE"; + case 0x12: return "MEDIUM MAGAZINE REMOVED"; + case 0x13: return "MEDIUM MAGAZINE INSERTED"; + case 0x14: return "MEDIUM MAGAZINE LOCKED"; + case 0x15: return "MEDIUM MAGAZINE UNLOCKED"; + case 0x16: return "MECHANICAL POSITIONING OR CHANGER ERROR"; + case 0x17: return "READ PAST END OF USER OBJECT"; + case 0x18: return "ELEMENT DISABLED"; + case 0x19: return "ELEMENT ENABLED"; + case 0x1A: return "DATA TRANSFER DEVICE REMOVED"; + case 0x1B: return "DATA TRANSFER DEVICE INSERTED"; + case 0x1C: return "TOO MANY LOGICAL OBJECTS ON PARTITION TO SUPPORT OPERATION"; + } + + break; + case 0x3D: + switch(ASCQ) + { + case 0x00: return "INVALID BITS IN IDENTIFY MESSAGE"; + } + + break; + case 0x3E: + switch(ASCQ) + { + case 0x00: return "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET"; + case 0x01: return "LOGICAL UNIT FAILURE"; + case 0x02: return "TIMEOUT ON LOGICAL UNIT"; + case 0x03: return "LOGICAL UNIT FAILED SELF-TEST"; + case 0x04: return "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG"; + } + + break; + case 0x3F: + switch(ASCQ) + { + case 0x00: return "TARGET OPERATING CONDITIONS HAVE CHANGED"; + case 0x01: return "MICROCODE HAS BEEN CHANGED"; + case 0x02: return "CHANGED OPERATING DEFINITION"; + case 0x03: return "INQUIRY DATA HAS CHANGED"; + case 0x04: return "COMPONENT DEVICE ATTACHED"; + case 0x05: return "DEVICE IDENTIFIED CHANGED"; + case 0x06: return "REDUNDANCY GROUP CREATED OR MODIFIED"; + case 0x07: return "REDUNDANCY GROUP DELETED"; + case 0x08: return "SPARE CREATED OR MODIFIED"; + case 0x09: return "SPARE DELETED"; + case 0x0A: return "VOLUME SET CREATED OR MODIFIED"; + case 0x0B: return "VOLUME SET DELETED"; + case 0x0C: return "VOLUME SET DEASSIGNED"; + case 0x0D: return "VOLUME SET REASSIGNED"; + case 0x0E: return "REPORTED LUNS DATA HAS CHANGED"; + case 0x0F: return "ECHO BUFFER OVERWRITTEN"; + case 0x10: return "MEDIUM LOADABLE"; + case 0x11: return "MEDIUM AUXILIARY MEMORY ACCESSIBLE"; + case 0x12: return "iSCSI IP ADDRESS ADDED"; + case 0x13: return "iSCSI IP ADDRESS REMOVED"; + case 0x14: return "iSCSI IP ADDRESS CHANGED"; + case 0x15: return "INSPECT REFERRALS SENSE DESCRIPTORS"; + case 0x16: return "MICROCODE HAS BEEN CHANGED WITHOUT RESET"; + case 0x17: return "ZONE TRANSITION TO FULL"; + } + + break; + case 0x40: + switch(ASCQ) + { + case 0x00: return "RAM FAILURE"; + default: return $"DIAGNOSTIC FAILURE ON COMPONENT {ASCQ:X2}h"; + } + case 0x41: + switch(ASCQ) + { + case 0x00: return "DATA PATH FAILURE"; + } + + break; + case 0x42: + switch(ASCQ) + { + case 0x00: return "POWER-ON OR SELF-TEST FAILURE"; + } + + break; + case 0x43: + switch(ASCQ) + { + case 0x00: return "MESSAGE ERROR"; + } + + break; + case 0x44: + switch(ASCQ) + { + case 0x00: return "INTERNAL TARGET FAILURE"; + case 0x01: return "PERSISTENT RESERVATION INFORMATION LOST"; + case 0x71: return "ATA DEVICE FAILED SET FEATURES"; + } + + break; + case 0x45: + switch(ASCQ) + { + case 0x00: return "SELECT OR RESELECT FAILURE"; + } + + break; + case 0x46: + switch(ASCQ) + { + case 0x00: return "UNSUCCESSFUL SOFT RESET"; + } + + break; + case 0x47: + switch(ASCQ) + { + case 0x00: return "SCSI PARITY ERROR"; + case 0x01: return "DATA PHASE CRC ERROR DETECTED"; + case 0x02: return "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE"; + case 0x03: return "INFORMATION UNIT iuCRC ERROR DETECTED"; + case 0x04: return "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED"; + case 0x05: return "PROTOCOL SERVICE CRC ERROR"; + case 0x06: return "PHY TEST FUNCTION IN PROGRESS"; + case 0x7F: return "SOME COMMANDS CLEARED BY iSCSI PROTOCOL EVENT"; + } + + break; + case 0x48: + switch(ASCQ) + { + case 0x00: return "INITIATOR DETECTED ERROR MESSAGE RECEIVED"; + } + + break; + case 0x49: + switch(ASCQ) + { + case 0x00: return "INVALID MESSAGE ERROR"; + } + + break; + case 0x4A: + switch(ASCQ) + { + case 0x00: return "COMMAND PHASE ERROR"; + } + + break; + case 0x4B: + switch(ASCQ) + { + case 0x00: return "DATA PHASE ERROR"; + case 0x01: return "INVALID TARGET PORT TRANSFER TAG RECEIVED"; + case 0x02: return "TOO MUCH WRITE DATA"; + case 0x03: return "ACK/NAK TIMEOUT"; + case 0x04: return "NAK RECEIVED"; + case 0x05: return "DATA OFFSET ERROR"; + case 0x06: return "INITIATOR RESPONSE TIMEOUT"; + case 0x07: return "CONNECTION LOST"; + case 0x08: return "DATA-IN BUFFER OVERFLOW - DATA BUFFER SIZE"; + case 0x09: return "DATA-IN BUFFER OVERFLOW - DATA BUFFER DESCRIPTOR AREA"; + case 0x0A: return "DATA-IN BUFFER ERROR"; + case 0x0B: return "DATA-OUT BUFFER OVERFLOW - DATA BUFFER SIZE"; + case 0x0C: return "DATA-OUT BUFFER OVERFLOW - DATA BUFFER DESCRIPTOR AREA"; + case 0x0D: return "DATA-OUT BUFFER ERROR"; + case 0x0E: return "PCIe FABRIC ERROR"; + case 0x0F: return "PCIe COMPLETION TIMEOUT"; + case 0x10: return "PCIe COMPLETION ABORT"; + case 0x11: return "PCIe POISONED TLP RECEIVED"; + case 0x12: return "PCIe ECRC CHECK FAILED"; + case 0x13: return "PCIe UNSUPPORTED REQUEST"; + case 0x14: return "PCIe ACS VIOLATION"; + case 0x15: return "PCIe TLP PREFIX BLOCKED"; + } + + break; + case 0x4C: + switch(ASCQ) + { + case 0x00: return "LOGICAL UNIT FAILED SELF-CONFIGURATION"; + } + + break; + case 0x4E: return $"OVERLAPPED COMMANDS ATTEMPTED FOR TASK TAG {ASCQ:X2}h"; + case 0x50: + switch(ASCQ) + { + case 0x00: return "WRITE APPEND ERROR"; + case 0x01: return "WRITE APPEND POSITION ERROR"; + case 0x02: return "POSITION ERROR RELATED TO TIMING"; + } + + break; + case 0x51: + switch(ASCQ) + { + case 0x00: return "ERASE FAILURE"; + case 0x01: return "ERASE FAILURE - INCOMPLETE ERASE OPERATION DETECTED"; + } + + break; + case 0x52: + switch(ASCQ) + { + case 0x00: return "CARTRIDGE FAULT"; + } + + break; + case 0x53: + switch(ASCQ) + { + case 0x00: return "MEDIA LOAD OR EJECT FAILED"; + case 0x01: return "UNLOAD TAPE FAILURE"; + case 0x02: return "MEDIUM REMOVAL PREVENTED"; + case 0x03: return "MEDIUM REMOVAL PREVENTED BY DATA TRANSFER ELEMENT"; + case 0x04: return "MEDIUM THREAD OR UNTHREAD FAILURE"; + case 0x05: return "VOLUME IDENTIFIER INVALID"; + case 0x06: return "VOLUME IDENTIFIED MISSING"; + case 0x07: return "DUPLICATE VOLUME IDENTIFIER"; + case 0x08: return "ELEMENT STATUS UNKNOWN"; + case 0x09: return "DATA TRANSFER DEVICE ERROR - LOAD FAILED"; + case 0x0A: return "DATA TRANSFER DEVICE ERROR - UNLOAD FAILED"; + case 0x0B: return "DATA TRANSFER DEVICE ERROR - UNLOAD MISSING"; + case 0x0C: return "DATA TRANSFER DEVICE ERROR - EJECT FAILED"; + case 0x0D: return "DATA TRANSFER DEVICE ERROR - LIBRARY COMMUNICATION FAILED"; + } + + break; + case 0x54: + switch(ASCQ) + { + case 0x00: return "SCSI TO HOST SYSTEM INTERFACE FAILURE"; + } + + break; + case 0x55: + switch(ASCQ) + { + case 0x00: return "SYSTEM RESOURCE FAILURE"; + case 0x01: return "SYSTEM BUFFER FULL"; + case 0x02: return "INSUFFICIENT RESERVATION RESOURCES"; + case 0x03: return "INSUFFICIENT RESOURCES"; + case 0x04: return "INSUFFICIENT REGISTRATION RESOURCES"; + case 0x05: return "INSUFFICIENT ACCESS CONTROL RESOURCES"; + case 0x06: return "AUXILIARY MEMORY OUT OF SPACE"; + case 0x07: return "QUOTA ERROR"; + case 0x08: return "MAXIMUM NUMBER OF SUPPLEMENTAL DECRYPTION KEYS EXCEEDED"; + case 0x09: return "MEDIUM AUXILIARY MEMORY NOT ACCESSIBLE"; + case 0x0A: return "DATA CURRENTLY UNAVAILABLE"; + case 0x0B: return "INSUFFICIENT POWER FOR OPERATION"; + case 0x0C: return "INSUFFICIENT RESOURCES TO CREATE ROD"; + case 0x0D: return "INSUFFICIENT RESOURCES TO CREATE ROD TOKEN"; + case 0x0E: return "INSUFFICIENT ZONE RESOURCES"; + case 0x0F: return "INSUFFICIENT ZONE RESOURCES TO COMPLETE WRITE"; + case 0x10: return "MAXIMUM NUMBER OF STREAMS OPEN"; + } + + break; + case 0x57: + switch(ASCQ) + { + case 0x00: return "UNABLE TO RECOVER TABLE-OF-CONTENTS"; + } + + break; + case 0x58: + switch(ASCQ) + { + case 0x00: return "GENERATION DOES NOT EXIST"; + } + + break; + case 0x59: + switch(ASCQ) + { + case 0x00: return "UPDATED BLOCK READ"; + } + + break; + case 0x5A: + switch(ASCQ) + { + case 0x00: return "OPERATOR REQUEST OR STATE CHANGE INPUT"; + case 0x01: return "OPERATOR MEDIUM REMOVAL REQUEST"; + case 0x02: return "OPERATOR SELECTED WRITE PROTECT"; + case 0x03: return "OPERATOR SELECTED WRITE PERMIT"; + } + + break; + case 0x5B: + switch(ASCQ) + { + case 0x00: return "LOG EXCEPTION"; + case 0x01: return "THRESHOLD CONDITION MET"; + case 0x02: return "LOG COUNTER AT MAXIMUM"; + case 0x03: return "LOG LIST CODES EXHAUSTED"; + } + + break; + case 0x5C: + switch(ASCQ) + { + case 0x00: return "RPL STATUS CHANGE"; + case 0x01: return "SPINDLES SYNCHRONIZED"; + case 0x02: return "SPINDLES NOT SYNCHRONIZED"; + case 0x03: return "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED"; + case 0x10: return "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x11: return "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x12: return "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x13: return "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x14: return "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x15: return "HARDWARE IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x16: return "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x17: return "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x18: return "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED"; + case 0x19: return "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x1A: return "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x1B: return "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x1C: return "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x20: return "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x21: return "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x22: return "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x23: return "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x24: return "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x25: return "CONTROLLER IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x26: return "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x27: return "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x28: return "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED"; + case 0x29: return "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x2A: return "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x2B: return "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x2C: return "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x30: return "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x31: return "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x32: return "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x33: return "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x34: return "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x35: return "DATA CHANNEL IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x36: return "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x37: return "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x38: return "DATA CHANNEL IMPENDING FAILURE DATA CHANNEL DETECTED"; + case 0x39: return "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x3A: return "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x3B: return "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x3C: return "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x40: return "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x41: return "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x42: return "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x43: return "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x44: return "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x45: return "SERVO IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x46: return "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x47: return "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x48: return "SERVO IMPENDING FAILURE SERVO DETECTED"; + case 0x49: return "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x4A: return "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x4B: return "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x4C: return "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x50: return "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x51: return "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x52: return "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x53: return "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x54: return "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x55: return "SPINDLE IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x56: return "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x57: return "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x58: return "SPINDLE IMPENDING FAILURE SPINDLE DETECTED"; + case 0x59: return "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x5A: return "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x5B: return "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x5C: return "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0x60: return "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE"; + case 0x61: return "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH"; + case 0x62: return "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH"; + case 0x63: return "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH"; + case 0x64: return "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS"; + case 0x65: return "FIRMWARE IMPENDING FAILURE ACCESS TIME TOO HIGH"; + case 0x66: return "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH"; + case 0x67: return "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS"; + case 0x68: return "FIRMWARE IMPENDING FAILURE FIRMWARE DETECTED"; + case 0x69: return "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE"; + case 0x6A: return "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE"; + case 0x6B: return "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT"; + case 0x6C: return "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"; + case 0xFF: return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"; + } + + break; + case 0x5E: + switch(ASCQ) + { + case 0x00: return "LOW POWER CONDITION ON"; + case 0x01: return "IDLE CONDITION ACTIVATED BY TIMER"; + case 0x02: return "STANDBY CONDITION ACTIVATED BY TIMER"; + case 0x03: return "IDLE CONDITION ACTIVATED BY COMMAND"; + case 0x04: return "STANDBY CONDITION ACTIVATED BY COMMAND"; + case 0x05: return "IDLE_B CONDITION ACTIVATED BY TIMER"; + case 0x06: return "IDLE_B CONDITION ACTIVATED BY COMMAND"; + case 0x07: return "IDLE_C CONDITION ACTIVATED BY TIMER"; + case 0x08: return "IDLE_C CONDITION ACTIVATED BY COMMAND"; + case 0x09: return "STANDBY_Y CONDITION ACTIVATED BY TIMER"; + case 0x0A: return "STANDBY_Y CONDITION ACTIVATED BY COMMAND"; + case 0x41: return "POWER STATE CHANGED TO ACTIVE"; + case 0x42: return "POWER STATE CHANGED TO IDLE"; + case 0x43: return "POWER STATE CHANGED TO STANDBY"; + case 0x45: return "POWER STATE CHANGED TO SLEEP"; + case 0x47: return "POWER STATE CHANGED TO DEVICE CONTROL"; + } + + break; + case 0x60: + switch(ASCQ) + { + case 0x00: return "LAMP FAILURE"; + } + + break; + case 0x61: + switch(ASCQ) + { + case 0x00: return "VIDEO ACQUISTION ERROR"; + case 0x01: return "UNABLE TO ACQUIRE VIDEO"; + case 0x02: return "OUT OF FOCUS"; + } + + break; + case 0x62: + switch(ASCQ) + { + case 0x00: return "SCAN HEAD POSITIONING ERROR"; + } + + break; + case 0x63: + switch(ASCQ) + { + case 0x00: return "END OF USER AREA ENCOUNTERED ON THIS TRACK"; + case 0x01: return "PACKET DOES NOT FIT IN AVAILABLE SPACE"; + } + + break; + case 0x64: + switch(ASCQ) + { + case 0x00: return "ILLEGAL MODE FOR THIS TRACK"; + case 0x01: return "INVALID PACKET SIZE"; + } + + break; + case 0x65: + switch(ASCQ) + { + case 0x00: return "VOLTAGE FAULT"; + } + + break; + case 0x66: + switch(ASCQ) + { + case 0x00: return "AUTOMATIC DOCUMENT FEEDER COVER UP"; + case 0x01: return "AUTOMATIC DOCUMENT FEEDER LIFT UP"; + case 0x02: return "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER"; + case 0x03: return "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER"; + } + + break; + case 0x67: + switch(ASCQ) + { + case 0x00: return "CONFIGURATION FAILURE"; + case 0x01: return "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED"; + case 0x02: return "ADD LOGICAL UNIT FAILED"; + case 0x03: return "MODIFICATION OF LOGICAL UNIT FAILED"; + case 0x04: return "EXCHANGE OF LOGICAL UNIT FAILED"; + case 0x05: return "REMOVE OF LOGICAL UNIT FAILED"; + case 0x06: return "ATTACHMENT OF LOGICAL UNIT FAILED"; + case 0x07: return "CREATION OF LOGICAL UNIT FAILED"; + case 0x08: return "ASSIGN FAILURE OCCURRED"; + case 0x09: return "MULTIPLY ASSIGNED LOGICAL UNIT"; + case 0x0A: return "SET TARGET PORT GROUPS COMMAND FAILED"; + case 0x0B: return "ATA DEVICE FEATURE NOT ENABLED"; + } + + break; + case 0x68: + switch(ASCQ) + { + case 0x00: return "LOGICAL UNIT NOT CONFIGURED"; + case 0x01: return "SUBSIDIARY LOGICAL UNIT NOT CONFIGURED"; + } + + break; + case 0x69: + switch(ASCQ) + { + case 0x00: return "DATA LOSS ON LOGICAL UNIT"; + case 0x01: return "MULTIPLE LOGICAL UNIT FAILURES"; + case 0x02: return "PARITY/DATA MISMATCH"; + } + + break; + case 0x6A: + switch(ASCQ) + { + case 0x00: return "INFORMATIONAL, REFER TO LOG"; + } + + break; + case 0x6B: + switch(ASCQ) + { + case 0x00: return "STATE CHANGE HAS OCCURRED"; + case 0x01: return "REDUNDANCY LEVEL GOT BETTER"; + case 0x02: return "REDUNDANCY LEVEL GOT WORSE"; + } + + break; + case 0x6C: + switch(ASCQ) + { + case 0x00: return "REBUILD FAILURE OCCURRED"; + } + + break; + case 0x6D: + switch(ASCQ) + { + case 0x00: return "RECALCULATE FAILURE OCCURRED"; + } + + break; + case 0x6E: + switch(ASCQ) + { + case 0x00: return "COMMAND TO LOGICAL UNIT FAILED"; + } + + break; + case 0x6F: + switch(ASCQ) + { + case 0x00: return "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE"; + case 0x01: return "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT"; + case 0x02: return "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED"; + case 0x03: return "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION"; + case 0x04: return "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION"; + case 0x05: return "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR"; + case 0x06: return "INSUFFICIENT BLOCK COUNT FOR BINDING NONCE RECORDING"; + case 0x07: return "CONFLICT IN BINDING NONCE RECORDING"; + } + + break; + case 0x70: return $"DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF {ASCQ:X2}h"; + case 0x71: + switch(ASCQ) + { + case 0x00: return "DECOMPRESSIONG EXCEPTION LONG ALGORITHM ID"; + } + + break; + case 0x72: + switch(ASCQ) + { + case 0x00: return "SESSION FIXATION ERROR"; + case 0x01: return "SESSION FIXATION ERROR WRITING LEAD-IN"; + case 0x02: return "SESSION FIXATION ERROR WRITING LEAD-OUT"; + case 0x03: return "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION"; + case 0x04: return "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK"; + case 0x05: return "NO MORE TRACK RESERVATIONS ALLOWED"; + case 0x06: return "RMZ EXTENSION IS NOT ALLOWED"; + case 0x07: return "NO MORE TEST ZONE EXTENSIONS ARE ALLOWED"; + } + + break; + case 0x73: + switch(ASCQ) + { + case 0x00: return "CD CONTROL ERROR"; + case 0x01: return "POWER CALIBRATION AREA ALMOST FULL"; + case 0x02: return "POWER CALIBRATION AREA IS FULL"; + case 0x03: return "POWER CALIBRATION AREA ERROR"; + case 0x04: return "PROGRAM MEMORY AREA UPDATE FAILURE"; + case 0x05: return "PROGRAM MEMORY AREA IS FULL"; + case 0x06: return "RMA/PMA IS ALMOST FULL"; + case 0x10: return "CURRENT POWER CALIBRATION AREA ALMOST FULL"; + case 0x11: return "CURRENT POWER CALIBRATION AREA IS FULL"; + case 0x17: return "RDZ IS FULL"; + } + + break; + case 0x74: + switch(ASCQ) + { + case 0x00: return "SECURITY ERROR"; + case 0x01: return "UNABLE TO DECRYPT DATA"; + case 0x02: return "UNENCRYPTED DATA ENCOUNTERED WHILE DECRYPTING"; + case 0x03: return "INCORRECT DATA ENCRYPTION KEY"; + case 0x04: return "CRYPTOGRAPHIC INTEGRITY VALIDATION FAILED"; + case 0x05: return "ERROR DECRYPTING DATA"; + case 0x06: return "UNKNOWN SIGNATURE VERIFICATION KEY"; + case 0x07: return "ENCRYPTION PARAMETERS NOT USEABLE"; + case 0x08: return "DIGITAL SIGNATURE VALIDATION FAILURE"; + case 0x09: return "ENCRYPTION MODE MISMATCH ON READ"; + case 0x0A: return "ENCRYPTED BLOCK NOT RAW READ ENABLED"; + case 0x0B: return "INCORRECT ENCRYPTION PARAMETERS"; + case 0x0C: return "UNABLE TO DECRYPT PARAMETER LIST"; + case 0x0D: return "ENCRYPTION ALGORITHM DISABLED"; + case 0x10: return "SA CREATION PARAMETER VALUE INVALID"; + case 0x11: return "SA CREATION PARAMETER VALUE REJECTED"; + case 0x12: return "INVALID SA USAGE"; + case 0x21: return "DATA ENCRYPTION CONFIGURATION PREVENTED"; + case 0x30: return "SA CREATION PARAMETER NOT SUPPORTED"; + case 0x40: return "AUTHENTICATION FAILED"; + case 0x61: return "EXTERNAL DATA ENCRYPTION KEY MANAGER ACCESS ERROR"; + case 0x62: return "EXTERNAL DATA ENCRYPTION KEY MANAGER ERROR"; + case 0x63: return "EXTERNAL DATA ENCRYPTION KEY NOT FOUND"; + case 0x64: return "EXTERNAL DATA ENCRYPTION REQUEST NOT AUTHORIZED"; + case 0x6E: return "EXTERNAL DATA ENCRYPTION CONTROL TIMEOUT"; + case 0x6F: return "EXTERNAL DATA ENCRYPTION CONTROL ERROR"; + case 0x71: return "LOGICAL UNIT ACCESS NOT AUTHORIZED"; + case 0x79: return "SECURITY CONFLICT IN TRANSLATED DEVICE"; + } + + break; + } + + return ASC >= 0x80 + ? ASCQ >= 0x80 + ? $"VENDOR-SPECIFIC ASC {ASC:X2}h WITH VENDOR-SPECIFIC ASCQ {ASCQ:X2}h" + : $"VENDOR-SPECIFIC ASC {ASC:X2}h WITH ASCQ {ASCQ:X2}h" + : ASCQ >= 0x80 + ? $"ASC {ASC:X2}h WITH VENDOR-SPECIFIC ASCQ {ASCQ:X2}h" + : $"ASC {ASC:X2}h WITH ASCQ {ASCQ:X2}h"; + } } \ No newline at end of file diff --git a/SCSI/Types.cs b/SCSI/Types.cs index 986219b..a8862ab 100644 --- a/SCSI/Types.cs +++ b/SCSI/Types.cs @@ -32,556 +32,555 @@ using System.Diagnostics.CodeAnalysis; -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum MediumTypes : byte { - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum MediumTypes : byte - { - Default = 0x00, + Default = 0x00, - #region Medium Types defined in ECMA-111 for Direct-Access devices - /// ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side - ECMA54 = 0x09, - /// - /// ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad - /// on Both Sides - /// - ECMA59 = 0x0A, - /// ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides - ECMA69 = 0x0B, - /// ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side - ECMA66 = 0x0E, - /// - /// ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both - /// Sides; 1,9 Tracks per mm - /// - ECMA70 = 0x12, - /// - /// ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both - /// Sides; 3,8 Tracks per mm - /// - ECMA78 = 0x16, - /// - /// ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; - /// 3,8 Tracks per mm - /// - ECMA99 = 0x1A, - /// - /// ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; - /// 5,3 Tracks per mm - /// - ECMA100 = 0x1E, - #endregion Medium Types defined in ECMA-111 for Direct-Access devices + #region Medium Types defined in ECMA-111 for Direct-Access devices + /// ECMA-54: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad on One Side + ECMA54 = 0x09, + /// + /// ECMA-59 & ANSI X3.121-1984: 200 mm Flexible Disk Cartridge using Two-Frequency Recording at 13262 ftprad + /// on Both Sides + /// + ECMA59 = 0x0A, + /// ECMA-69: 200 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides + ECMA69 = 0x0B, + /// ECMA-66: 130 mm Flexible Disk Cartridge using Two-Frequency Recording at 7958 ftprad on One Side + ECMA66 = 0x0E, + /// + /// ECMA-70 & ANSI X3.125-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both + /// Sides; 1,9 Tracks per mm + /// + ECMA70 = 0x12, + /// + /// ECMA-78 & ANSI X3.126-1986: 130 mm Flexible Disk Cartridge using MFM Recording at 7958 ftprad on Both + /// Sides; 3,8 Tracks per mm + /// + ECMA78 = 0x16, + /// + /// ECMA-99 & ISO 8630-1985: 130 mm Flexible Disk Cartridge using MFM Recording at 13262 ftprad on Both Sides; + /// 3,8 Tracks per mm + /// + ECMA99 = 0x1A, + /// + /// ECMA-100 & ANSI X3.137: 90 mm Flexible Disk Cartridge using MFM Recording at 7859 ftprad on Both Sides; + /// 5,3 Tracks per mm + /// + ECMA100 = 0x1E, + #endregion Medium Types defined in ECMA-111 for Direct-Access devices - #region Medium Types defined in SCSI-2 for Direct-Access devices - /// Unspecified single sided flexible disk - Unspecified_SS = 0x01, - /// Unspecified double sided flexible disk - Unspecified_DS = 0x02, - /// ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 1 side - X3_73 = 0x05, - /// ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 2 sides - X3_73_DS = 0x06, - /// ANSI X3.80-1980: 130 mm, 3979 ftprad, 1,9 Tracks per mm, 1 side - X3_82 = 0x0D, - /// 6,3 mm tape with 12 tracks at 394 ftpmm - Tape12 = 0x40, - /// 6,3 mm tape with 24 tracks at 394 ftpmm - Tape24 = 0x44, - #endregion Medium Types defined in SCSI-2 for Direct-Access devices + #region Medium Types defined in SCSI-2 for Direct-Access devices + /// Unspecified single sided flexible disk + Unspecified_SS = 0x01, + /// Unspecified double sided flexible disk + Unspecified_DS = 0x02, + /// ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 1 side + X3_73 = 0x05, + /// ANSI X3.73-1980: 200 mm, 6631 ftprad, 1,9 Tracks per mm, 2 sides + X3_73_DS = 0x06, + /// ANSI X3.80-1980: 130 mm, 3979 ftprad, 1,9 Tracks per mm, 1 side + X3_82 = 0x0D, + /// 6,3 mm tape with 12 tracks at 394 ftpmm + Tape12 = 0x40, + /// 6,3 mm tape with 24 tracks at 394 ftpmm + Tape24 = 0x44, + #endregion Medium Types defined in SCSI-2 for Direct-Access devices - #region Medium Types defined in SCSI-3 SBC-1 for Optical devices - /// Read-only medium - ReadOnly = 0x01, - /// Write-once Read-many medium - WORM = 0x02, - /// Erasable medium - Erasable = 0x03, - /// Combination of read-only and write-once medium - RO_WORM = 0x04, - /// Combination of read-only and erasable medium - RO_RW = 0x05, - /// Combination of write-once and erasable medium - WORM_RW = 0x06, - #endregion Medium Types defined in SCSI-3 SBC-1 for Optical devices + #region Medium Types defined in SCSI-3 SBC-1 for Optical devices + /// Read-only medium + ReadOnly = 0x01, + /// Write-once Read-many medium + WORM = 0x02, + /// Erasable medium + Erasable = 0x03, + /// Combination of read-only and write-once medium + RO_WORM = 0x04, + /// Combination of read-only and erasable medium + RO_RW = 0x05, + /// Combination of write-once and erasable medium + WORM_RW = 0x06, + #endregion Medium Types defined in SCSI-3 SBC-1 for Optical devices - #region Medium Types defined in SCSI-2 for MultiMedia devices - /// 120 mm CD-ROM - CDROM = 0x01, - /// 120 mm Compact Disc Digital Audio - CDDA = 0x02, - /// 120 mm Compact Disc with data and audio - MixedCD = 0x03, - /// 80 mm CD-ROM - CDROM_80 = 0x05, - /// 80 mm Compact Disc Digital Audio - CDDA_80 = 0x06, - /// 80 mm Compact Disc with data and audio - MixedCD_80 = 0x07, - #endregion Medium Types defined in SCSI-2 for MultiMedia devices + #region Medium Types defined in SCSI-2 for MultiMedia devices + /// 120 mm CD-ROM + CDROM = 0x01, + /// 120 mm Compact Disc Digital Audio + CDDA = 0x02, + /// 120 mm Compact Disc with data and audio + MixedCD = 0x03, + /// 80 mm CD-ROM + CDROM_80 = 0x05, + /// 80 mm Compact Disc Digital Audio + CDDA_80 = 0x06, + /// 80 mm Compact Disc with data and audio + MixedCD_80 = 0x07, + #endregion Medium Types defined in SCSI-2 for MultiMedia devices - #region Medium Types defined in SFF-8020i - /// Unknown medium type - Unknown_CD = 0x00, - /// 120 mm Hybrid disc (Photo CD) - HybridCD = 0x04, - /// Unknown size CD-R - Unknown_CDR = 0x10, - /// 120 mm CD-R with data only - CDR = 0x11, - /// 120 mm CD-R with audio only - CDR_DA = 0x12, - /// 120 mm CD-R with data and audio - CDR_Mixed = 0x13, - /// 120 mm Hybrid CD-R (Photo CD) - HybridCDR = 0x14, - /// 80 mm CD-R with data only - CDR_80 = 0x15, - /// 80 mm CD-R with audio only - CDR_DA_80 = 0x16, - /// 80 mm CD-R with data and audio - CDR_Mixed_80 = 0x17, - /// 80 mm Hybrid CD-R (Photo CD) - HybridCDR_80 = 0x18, - /// Unknown size CD-RW - Unknown_CDRW = 0x20, - /// 120 mm CD-RW with data only - CDRW = 0x21, - /// 120 mm CD-RW with audio only - CDRW_DA = 0x22, - /// 120 mm CD-RW with data and audio - CDRW_Mixed = 0x23, - /// 120 mm Hybrid CD-RW (Photo CD) - HybridCDRW = 0x24, - /// 80 mm CD-RW with data only - CDRW_80 = 0x25, - /// 80 mm CD-RW with audio only - CDRW_DA_80 = 0x26, - /// 80 mm CD-RW with data and audio - CDRW_Mixed_80 = 0x27, - /// 80 mm Hybrid CD-RW (Photo CD) - HybridCDRW_80 = 0x28, - /// Unknown size HD disc - Unknown_HD = 0x30, - /// 120 mm HD disc - HD = 0x31, - /// 80 mm HD disc - HD_80 = 0x35, - /// No disc inserted, tray closed or caddy inserted - NoDisc = 0x70, - /// Tray open or no caddy inserted - TrayOpen = 0x71, - /// Tray closed or caddy inserted but medium error - MediumError = 0x72, - #endregion Medium Types defined in SFF-8020i + #region Medium Types defined in SFF-8020i + /// Unknown medium type + Unknown_CD = 0x00, + /// 120 mm Hybrid disc (Photo CD) + HybridCD = 0x04, + /// Unknown size CD-R + Unknown_CDR = 0x10, + /// 120 mm CD-R with data only + CDR = 0x11, + /// 120 mm CD-R with audio only + CDR_DA = 0x12, + /// 120 mm CD-R with data and audio + CDR_Mixed = 0x13, + /// 120 mm Hybrid CD-R (Photo CD) + HybridCDR = 0x14, + /// 80 mm CD-R with data only + CDR_80 = 0x15, + /// 80 mm CD-R with audio only + CDR_DA_80 = 0x16, + /// 80 mm CD-R with data and audio + CDR_Mixed_80 = 0x17, + /// 80 mm Hybrid CD-R (Photo CD) + HybridCDR_80 = 0x18, + /// Unknown size CD-RW + Unknown_CDRW = 0x20, + /// 120 mm CD-RW with data only + CDRW = 0x21, + /// 120 mm CD-RW with audio only + CDRW_DA = 0x22, + /// 120 mm CD-RW with data and audio + CDRW_Mixed = 0x23, + /// 120 mm Hybrid CD-RW (Photo CD) + HybridCDRW = 0x24, + /// 80 mm CD-RW with data only + CDRW_80 = 0x25, + /// 80 mm CD-RW with audio only + CDRW_DA_80 = 0x26, + /// 80 mm CD-RW with data and audio + CDRW_Mixed_80 = 0x27, + /// 80 mm Hybrid CD-RW (Photo CD) + HybridCDRW_80 = 0x28, + /// Unknown size HD disc + Unknown_HD = 0x30, + /// 120 mm HD disc + HD = 0x31, + /// 80 mm HD disc + HD_80 = 0x35, + /// No disc inserted, tray closed or caddy inserted + NoDisc = 0x70, + /// Tray open or no caddy inserted + TrayOpen = 0x71, + /// Tray closed or caddy inserted but medium error + MediumError = 0x72, + #endregion Medium Types defined in SFF-8020i - #region Medium Types defined in USB Mass Storage Class - UFI Command Specification - /// 3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb) - Type3Floppy = 0x93, - /// 3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb) - HDFloppy = 0x94, - #endregion Medium Types defined in USB Mass Storage Class - UFI Command Specification + #region Medium Types defined in USB Mass Storage Class - UFI Command Specification + /// 3.5-inch, 135 tpi, 12362 bits/radian, double-sided MFM (aka 1.25Mb) + Type3Floppy = 0x93, + /// 3.5-inch, 135 tpi, 15916 bits/radian, double-sided MFM (aka 1.44Mb) + HDFloppy = 0x94, + #endregion Medium Types defined in USB Mass Storage Class - UFI Command Specification - #region Medium Types defined in INF-8070 - /// Unknown type block device - UnknownBlockDevice = 0x40, - /// Read-only block device - ReadOnlyBlockDevice = 0x41, - /// Read/Write block device - ReadWriteBlockDevice = 0x42, - #endregion Medium Types defined in INF-8070 + #region Medium Types defined in INF-8070 + /// Unknown type block device + UnknownBlockDevice = 0x40, + /// Read-only block device + ReadOnlyBlockDevice = 0x41, + /// Read/Write block device + ReadWriteBlockDevice = 0x42, + #endregion Medium Types defined in INF-8070 - #region Medium Types found in vendor documents - /// LTO WORM as reported by HP drives - LTOWORM = 0x01, - /// LTO cleaning cartridge as reported by Certance/Seagate drives - LTOCleaning = 0x01, - /// Direct-overwrite magneto-optical - DOW = 0x07, - /// LTO Ultrium - LTO = 0x18, - /// LTO Ultrium-2 - LTO2 = 0x28, - /// DC-2900SL - DC2900SL = 0x31, - /// MLR-1 - MLR1 = 0x33, - /// DDS-3 - DDS3 = 0x33, - /// DC-9200 - DC9200 = 0x34, - /// DDS-4 - DDS4 = 0x34, - /// DAT-72 - DAT72 = 0x35, - /// LTO Ultrium-3 - LTO3 = 0x38, - /// LTO Ultrium-3 WORM - LTO3WORM = 0x3C, - /// DDS cleaning cartridge - DDSCleaning = 0x3F, - /// DC-9250 - DC9250 = 0x40, - /// SLR-32 - SLR32 = 0x43, - /// MLR-1SL - MLR1SL = 0x44, - /// SLRtape-50 - SLRtape50 = 0x47, - /// LTO Ultrium-4 - LTO4 = 0x48, - /// LTO Ultrium-4 WORM - LTO4WORM = 0x4C, - /// SLRtape-50SL - SLRtape50SL = 0x50, - /// SLR-32SL - SLR32SL = 0x54, - /// SLR-5 - SLR5 = 0x55, - /// SLR-5SL - SLR5SL = 0x56, - /// LTO Ultrium-5 - LTO5 = 0x58, - /// LTO Ultrium-5 WORM - LTO5WORM = 0x5C, - /// SLRtape-7 - SLRtape7 = 0x63, - /// SLRtape-7SL - SLRtape7SL = 0x64, - /// SLRtape-24 - SLRtape24 = 0x65, - /// SLRtape-24SL - SLRtape24SL = 0x66, - /// LTO Ultrium-6 - LTO6 = 0x68, - /// LTO Ultrium-6 WORM - LTO6WORM = 0x6C, - /// SLRtape-140 - SLRtape140 = 0x70, - /// SLRtape-40 - SLRtape40 = 0x73, - /// SLRtape-60 - SLRtape60 = 0x74, - /// SLRtape-75 - SLRtape75 = 0x74, - /// SLRtape-100 - SLRtape100 = 0x75, - /// SLR-40 or SLR-60 or SLR-100 - SLR40_60_100 = 0x76, - /// LTO Ultrium-7 - LTO7 = 0x78, - /// LTO Ultrium-7 WORM - LTO7WORM = 0x7C, - /// HP LTO emulating a CD - LTOCD = 0x80, - /// Exatape 15m - Exatape15m = 0x81, - /// IBM MagStar - MagStar = 0x81, - /// VXA - VXA = 0x81, - /// CompactTape I - CT1 = 0x82, - /// Exatape 28m - Exatape28m = 0x82, - /// CompactTape II - CT2 = 0x82, - /// VXA-2 - VXA2 = 0x82, - /// VXA-3 - VXA3 = 0x82, - /// Exatape 54m - Exatape54m = 0x83, - /// DLTtape III - DLTtapeIII = 0x83, - /// Exatape 80m - Exatape80m = 0x84, - /// DLTtape IIIxt - DLTtapeIIIxt = 0x84, - /// Exatape 106m - Exatape106m = 0x85, - /// DLTtape IV - DLTtapeIV = 0x85, - /// Travan 5 - Travan5 = 0x85, - /// Exatape 106m XL - Exatape106mXL = 0x86, - /// SuperDLT I - SDLT1 = 0x86, - /// SuperDLT II - SDLT2 = 0x87, - /// VStape I - VStapeI = 0x90, - /// DLTtape S4 - DLTtapeS4 = 0x91, - /// Travan 7 - Travan7 = 0x95, - /// Exatape 22m - Exatape22m = 0xC1, - /// Exatape 40m - Exatape40m = 0xC2, - /// Exatape 76m - Exatape76m = 0xC3, - /// Exatape 112m - Exatape112m = 0xC4, - /// Exatape 22m AME - Exatape22mAME = 0xD1, - /// Exatape 170m - Exatape170m = 0xD2, - /// Exatape 125m - Exatape125m = 0xD3, - /// Exatape 45m - Exatape45m = 0xD4, - /// Exatape 225m - Exatape225m = 0xD5, - /// Exatape 150m - Exatape150m = 0xD6, - /// Exatape 75m - Exatape75m = 0xD7, - #endregion Medium Types found in vendor documents + #region Medium Types found in vendor documents + /// LTO WORM as reported by HP drives + LTOWORM = 0x01, + /// LTO cleaning cartridge as reported by Certance/Seagate drives + LTOCleaning = 0x01, + /// Direct-overwrite magneto-optical + DOW = 0x07, + /// LTO Ultrium + LTO = 0x18, + /// LTO Ultrium-2 + LTO2 = 0x28, + /// DC-2900SL + DC2900SL = 0x31, + /// MLR-1 + MLR1 = 0x33, + /// DDS-3 + DDS3 = 0x33, + /// DC-9200 + DC9200 = 0x34, + /// DDS-4 + DDS4 = 0x34, + /// DAT-72 + DAT72 = 0x35, + /// LTO Ultrium-3 + LTO3 = 0x38, + /// LTO Ultrium-3 WORM + LTO3WORM = 0x3C, + /// DDS cleaning cartridge + DDSCleaning = 0x3F, + /// DC-9250 + DC9250 = 0x40, + /// SLR-32 + SLR32 = 0x43, + /// MLR-1SL + MLR1SL = 0x44, + /// SLRtape-50 + SLRtape50 = 0x47, + /// LTO Ultrium-4 + LTO4 = 0x48, + /// LTO Ultrium-4 WORM + LTO4WORM = 0x4C, + /// SLRtape-50SL + SLRtape50SL = 0x50, + /// SLR-32SL + SLR32SL = 0x54, + /// SLR-5 + SLR5 = 0x55, + /// SLR-5SL + SLR5SL = 0x56, + /// LTO Ultrium-5 + LTO5 = 0x58, + /// LTO Ultrium-5 WORM + LTO5WORM = 0x5C, + /// SLRtape-7 + SLRtape7 = 0x63, + /// SLRtape-7SL + SLRtape7SL = 0x64, + /// SLRtape-24 + SLRtape24 = 0x65, + /// SLRtape-24SL + SLRtape24SL = 0x66, + /// LTO Ultrium-6 + LTO6 = 0x68, + /// LTO Ultrium-6 WORM + LTO6WORM = 0x6C, + /// SLRtape-140 + SLRtape140 = 0x70, + /// SLRtape-40 + SLRtape40 = 0x73, + /// SLRtape-60 + SLRtape60 = 0x74, + /// SLRtape-75 + SLRtape75 = 0x74, + /// SLRtape-100 + SLRtape100 = 0x75, + /// SLR-40 or SLR-60 or SLR-100 + SLR40_60_100 = 0x76, + /// LTO Ultrium-7 + LTO7 = 0x78, + /// LTO Ultrium-7 WORM + LTO7WORM = 0x7C, + /// HP LTO emulating a CD + LTOCD = 0x80, + /// Exatape 15m + Exatape15m = 0x81, + /// IBM MagStar + MagStar = 0x81, + /// VXA + VXA = 0x81, + /// CompactTape I + CT1 = 0x82, + /// Exatape 28m + Exatape28m = 0x82, + /// CompactTape II + CT2 = 0x82, + /// VXA-2 + VXA2 = 0x82, + /// VXA-3 + VXA3 = 0x82, + /// Exatape 54m + Exatape54m = 0x83, + /// DLTtape III + DLTtapeIII = 0x83, + /// Exatape 80m + Exatape80m = 0x84, + /// DLTtape IIIxt + DLTtapeIIIxt = 0x84, + /// Exatape 106m + Exatape106m = 0x85, + /// DLTtape IV + DLTtapeIV = 0x85, + /// Travan 5 + Travan5 = 0x85, + /// Exatape 106m XL + Exatape106mXL = 0x86, + /// SuperDLT I + SDLT1 = 0x86, + /// SuperDLT II + SDLT2 = 0x87, + /// VStape I + VStapeI = 0x90, + /// DLTtape S4 + DLTtapeS4 = 0x91, + /// Travan 7 + Travan7 = 0x95, + /// Exatape 22m + Exatape22m = 0xC1, + /// Exatape 40m + Exatape40m = 0xC2, + /// Exatape 76m + Exatape76m = 0xC3, + /// Exatape 112m + Exatape112m = 0xC4, + /// Exatape 22m AME + Exatape22mAME = 0xD1, + /// Exatape 170m + Exatape170m = 0xD2, + /// Exatape 125m + Exatape125m = 0xD3, + /// Exatape 45m + Exatape45m = 0xD4, + /// Exatape 225m + Exatape225m = 0xD5, + /// Exatape 150m + Exatape150m = 0xD6, + /// Exatape 75m + Exatape75m = 0xD7, + #endregion Medium Types found in vendor documents - #region Medium Types found testing a Hi-MD drive - /// Hi-MD - HiMD = 0x44, - #endregion Medium Types found testing a Hi-MD drive - } + #region Medium Types found testing a Hi-MD drive + /// Hi-MD + HiMD = 0x44, + #endregion Medium Types found testing a Hi-MD drive +} - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DensityType : byte - { - Default = 0x00, +[SuppressMessage("ReSharper", "InconsistentNaming")] +public enum DensityType : byte +{ + Default = 0x00, - #region Density Types defined in ECMA-111 for Direct-Access devices - /// 7958 flux transitions per radian - Flux7958 = 0x01, - /// 13262 flux transitions per radian - Flux13262 = 0x02, - /// 15916 flux transitions per radian - Flux15916 = 0x03, - #endregion Density Types defined in ECMA-111 for Direct-Access devices + #region Density Types defined in ECMA-111 for Direct-Access devices + /// 7958 flux transitions per radian + Flux7958 = 0x01, + /// 13262 flux transitions per radian + Flux13262 = 0x02, + /// 15916 flux transitions per radian + Flux15916 = 0x03, + #endregion Density Types defined in ECMA-111 for Direct-Access devices - #region Density Types defined in ECMA-111 for Sequential-Access devices - /// ECMA-62 & ANSI X3.22-1983: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm - ECMA62 = 0x01, - /// ECMA-62 & ANSI X3.39-1986: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm - ECMA62_Phase = 0x02, - /// ECMA-62 & ANSI X3.54-1986: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR - ECMA62_GCR = 0x03, - /// ECMA-79 & ANSI X3.116-1986: 6,30 mm Magnetic Tape Cartridge using MFM Recording at 252 ftpmm - ECMA79 = 0x07, - /// - /// Draft ECMA & ANSI X3B5/87-099: 12,7 mm Magnetic Tape Cartridge using IFM Recording on 18 Tracks at 1944 - /// ftpmm, GCR (IBM 3480, 3490, 3490E) - /// - IBM3480 = 0x09, - /// ECMA-46 & ANSI X3.56-1986: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm - ECMA46 = 0x0B, - /// ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZI Recording, 394 ftpmm - ECMA98 = 0x0E, - #endregion Density Types defined in ECMA-111 for Sequential-Access devices + #region Density Types defined in ECMA-111 for Sequential-Access devices + /// ECMA-62 & ANSI X3.22-1983: 12,7 mm 9-Track Magnetic Tape, 32 ftpmm, NRZI, 32 cpmm + ECMA62 = 0x01, + /// ECMA-62 & ANSI X3.39-1986: 12,7 mm 9-Track Magnetic Tape, 126 ftpmm, Phase Encoding, 63 cpmm + ECMA62_Phase = 0x02, + /// ECMA-62 & ANSI X3.54-1986: 12,7 mm 9-Track Magnetic Tape, 356 ftpmm, NRZI, 245 cpmm GCR + ECMA62_GCR = 0x03, + /// ECMA-79 & ANSI X3.116-1986: 6,30 mm Magnetic Tape Cartridge using MFM Recording at 252 ftpmm + ECMA79 = 0x07, + /// + /// Draft ECMA & ANSI X3B5/87-099: 12,7 mm Magnetic Tape Cartridge using IFM Recording on 18 Tracks at 1944 + /// ftpmm, GCR (IBM 3480, 3490, 3490E) + /// + IBM3480 = 0x09, + /// ECMA-46 & ANSI X3.56-1986: 6,30 mm Magnetic Tape Cartridge, Phase Encoding, 63 bpmm + ECMA46 = 0x0B, + /// ECMA-98: 6,30 mm Magnetic Tape Cartridge, NRZI Recording, 394 ftpmm + ECMA98 = 0x0E, + #endregion Density Types defined in ECMA-111 for Sequential-Access devices - #region Density Types defined in SCSI-2 for Sequential-Access devices - /// ANXI X3.136-1986: 6,35 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24) - X3_136 = 0x05, - /// ANXI X3.157-1987: 12,7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding - X3_157 = 0x06, - /// ANXI X3.158-1987: 3,81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR - X3_158 = 0x08, - /// ANXI X3B5/86-199: 12,7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM - X3B5_86 = 0x0A, - /// HI-TC1: 12,7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR - HiTC1 = 0x0C, - /// HI-TC2: 12,7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR - HiTC2 = 0x0D, - /// QIC-120: 6,3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR - QIC120 = 0x0F, - /// QIC-150: 6,3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR - QIC150 = 0x10, - /// QIC-320: 6,3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR - QIC320 = 0x11, - /// QIC-1350: 6,3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL - QIC1350 = 0x12, - /// ANXI X3B5/88-185A: 3,81 mm Magnetic Tape Cassette, 2400 bpmm, DDS - X3B5_88 = 0x13, - /// ANXI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL - X3_202 = 0x14, - /// ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL - ECMA_TC17 = 0x15, - /// ANXI X3.193-1990: 12,7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM - X3_193 = 0x16, - /// ANXI X3B5/97-174: 12,7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM - X3B5_91 = 0x17, - #endregion Density Types defined in SCSI-2 for Sequential-Access devices + #region Density Types defined in SCSI-2 for Sequential-Access devices + /// ANXI X3.136-1986: 6,35 mm 4 or 9-Track Magnetic Tape Cartridge, 315 bpmm, GCR (QIC-24) + X3_136 = 0x05, + /// ANXI X3.157-1987: 12,7 mm 9-Track Magnetic Tape, 126 bpmm, Phase Encoding + X3_157 = 0x06, + /// ANXI X3.158-1987: 3,81 mm 4-Track Magnetic Tape Cassette, 315 bpmm, GCR + X3_158 = 0x08, + /// ANXI X3B5/86-199: 12,7 mm 22-Track Magnetic Tape Cartridge, 262 bpmm, MFM + X3B5_86 = 0x0A, + /// HI-TC1: 12,7 mm 24-Track Magnetic Tape Cartridge, 500 bpmm, GCR + HiTC1 = 0x0C, + /// HI-TC2: 12,7 mm 24-Track Magnetic Tape Cartridge, 999 bpmm, GCR + HiTC2 = 0x0D, + /// QIC-120: 6,3 mm 15-Track Magnetic Tape Cartridge, 394 bpmm, GCR + QIC120 = 0x0F, + /// QIC-150: 6,3 mm 18-Track Magnetic Tape Cartridge, 394 bpmm, GCR + QIC150 = 0x10, + /// QIC-320: 6,3 mm 26-Track Magnetic Tape Cartridge, 630 bpmm, GCR + QIC320 = 0x11, + /// QIC-1350: 6,3 mm 30-Track Magnetic Tape Cartridge, 2034 bpmm, RLL + QIC1350 = 0x12, + /// ANXI X3B5/88-185A: 3,81 mm Magnetic Tape Cassette, 2400 bpmm, DDS + X3B5_88 = 0x13, + /// ANXI X3.202-1991: 8 mm Magnetic Tape Cassette, 1703 bpmm, RLL + X3_202 = 0x14, + /// ECMA TC17: 8 mm Magnetic Tape Cassette, 1789 bpmm, RLL + ECMA_TC17 = 0x15, + /// ANXI X3.193-1990: 12,7 mm 48-Track Magnetic Tape Cartridge, 394 bpmm, MFM + X3_193 = 0x16, + /// ANXI X3B5/97-174: 12,7 mm 48-Track Magnetic Tape Cartridge, 1673 bpmm, MFM + X3B5_91 = 0x17, + #endregion Density Types defined in SCSI-2 for Sequential-Access devices - #region Density Types defined in SCSI-2 for MultiMedia devices - /// User data only - User = 0x01, - /// User data plus auxiliary data field - UserAuxiliary = 0x02, - /// 4-byt tag field, user data plus auxiliary data - UserAuxiliaryTag = 0x03, - /// Audio information only - Audio = 0x04, - #endregion Density Types defined in SCSI-2 for MultiMedia devices + #region Density Types defined in SCSI-2 for MultiMedia devices + /// User data only + User = 0x01, + /// User data plus auxiliary data field + UserAuxiliary = 0x02, + /// 4-byt tag field, user data plus auxiliary data + UserAuxiliaryTag = 0x03, + /// Audio information only + Audio = 0x04, + #endregion Density Types defined in SCSI-2 for MultiMedia devices - #region Density Types defined in SCSI-2 for Optical devices - /// ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks - ISO10090 = 0x01, - /// 89 mm Read/Write double-sided optical disc with 12500 tracks - D581 = 0x02, - /// ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks - X3_212 = 0x03, - /// ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks - X3_191 = 0x04, - /// ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks - X3_214 = 0x05, - /// ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks - X3_211 = 0x06, - /// 200 mm optical disc - D407 = 0x07, - /// ISO/IEC 13614: 300 mm double-sided optical disc - ISO13614 = 0x08, - /// ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks - X3_200 = 0x09, - #endregion Density Types defined in SCSI-2 for Optical devices + #region Density Types defined in SCSI-2 for Optical devices + /// ISO/IEC 10090: 86 mm Read/Write single-sided optical disc with 12500 tracks + ISO10090 = 0x01, + /// 89 mm Read/Write double-sided optical disc with 12500 tracks + D581 = 0x02, + /// ANSI X3.212: 130 mm Read/Write double-sided optical disc with 18750 tracks + X3_212 = 0x03, + /// ANSI X3.191: 130 mm Write-Once double-sided optical disc with 30000 tracks + X3_191 = 0x04, + /// ANSI X3.214: 130 mm Write-Once double-sided optical disc with 20000 tracks + X3_214 = 0x05, + /// ANSI X3.211: 130 mm Write-Once double-sided optical disc with 18750 tracks + X3_211 = 0x06, + /// 200 mm optical disc + D407 = 0x07, + /// ISO/IEC 13614: 300 mm double-sided optical disc + ISO13614 = 0x08, + /// ANSI X3.200: 356 mm double-sided optical disc with 56350 tracks + X3_200 = 0x09, + #endregion Density Types defined in SCSI-2 for Optical devices - #region Density Types found in vendor documents - /// QIC-11 - QIC11 = 0x04, - /// CompactTape I - CT1 = 0x0A, - /// Exabyte 8200 format - Ex8200 = 0x14, - /// Exabyte 8500 format - Ex8500 = 0x15, - /// CompactTape II - CT2 = 0x16, - /// DLTtape III 42500 bpi - DLT3_42k = 0x17, - /// DLTtape III 56 track - DLT3_56t = 0x18, - /// DLTtape III 62500 bpi - DLT3_62k = 0x19, - /// DLTtape IV - DLT4 = 0x1A, - /// DLTtape IV 85937 bpi - DLT4_85k = 0x1B, - /// DDS-2 - DDS2 = 0x24, - /// DDS-3 - DDS3 = 0x25, - /// DDS-4 - DDS4 = 0x26, - /// Exabyte Mammoth - Mammoth = 0x27, - /// IBM 3490 & 3490E - IBM3490E = 0x28, - /// Exabyte Mammoth-2 - Mammoth2 = 0x28, - /// IBM 3590 - IBM3590 = 0x29, - /// IBM 3590E - IBM3590E = 0x2A, - /// AIT-1 - AIT1 = 0x30, - /// AIT-2 - AIT2 = 0x31, - /// AIT-3 - AIT3 = 0x32, - /// DLTtape IV 123090 bpi - DLT4_123k = 0x40, - /// Ultrium-1 - LTO1 = 0x40, - /// Super AIT-1 - SAIT1 = 0x40, - /// DLTtape IV 85937 bpi - DLT4_98k = 0x41, - /// Ultrium-2 as reported by the Certance drive - LTO2Old = 0x41, - /// Ultrium-2 - LTO2 = 0x42, - /// T9840 - T9840 = 0x42, - /// T9940 - T9940 = 0x43, - /// Ultrium- - LTO3 = 0x44, - /// T9840C - T9840C = 0x45, - /// Travan 5 - Travan5 = 0x46, - /// Ultrium-4 - LTO4 = 0x46, - /// T9840D - T9840D = 0x46, - /// DAT-72 - DAT72 = 0x47, - /// Super DLTtape I 133000 bpi - SDLT1_133k = 0x48, - /// Super DLTtape I - SDLT1 = 0x49, - /// T10000A - T10000A = 0x4A, - /// Super DLTtape II - SDLT2 = 0x4A, - /// DLTtape S4 - DLTS4 = 0x4B, - /// T10000B - T10000B = 0x4B, - /// T10000C - T10000C = 0x4C, - /// T10000D - T10000D = 0x4D, - /// VStape I - VStape1 = 0x40, - /// Ultrium-5 - LTO5 = 0x58, - /// Ultrium-6 - LTO6 = 0x5A, - /// Ultrium-7 - LTO7 = 0x5C, - /// DLTtape III 62500 bpi secondary code - DLT3_62kAlt = 0x80, - /// VXA-1 - VXA1 = 0x80, - /// DLTtape III compressed - DLT3c = 0x81, - /// VXA-2 - VXA2 = 0x81, - /// DLTtape IV secondary code - DLT4Alt = 0x82, - /// VXA-3 - VXA3 = 0x82, - /// DLTtape IV compressed - DLT4c = 0x83, - /// DLTtape IV 85937 bpi secondary code - DLT4_85kAlt = 0x84, - /// DLTtape IV 85937 bpi compressed - DLT4c_85k = 0x85, - /// DLTtape IV 123090 bpi secondary code - DLT4_123kAlt = 0x86, - /// DLTtape IV 123090 bpi compressed - DLT4c_123k = 0x87, - /// DLTtape IV 98250 bpi secondary code - DLT4_98kAlt = 0x88, - /// DLTtape IV 98250 bpi compressed - DLT4c_98k = 0x89, - /// Exabyte compressed 8200 format - Ex8500c = 0x8C, - /// Exabyte compressed 8500 format - Ex8200c = 0x90, - /// Super DLTtape I secondary code - SDLT1Alt = 0x90, - /// Super DLTtape I compressed - SDLT1c = 0x91, - /// Super DLTtape I 133000 bpi secondary code - SDLT1_133kAlt = 0x92, - /// Super DLTtape I 133000 bpi compressed - SDLT1c_133k = 0x93, - /// VStape I secondary code - VStape1Alt = 0x98, - /// VStape I compressed - VStape1c = 0x99, - #endregion Density Types found in vendor documents - } + #region Density Types found in vendor documents + /// QIC-11 + QIC11 = 0x04, + /// CompactTape I + CT1 = 0x0A, + /// Exabyte 8200 format + Ex8200 = 0x14, + /// Exabyte 8500 format + Ex8500 = 0x15, + /// CompactTape II + CT2 = 0x16, + /// DLTtape III 42500 bpi + DLT3_42k = 0x17, + /// DLTtape III 56 track + DLT3_56t = 0x18, + /// DLTtape III 62500 bpi + DLT3_62k = 0x19, + /// DLTtape IV + DLT4 = 0x1A, + /// DLTtape IV 85937 bpi + DLT4_85k = 0x1B, + /// DDS-2 + DDS2 = 0x24, + /// DDS-3 + DDS3 = 0x25, + /// DDS-4 + DDS4 = 0x26, + /// Exabyte Mammoth + Mammoth = 0x27, + /// IBM 3490 & 3490E + IBM3490E = 0x28, + /// Exabyte Mammoth-2 + Mammoth2 = 0x28, + /// IBM 3590 + IBM3590 = 0x29, + /// IBM 3590E + IBM3590E = 0x2A, + /// AIT-1 + AIT1 = 0x30, + /// AIT-2 + AIT2 = 0x31, + /// AIT-3 + AIT3 = 0x32, + /// DLTtape IV 123090 bpi + DLT4_123k = 0x40, + /// Ultrium-1 + LTO1 = 0x40, + /// Super AIT-1 + SAIT1 = 0x40, + /// DLTtape IV 85937 bpi + DLT4_98k = 0x41, + /// Ultrium-2 as reported by the Certance drive + LTO2Old = 0x41, + /// Ultrium-2 + LTO2 = 0x42, + /// T9840 + T9840 = 0x42, + /// T9940 + T9940 = 0x43, + /// Ultrium- + LTO3 = 0x44, + /// T9840C + T9840C = 0x45, + /// Travan 5 + Travan5 = 0x46, + /// Ultrium-4 + LTO4 = 0x46, + /// T9840D + T9840D = 0x46, + /// DAT-72 + DAT72 = 0x47, + /// Super DLTtape I 133000 bpi + SDLT1_133k = 0x48, + /// Super DLTtape I + SDLT1 = 0x49, + /// T10000A + T10000A = 0x4A, + /// Super DLTtape II + SDLT2 = 0x4A, + /// DLTtape S4 + DLTS4 = 0x4B, + /// T10000B + T10000B = 0x4B, + /// T10000C + T10000C = 0x4C, + /// T10000D + T10000D = 0x4D, + /// VStape I + VStape1 = 0x40, + /// Ultrium-5 + LTO5 = 0x58, + /// Ultrium-6 + LTO6 = 0x5A, + /// Ultrium-7 + LTO7 = 0x5C, + /// DLTtape III 62500 bpi secondary code + DLT3_62kAlt = 0x80, + /// VXA-1 + VXA1 = 0x80, + /// DLTtape III compressed + DLT3c = 0x81, + /// VXA-2 + VXA2 = 0x81, + /// DLTtape IV secondary code + DLT4Alt = 0x82, + /// VXA-3 + VXA3 = 0x82, + /// DLTtape IV compressed + DLT4c = 0x83, + /// DLTtape IV 85937 bpi secondary code + DLT4_85kAlt = 0x84, + /// DLTtape IV 85937 bpi compressed + DLT4c_85k = 0x85, + /// DLTtape IV 123090 bpi secondary code + DLT4_123kAlt = 0x86, + /// DLTtape IV 123090 bpi compressed + DLT4c_123k = 0x87, + /// DLTtape IV 98250 bpi secondary code + DLT4_98kAlt = 0x88, + /// DLTtape IV 98250 bpi compressed + DLT4c_98k = 0x89, + /// Exabyte compressed 8200 format + Ex8500c = 0x8C, + /// Exabyte compressed 8500 format + Ex8200c = 0x90, + /// Super DLTtape I secondary code + SDLT1Alt = 0x90, + /// Super DLTtape I compressed + SDLT1c = 0x91, + /// Super DLTtape I 133000 bpi secondary code + SDLT1_133kAlt = 0x92, + /// Super DLTtape I 133000 bpi compressed + SDLT1c_133k = 0x93, + /// VStape I secondary code + VStape1Alt = 0x98, + /// VStape I compressed + VStape1c = 0x99, + #endregion Density Types found in vendor documents } \ No newline at end of file diff --git a/SCSI/VendorString.cs b/SCSI/VendorString.cs index ca5a83d..8632074 100644 --- a/SCSI/VendorString.cs +++ b/SCSI/VendorString.cs @@ -30,814 +30,813 @@ // Copyright © 2011-2022 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Decoders.SCSI +namespace Aaru.Decoders.SCSI; + +public static class VendorString { - public static class VendorString + public static string Prettify(string scsiVendorString) { - public static string Prettify(string scsiVendorString) + switch(scsiVendorString) { - switch(scsiVendorString) - { - case "0B4C": return "MOOSIK Ltd."; - case "13FE": return "PHISON"; - case "2AI": return "2AI (Automatisme et Avenir Informatique)"; - case "3M": return "3M Company"; - case "3nhtech": return "3NH Technologies"; - case "3PARdata": return "3PARdata, Inc."; - case "A-Max": return "A-Max Technology Co., Ltd"; - case "ABSOLUTE": return "Absolute Analysis"; - case "ACARD": return "ACARD Technology Corp."; - case "Accusys": return "Accusys INC."; - case "Acer": return "Acer, Inc."; - case "ACL": return "Automated Cartridge Librarys, Inc."; - case "Actifio": return "Actifio"; - case "Acuid": return "Acuid Corporation Ltd."; - case "AcuLab": return "AcuLab, Inc. (Tulsa, OK)"; - case "ADAPTEC": return "Adaptec"; - case "ADIC": return "Advanced Digital Information Corporation"; - case "ADSI": return "Adaptive Data Systems, Inc. (a Western Digital subsidiary)"; - case "ADTX": return "ADTX Co., Ltd."; - case "ADVA": return "ADVA Optical Networking AG"; - case "AEM": return "AEM Performance Electronics"; - case "AERONICS": return "Aeronics, Inc."; - case "AGFA": return "AGFA"; - case "Agilent": return "Agilent Technologies"; - case "AIC": return "Advanced Industrial Computer, Inc."; - case "AIPTEK": return "AIPTEK International Inc."; - case "Alcohol": return "Alcohol Soft"; - case "ALCOR": return "Alcor Micro, Corp."; - case "AMCC": return "Applied Micro Circuits Corporation"; - case "AMCODYNE": return "Amcodyne"; - case "Amgeon": return "Amgeon LLC"; - case "AMI": return "American Megatrends, Inc."; - case "AMPEX": return "Ampex Data Systems"; - case "Amphenol": return "Amphenol"; - case "Amtl": return "Tenlon Technology Co.,Ltd"; - case "ANAMATIC": return "Anamartic Limited (England)"; - case "Ancor": return "Ancor Communications, Inc."; - case "ANCOT": return "ANCOT Corp."; - case "ANDATACO": return "Andataco"; - case "andiamo": return "Andiamo Systems, Inc."; - case "ANOBIT": return "Anobit"; - case "ANRITSU": return "Anritsu Corporation"; - case "ANTONIO": return "Antonio Precise Products Manufactory Ltd."; - case "AoT": return "Art of Technology AG"; - case "APPLE": return "Apple Computer, Inc."; - case "ARCHIVE": return "Archive"; - case "ARDENCE": return "Ardence Inc"; - case "Areca": return "Areca Technology Corporation"; - case "Arena": return "MaxTronic International Co., Ltd."; - case "Argent": return "Argent Data Systems, Inc."; - case "ARIO": return "Ario Data Networks, Inc."; - case "ARISTOS": return "Aristos Logic Corp."; - case "ARK": return "ARK Research Corporation"; - case "ARL:UT@A": return "Applied Research Laboratories : University of Texas at Austin"; - case "ARTECON": return "Artecon Inc."; - case "Artistic": return "Artistic Licence (UK) Ltd"; - case "ARTON": return "Arton Int."; - case "ASACA": return "ASACA Corp."; - case "ASC": return "Advanced Storage Concepts, Inc."; - case "ASPEN": return "Aspen Peripherals"; - case "AST": return "AST Research"; - case "ASTEK": return "Astek Corporation"; - case "ASTK": return "Alcatel STK A/S"; - case "AStor": return "AccelStor, Inc."; - case "ASTUTE": return "Astute Networks, Inc."; - case "AT&T": return "AT&T"; - case "ATA": return "SCSI / ATA Translator Software (Organization Not Specified)"; - case "ATARI": return "Atari Corporation"; - case "ATech": return "ATech electronics"; - case "ATG CYG": return "ATG Cygnet Inc."; - case "ATL": return "Quantum|ATL Products"; - case "ATTO": return "ATTO Technology Inc."; - case "ATTRATEC": return "Attratech Ltd liab. Co"; - case "ATX": return "Alphatronix"; - case "AURASEN": return "Aurasen Limited"; - case "Avago": return "Avago Technologies"; - case "AVC": return "AVC Technology Ltd"; - case "AVIDVIDR": return "AVID Technologies, Inc."; - case "AVR": return "Advanced Vision Research"; - case "AXSTOR": return "AXSTOR"; - case "Axxana": return "Axxana Ltd."; - case "B*BRIDGE": return "Blockbridge Networks LLC"; - case "BALLARD": return "Ballard Synergy Corp."; - case "Barco": return "Barco"; - case "BAROMTEC": return "Barom Technologies Co., Ltd."; - case "Bassett": return "Bassett Electronic Systems Ltd"; - case "BC Hydro": return "BC Hydro"; - case "BDT": return "BDT AG"; - case "BECEEM": return "Beceem Communications, Inc"; - case "BENQ": return "BENQ Corporation."; - case "BERGSWD": return "Berg Software Design"; - case "BEZIER": return "Bezier Systems, Inc."; - case "BHTi": return "Breece Hill Technologies"; - case "biodata": return "Biodata Devices SL"; - case "BIOS": return "BIOS Corporation"; - case "BIR": return "Bio-Imaging Research, Inc."; - case "BiT": return "BiT Microsystems"; - case "BITMICRO": return "BiT Microsystems, Inc."; - case "Blendlgy": return "Blendology Limited"; - case "BLOOMBAS": return "Bloombase Technologies Limited"; - case "BlueArc": return "BlueArc Corporation"; - case "bluecog": return "bluecog"; - case "BME-HVT": return "Broadband Infocommunicatons and Electromagnetic Theory Department"; - case "BNCHMARK": return "Benchmark Tape Systems Corporation"; - case "Bosch": return "Robert Bosch GmbH"; - case "Botman": return "Botmanfamily Electronics"; - case "BoxHill": return "Box Hill Systems Corporation"; - case "BRDGWRKS": return "Bridgeworks Ltd."; - case "BREA": return "BREA Technologies, Inc."; - case "BREECE": return "Breece Hill LLC"; - case "BreqLabs": return "BreqLabs Inc."; - case "Broadcom": return "Broadcom Corporation"; - case "BROCADE": return "Brocade Communications Systems, Incorporated"; - case "BUFFALO": return "BUFFALO INC."; - case "BULL": return "Bull Peripherals Corp."; - case "BUSLOGIC": return "BusLogic Inc."; - case "BVIRTUAL": return "B-Virtual N.V."; - case "CACHEIO": return "CacheIO LLC"; - case "CalComp": return "CalComp, A Lockheed Company"; - case "CALCULEX": return "CALCULEX, Inc."; - case "CALIPER": return "Caliper (California Peripheral Corp.)"; - case "CAMBEX": return "Cambex Corporation"; - case "CAMEOSYS": return "Cameo Systems Inc."; - case "CANDERA": return "Candera Inc."; - case "CAPTION": return "CAPTION BANK"; - case "CAST": return "Advanced Storage Tech"; - case "CATALYST": return "Catalyst Enterprises"; - case "CCDISK": return "iSCSI Cake"; - case "CDC": return "Control Data or MPI"; - case "CDP": return "Columbia Data Products"; - case "Celsia": return "A M Bromley Limited"; - case "CenData": return "Central Data Corporation"; - case "Cereva": return "Cereva Networks Inc."; - case "CERTANCE": return "Certance"; - case "Chantil": return "Chantil Technology"; - case "CHEROKEE": return "Cherokee Data Systems"; - case "CHINON": return "Chinon"; - case "CHRISTMA": return "Christmann Informationstechnik + Medien GmbH & Co KG"; - case "CIE&YED": return "YE Data, C.Itoh Electric Corp."; - case "CIPHER": return "Cipher Data Products"; - case "Ciprico": return "Ciprico, Inc."; - case "CIRRUSL": return "Cirrus Logic Inc."; - case "CISCO": return "Cisco Systems, Inc."; - case "CLEARSKY": return "ClearSky Data, Inc."; - case "CLOVERLF": return "Cloverleaf Communications, Inc"; - case "CLS": return "Celestica"; - case "CMD": return "CMD Technology Inc."; - case "CMTechno": return "CMTech"; - case "CNGR SFW": return "Congruent Software, Inc."; - case "CNSi": return "Chaparral Network Storage, Inc."; - case "CNT": return "Computer Network Technology"; - case "COBY": return "Coby Electronics Corporation, USA"; - case "COGITO": return "Cogito"; - case "COMAY": return "Corerise Electronics"; - case "COMPAQ": return "Compaq Computer Corporation"; - case "COMPELNT": return "Compellent Technologies, Inc."; - case "COMPORT": return "Comport Corp."; - case "COMPSIG": return "Computer Signal Corporation"; - case "COMPTEX": return "Comptex Pty Limited"; - case "CONNER": return "Conner Peripherals"; - case "COPANSYS": return "COPAN SYSTEMS INC"; - case "CORAID": return "Coraid, Inc"; - case "CORE": return "Core International, Inc."; - case "CORERISE": return "Corerise Electronics"; - case "COVOTE": return "Covote GmbH & Co KG"; - case "COWON": return "COWON SYSTEMS, Inc."; - case "CPL": return "Cross Products Ltd"; - case "CPU TECH": return "CPU Technology, Inc."; - case "CREO": return "Creo Products Inc."; - case "CROSFLD": return "Crosfield Electronics"; - case "CROSSRDS": return "Crossroads Systems, Inc."; - case "crosswlk": return "Crosswalk, Inc."; - case "CSCOVRTS": return "Cisco - Veritas"; - case "CSM, INC": return "Computer SM, Inc."; - case "Cunuqui": return "CUNUQUI SLU"; - case "CYBERNET": return "Cybernetics"; - case "Cygnal": return "Dekimo"; - case "CYPRESS": return "Cypress Semiconductor Corp."; - case "D Bit": return "Digby's Bitpile, Inc. DBA D Bit"; - case "DALSEMI": return "Dallas Semiconductor"; - case "DANEELEC": return "Dane-Elec"; - case "DANGER": return "Danger Inc."; - case "DAT-MG": return "DAT Manufacturers Group"; - case "Data Com": return "Data Com Information Systems Pty. Ltd."; - case "DATABOOK": return "Databook, Inc."; - case "DATACOPY": return "Datacopy Corp."; - case "DataCore": return "DataCore Software Corporation"; - case "DataG": return "DataGravity"; - case "DATAPT": return "Datapoint Corp."; - case "DATARAM": return "Dataram Corporation"; - case "DATC": return "Datum Champion Technology Co., Ltd"; - case "DAVIS": return "Daviscomms (S) Pte Ltd"; - case "DCS": return "ShenZhen DCS Group Co.,Ltd"; - case "DDN": return "DataDirect Networks, Inc."; - case "DDRDRIVE": return "DDRdrive LLC"; - case "DE": return "Dimension Engineering LLC"; - case "DEC": return "Digital Equipment Corporation"; - case "DEI": return "Digital Engineering, Inc."; - case "DELL": return "Dell, Inc."; - case "Dell(tm)": return "Dell, Inc"; - case "DELPHI": return "Delphi Data Div. of Sparks Industries, Inc."; - case "DENON": return "Denon/Nippon Columbia"; - case "DenOptix": return "DenOptix, Inc."; - case "DEST": return "DEST Corp."; - case "DFC": return "DavioFranke.com"; - case "DFT": return "Data Fault Tolerance System CO.,LTD."; - case "DGC": return "Data General Corp."; - case "DIGIDATA": return "Digi-Data Corporation"; - case "DigiIntl": return "Digi International"; - case "Digital": return "Digital Equipment Corporation"; - case "DILOG": return "Distributed Logic Corp."; - case "DISC": return "Document Imaging Systems Corp."; - case "DiscSoft": return "Disc Soft Ltd"; - case "DLNET": return "Driveline"; - case "DNS": return "Data and Network Security"; - case "DNUK": return "Digital Networks Uk Ltd"; - case "DotHill": return "Dot Hill Systems Corp."; - case "DP": return "Dell, Inc."; - case "DPT": return "Distributed Processing Technology"; - case "Drewtech": return "Drew Technologies, Inc."; - case "DROBO": return "Data Robotics, Inc."; - case "DSC": return "DigitalStream Corporation"; - case "DSI": return "Data Spectrum, Inc."; - case "DSM": return "Deterner Steuerungs- und Maschinenbau GmbH & Co."; - case "DSNET": return "Cleversafe, Inc."; - case "DT": return "Double-Take Software, INC."; - case "DTC QUME": return "Data Technology Qume"; - case "DXIMAGIN": return "DX Imaging"; - case "E-Motion": return "E-Motion LLC"; - case "EARTHLAB": return "EarthLabs"; - case "EarthLCD": return "Earth Computer Technologies, Inc."; - case "ECCS": return "ECCS, Inc."; - case "ECMA": return "European Computer Manufacturers Association"; - case "EDS": return "Embedded Data Systems"; - case "EIM": return "InfoCore"; - case "ELE Intl": return "ELE International"; - case "ELEGANT": return "Elegant Invention, LLC"; - case "Elektron": return "Elektron Music Machines MAV AB"; - case "elipsan": return "Elipsan UK Ltd."; - case "Elms": return "Elms Systems Corporation"; - case "ELSE": return "ELSE Ltd."; - case "ELSEC": return "Littlemore Scientific"; - case "EMASS": return "EMASS, Inc."; - case "EMC": return "EMC Corp."; - case "EMiT": return "EMiT Conception Eletronique"; - case "EMTEC": return "EMTEC Magnetics"; - case "EMULEX": return "Emulex"; - case "ENERGY-B": return "Energybeam Corporation"; - case "ENGENIO": return "Engenio Information Technologies, Inc."; - case "ENMOTUS": return "Enmotus Inc"; - case "Entacore": return "Entacore"; - case "EPOS": return "EPOS Technologies Ltd."; - case "EPSON": return "Epson"; - case "EQLOGIC": return "EqualLogic"; - case "Eris/RSI": return "RSI Systems, Inc."; - case "ETERNE": return "EterneData Technology Co.,Ltd.(China PRC.)"; - case "EuroLogc": return "Eurologic Systems Limited"; - case "evolve": return "Evolution Technologies, Inc"; - case "EXABYTE": return "Exabyte Corp."; - case "EXATEL": return "Exatelecom Co., Ltd."; - case "EXAVIO": return "Exavio, Inc."; - case "Exsequi": return "Exsequi Ltd"; - case "Exxotest": return "Annecy Electronique"; - case "FAIRHAVN": return "Fairhaven Health, LLC"; - case "FALCON": return "FalconStor, Inc."; - case "FDS": return "Formation Data Systems"; - case "FFEILTD": return "FujiFilm Electonic Imaging Ltd"; - case "Fibxn": return "Fiberxon, Inc."; - case "FID": return "First International Digital, Inc."; - case "FILENET": return "FileNet Corp."; - case "FirmFact": return "Firmware Factory Ltd"; - case "FLYFISH": return "Flyfish Technologies"; - case "FOXCONN": return "Foxconn Technology Group"; - case "FRAMDRV": return "FRAMEDRIVE Corp."; - case "FREECION": return "Nable Communications, Inc."; - case "FRESHDTK": return "FreshDetect GmbH"; - case "FSC": return "Fujitsu Siemens Computers"; - case "FTPL": return "Frontline Technologies Pte Ltd"; - case "FUJI": return "Fuji Electric Co., Ltd. (Japan)"; - case "FUJIFILM": return "Fuji Photo Film, Co., Ltd."; - case "FUJITSU": return "Fujitsu"; - case "FUNAI": return "Funai Electric Co., Ltd."; - case "FUSIONIO": return "Fusion-io Inc."; - case "FUTURED": return "Future Domain Corp."; - case "G&D": return "Giesecke & Devrient GmbH"; - case "G.TRONIC": return "Globaltronic - Electronica e Telecomunicacoes, S.A."; - case "Gadzoox": return "Gadzoox Networks, Inc."; - case "Gammaflx": return "Gammaflux L.P."; - case "GDI": return "Generic Distribution International"; - case "GEMALTO": return "gemalto"; - case "Gen_Dyn": return "General Dynamics"; - case "Generic": return "Generic Technology Co., Ltd."; - case "GENSIG": return "General Signal Networks"; - case "GEO": return "Green Energy Options Ltd"; - case "GIGATAPE": return "GIGATAPE GmbH"; - case "GIGATRND": return "GigaTrend Incorporated"; - case "Global": return "Global Memory Test Consortium"; - case "Gnutek": return "Gnutek Ltd."; - case "Goidelic": return "Goidelic Precision, Inc."; - case "GoldKey": return "GoldKey Security Corporation"; - case "GoldStar": return "LG Electronics Inc."; - case "GOOGLE": return "Google, Inc."; - case "GORDIUS": return "Gordius"; - case "GOULD": return "Gould"; - case "HAGIWARA": return "Hagiwara Sys-Com Co., Ltd."; - case "HAPP3": return "Inventec Multimedia and Telecom co., ltd"; - case "HDS": return "Horizon Data Systems, Inc."; - case "Helldyne": return "Helldyne, Inc"; - case "Heydays": return "Mazo Technology Co., Ltd."; - case "HGST": return "HGST a Western Digital Company"; - case "HI-TECH": return "HI-TECH Software Pty. Ltd."; - case "HITACHI": return "Hitachi America Ltd or Nissei Sangyo America Ltd"; - case "HL-DT-ST": return "Hitachi-LG Data Storage, Inc."; - case "HONEYWEL": return "Honeywell Inc."; - case "Hoptroff": return "HexWax Ltd"; - case "HORIZONT": return "Horizontigo Software"; - case "HP": return "Hewlett Packard"; - case "HPE": return "Hewlett Packard Enterprise"; - case "HPI": return "HP Inc."; - case "HPQ": return "Hewlett Packard"; - case "HUALU": return "CHINA HUALU GROUP CO., LTD"; - case "HUASY": return "Huawei Symantec Technologies Co., Ltd."; - case "HYLINX": return "Hylinx Ltd."; - case "HYUNWON": return "HYUNWON inc"; - case "i-cubed": return "i-cubed ltd."; - case "IBM": return "International Business Machines"; - case "Icefield": return "Icefield Tools Corporation"; - case "Iceweb": return "Iceweb Storage Corp"; - case "ICL": return "ICL"; - case "ICP": return "ICP vortex Computersysteme GmbH"; - case "IDE": return "International Data Engineering, Inc."; - case "IDG": return "Interface Design Group"; - case "IET": return "ISCSI ENTERPRISE TARGET"; - case "IFT": return "Infortrend Technology, Inc."; - case "IGR": return "Intergraph Corp."; - case "IMAGINE": return "Imagine Communications Corp."; - case "IMAGO": return "IMAGO SOFTWARE SL"; - case "IMATION": return "Imation"; - case "IMPLTD": return "Integrated Micro Products Ltd."; - case "IMPRIMIS": return "Imprimis Technology Inc."; - case "INCIPNT": return "Incipient Technologies Inc."; - case "INCITS": return "InterNational Committee for Information Technology"; - case "INDCOMP": return "Industrial Computing Limited"; - case "Indigita": return "Indigita Corporation"; - case "INFOCORE": return "InfoCore"; - case "INITIO": return "Initio Corporation"; - case "INRANGE": return "INRANGE Technologies Corporation"; - case "Insight": return "L-3 Insight Technology Inc"; - case "INSITE": return "Insite Peripherals"; - case "integrix": return "Integrix, Inc."; - case "INTEL": return "Intel Corporation"; - case "Intransa": return "Intransa, Inc."; - case "IOC": return "I/O Concepts, Inc."; - case "iofy": return "iofy Corporation"; - case "IOMEGA": return "Iomega"; - case "IOT": return "IO Turbine, Inc."; - case "iPaper": return "intelliPaper, LLC"; - case "iqstor": return "iQstor Networks, Inc."; - case "iQue": return "iQue"; - case "ISi": return "Information Storage inc."; - case "Isilon": return "Isilon Systems, Inc."; - case "ISO": return "International Standards Organization"; - case "iStor": return "iStor Networks, Inc."; - case "ITC": return "International Tapetronics Corporation"; - case "iTwin": return "iTwin Pte Ltd"; - case "IVIVITY": return "iVivity, Inc."; - case "IVMMLTD": return "InnoVISION Multimedia Ltd."; - case "JABIL001": return "Jabil Circuit"; - case "JETWAY": return "Jetway Information Co., Ltd"; - case "JMR": return "JMR Electronics Inc."; - case "JOFEMAR": return "Jofemar"; - case "JOLLYLOG": return "Jolly Logic"; - case "JPC Inc.": return "JPC Inc."; - case "JSCSI": return "jSCSI Project"; - case "Juniper": return "Juniper Networks"; - case "JVC": return "JVC Information Products Co."; - case "KASHYA": return "Kashya, Inc."; - case "KENNEDY": return "Kennedy Company"; - case "KENWOOD": return "KENWOOD Corporation"; - case "KEWL": return "Shanghai KEWL Imp&Exp Co., Ltd."; - case "Key Tech": return "Key Technologies, Inc"; - case "KMNRIO": return "Kaminario Technologies Ltd."; - case "KODAK": return "Eastman Kodak"; - case "KONAN": return "Konan"; - case "koncepts": return "koncepts International Ltd."; - case "KONICA": return "Konica Japan"; - case "KOVE": return "KOVE"; - case "KSCOM": return "KSCOM Co. Ltd.,"; - case "KUDELSKI": return "Nagravision SA - Kudelski Group"; - case "Kyocera": return "Kyocera Corporation"; - case "Lapida": return "Gonmalo Electronics"; - case "LAPINE": return "Lapine Technology"; - case "LASERDRV": return "LaserDrive Limited"; - case "LASERGR": return "Lasergraphics, Inc."; - case "LeapFrog": return "LeapFrog Enterprises, Inc."; - case "LEFTHAND": return "LeftHand Networks"; - case "Leica": return "Leica Camera AG"; - case "Lexar": return "Lexar Media, Inc."; - case "LEYIO": return "LEYIO"; - case "LG": return "LG Electronics Inc."; - case "LGE": return "LG Electronics Inc."; - case "LIBNOVA": return "LIBNOVA, SL Digital Preservation Systems"; - case "LION": return "Lion Optics Corporation"; - case "LMS": return "Laser Magnetic Storage International Company"; - case "LoupTech": return "Loup Technologies, Inc."; - case "LSI": return "LSI Corp. (was LSI Logic Corp.)"; - case "LSILOGIC": return "LSI Logic Storage Systems, Inc."; - case "LTO-CVE": return "Linear Tape - Open, Compliance Verification Entity"; - case "LUXPRO": return "Luxpro Corporation"; - case "MacroSAN": return "MacroSAN Technologies Co., Ltd."; - case "Malakite": return "Malachite Technologies (New VID is: Sandial)"; - case "MarcBoon": return "marcboon.com"; - case "Marner": return "Marner Storage Technologies, Inc."; - case "MARVELL": return "Marvell Semiconductor, Inc."; - case "Matrix": return "Matrix Orbital Corp."; - case "MATSHITA": return "Matsushita"; - case "MAXELL": return "Hitachi Maxell, Ltd."; - case "MAXIM-IC": return "Maxim Integrated Products"; - case "MaxOptix": return "Maxoptix Corp."; - case "MAXSTRAT": return "Maximum Strategy, Inc."; - case "MAXTOR": return "Maxtor Corp."; - case "MaXXan": return "MaXXan Systems, Inc."; - case "MAYCOM": return "maycom Co., Ltd."; - case "MBEAT": return "K-WON C&C Co.,Ltd"; - case "MCC": return "Measurement Computing Corporation"; - case "McDATA": return "McDATA Corporation"; - case "MCUBE": return "Mcube Technology Co., Ltd."; - case "MDI": return "Micro Design International, Inc."; - case "MEADE": return "Meade Instruments Corporation"; - case "mediamat": return "mediamatic"; - case "MegaElec": return "Mega Electronics Ltd"; - case "MEII": return "Mountain Engineering II, Inc."; - case "MELA": return "Mitsubishi Electronics America"; - case "MELCO": return "Mitsubishi Electric (Japan)"; - case "mellanox": return "Mellanox Technologies Ltd."; - case "MEMOREX": return "Memorex Telex Japan Ltd."; - case "MEMREL": return "Memrel Corporation"; - case "MEMTECH": return "MemTech Technology"; - case "Mendocin": return "Mendocino Software"; - case "MendoCno": return "Mendocino Software"; - case "MERIDATA": return "Oy Meridata Finland Ltd"; - case "METHODEI": return "Methode Electronics India pvt ltd"; - case "METRUM": return "Metrum, Inc."; - case "MHTL": return "Matsunichi Hi-Tech Limited"; - case "MICROBTX": return "Microbotics Inc."; - case "Microchp": return "Microchip Technology, Inc."; - case "MICROLIT": return "Microlite Corporation"; - case "MICRON": return "Micron Technology, Inc."; - case "MICROP": return "Micropolis"; - case "MICROTEK": return "Microtek Storage Corp"; - case "Minitech": return "Minitech (UK) Limited"; - case "Minolta": return "Minolta Corporation"; - case "MINSCRIB": return "Miniscribe"; - case "MiraLink": return "MiraLink Corporation"; - case "Mirifica": return "Mirifica s.r.l."; - case "MITSUMI": return "Mitsumi Electric Co., Ltd."; - case "MKM": return "Mitsubishi Kagaku Media Co., LTD."; - case "Mobii": return "Mobii Systems (Pty.) Ltd."; - case "MOL": return "Petrosoft Sdn. Bhd."; - case "MOSAID": return "Mosaid Technologies Inc."; - case "MOTOROLA": return "Motorola"; - case "MP-400": return "Daiwa Manufacturing Limited"; - case "MPC": return "MPC Corporation"; - case "MPCCORP": return "MPC Computers"; - case "MPEYE": return "Touchstone Technology Co., Ltd"; - case "MPIO": return "DKT Co.,Ltd"; - case "MPM": return "Mitsubishi Paper Mills, Ltd."; - case "MPMan": return "MPMan.com, Inc."; - case "MSFT": return "Microsoft Corporation"; - case "MSI": return "Micro-Star International Corp."; - case "MST": return "Morning Star Technologies, Inc."; - case "MSystems": return "M-Systems Flash Disk Pioneers"; - case "MTI": return "MTI Technology Corporation"; - case "MTNGATE": return "MountainGate Data Systems"; - case "MXI": return "Memory Experts International"; - case "nac": return "nac Image Technology Inc."; - case "NAGRA": return "Nagravision SA - Kudelski Group"; - case "NAI": return "North Atlantic Industries"; - case "NAKAMICH": return "Nakamichi Corporation"; - case "NatInst": return "National Instruments"; - case "NatSemi": return "National Semiconductor Corp."; - case "NCITS": return "InterNational Committee for Information Technology Standards (INCITS)"; - case "NCL": return "NCL America"; - case "NCR": return "NCR Corporation"; - case "NDBTECH": return "NDB Technologie Inc."; - case "Neartek": return "Neartek, Inc."; - case "NEC": return "NEC"; - case "NETAPP": return "NetApp, Inc. (was Network Appliance)"; - case "NetBSD": return "The NetBSD Foundation"; - case "Netcom": return "Netcom Storage"; - case "NETENGIN": return "NetEngine, Inc."; - case "NEWISYS": return "Newisys Data Storage"; - case "Newtech": return "Newtech Co., Ltd."; - case "NEXSAN": return "Nexsan Technologies, Ltd."; - case "NFINIDAT": return "Infinidat Ltd."; - case "NHR": return "NH Research, Inc."; - case "Nike": return "Nike, Inc."; - case "Nimble": return "Nimble Storage"; - case "NISCA": return "NISCA Inc."; - case "NISHAN": return "Nishan Systems Inc."; - case "Nitz": return "Nitz Associates, Inc."; - case "NKK": return "NKK Corp."; - case "NRC": return "Nakamichi Research Corporation"; - case "NSD": return "Nippon Systems Development Co.,Ltd."; - case "NSM": return "NSM Jukebox GmbH"; - case "nStor": return "nStor Technologies, Inc."; - case "NT": return "Northern Telecom"; - case "NUCONNEX": return "NuConnex"; - case "NUSPEED": return "NuSpeed, Inc."; - case "NVIDIA": return "NVIDIA Corporation"; - case "NVMe": return "NVM Express Working Group"; - case "OAI": return "Optical Access International"; - case "OCE": return "Oce Graphics"; - case "ODS": return "ShenZhen DCS Group Co.,Ltd"; - case "OHDEN": return "Ohden Co., Ltd."; - case "OKI": return "OKI Electric Industry Co.,Ltd (Japan)"; - case "Olidata": return "Olidata S.p.A."; - case "OMI": return "Optical Media International"; - case "OMNIFI": return "Rockford Corporation - Omnifi Media"; - case "OMNIS": return "OMNIS Company (FRANCE)"; - case "Ophidian": return "Ophidian Designs"; - case "opslag": return "Tyrone Systems"; - case "Optelec": return "Optelec BV"; - case "Optiarc": return "Sony Optiarc Inc."; - case "OPTIMEM": return "Cipher/Optimem"; - case "OPTOTECH": return "Optotech"; - case "ORACLE": return "Oracle Corporation"; - case "ORANGE": return "Orange Micro, Inc."; - case "ORCA": return "Orca Technology"; - case "Origin": return "Origin Energy"; - case "OSI": return "Optical Storage International"; - case "OSNEXUS": return "OS NEXUS, Inc."; - case "OTL": return "OTL Engineering"; - case "OVERLAND": return "Overland Storage Inc."; - case "pacdigit": return "Pacific Digital Corp"; - case "Packard": return "Parkard Bell"; - case "Panasas": return "Panasas, Inc."; - case "PARALAN": return "Paralan Corporation"; - case "PASCOsci": return "Pasco Scientific"; - case "PATHLGHT": return "Pathlight Technology, Inc."; - case "PCS": return "Pro Charging Systems, LLC"; - case "PerStor": return "Perstor"; - case "PERTEC": return "Pertec Peripherals Corporation"; - case "PFTI": return "Performance Technology Inc."; - case "PFU": return "PFU Limited"; - case "Phigment": return "Phigment Technologies"; - case "PHILIPS": return "Philips Electronics"; - case "PICO": return "Packard Instrument Company"; - case "PIK": return "TECHNILIENT & MCS"; - case "Pillar": return "Pillar Data Systems"; - case "PIONEER": return "Pioneer Electronic Corp."; - case "Pirus": return "Pirus Networks"; - case "PIVOT3": return "Pivot3, Inc."; - case "PLASMON": return "Plasmon Data"; - case "Pliant": return "Pliant Technology, Inc."; - case "PMCSIERA": return "PMC-Sierra"; - case "PME": return "Precision Measurement Engineering"; - case "PNNMed": return "PNN Medical SA"; - case "POKEN": return "Poken SA"; - case "POLYTRON": return "PT. HARTONO ISTANA TEKNOLOGI"; - case "PRAIRIE": return "PrairieTek"; - case "PREPRESS": return "PrePRESS Solutions"; - case "PRESOFT": return "PreSoft Architects"; - case "PRESTON": return "Preston Scientific"; - case "PRIAM": return "Priam"; - case "PRIMAGFX": return "Primagraphics Ltd"; - case "PRIMOS": return "Primos"; - case "PROCOM": return "Procom Technology"; - case "PROLIFIC": return "Prolific Technology Inc."; - case "PROMISE": return "PROMISE TECHNOLOGY, Inc"; - case "PROSTOR": return "ProStor Systems, Inc."; - case "PROSUM": return "PROSUM"; - case "PROWARE": return "Proware Technology Corp."; - case "PTI": return "Peripheral Technology Inc."; - case "PTICO": return "Pacific Technology International"; - case "PURE": return "PURE Storage"; - case "Qi-Hardw": return "Qi Hardware"; - case "QIC": return "Quarter-Inch Cartridge Drive Standards, Inc."; - case "QLogic": return "QLogic Corporation"; - case "QNAP": return "QNAP Systems"; - case "Qsan": return "QSAN Technology, Inc."; - case "QUALSTAR": return "Qualstar"; - case "QUANTEL": return "Quantel Ltd."; - case "QUANTUM": return "Quantum Corp."; - case "QUIX": return "Quix Computerware AG"; - case "R-BYTE": return "R-Byte, Inc."; - case "RACALREC": return "Racal Recorders"; - case "RADITEC": return "Radikal Technologies Deutschland GmbH"; - case "RADSTONE": return "Radstone Technology"; - case "RAIDINC": return "RAID Inc."; - case "RASSYS": return "Rasilient Systems Inc."; - case "RASVIA": return "Rasvia Systems, Inc."; - case "rave-mp": return "Go Video"; - case "RDKMSTG": return "MMS Dipl. Ing. Rolf-Dieter Klein"; - case "RDStor": return "Rorke China"; - case "Readboy": return "Readboy Ltd Co."; - case "Realm": return "Realm Systems"; - case "realtek": return "Realtek Semiconductor Corp."; - case "REDUXIO": return "Reduxio Systems Ltd."; - case "rehanltd": return "Rehan Electronics Ltd"; - case "REKA": return "REKA HEALTH PTE LTD"; - case "RELDATA": return "RELDATA Inc"; - case "RENAGmbH": return "RENA GmbH"; - case "ReThinkM": return "RETHINK MEDICAL, INC"; - case "Revivio": return "Revivio, Inc."; - case "RGBLaser": return "RGB Lasersysteme GmbH"; - case "RGI": return "Raster Graphics, Inc."; - case "RHAPSODY": return "Rhapsody Networks, Inc."; - case "RHS": return "Racal-Heim Systems GmbH"; - case "RICOH": return "Ricoh"; - case "RODIME": return "Rodime"; - case "Rorke": return "RD DATA Technology (ShenZhen) Limited"; - case "Royaltek": return "RoyalTek company Ltd."; - case "RPS": return "RPS"; - case "RTI": return "Reference Technology"; - case "S-D": return "Sauer-Danfoss"; - case "S-flex": return "Storageflex Inc"; - case "S-SYSTEM": return "S-SYSTEM"; - case "S1": return "storONE"; - case "SAMSUNG": return "Samsung Electronics Co., Ltd."; - case "SAN": return "Storage Area Networks, Ltd."; - case "Sandial": return "Sandial Systems, Inc."; - case "SanDisk": return "SanDisk Corporation"; - case "SANKYO": return "Sankyo Seiki"; - case "SANRAD": return "SANRAD Inc."; - case "SANYO": return "SANYO Electric Co., Ltd."; - case "SC.Net": return "StorageConnections.Net"; - case "SCALE": return "Scale Computing, Inc."; - case "SCIENTEK": return "SCIENTEK CORP"; - case "SCInc.": return "Storage Concepts, Inc."; - case "SCREEN": return "Dainippon Screen Mfg. Co., Ltd."; - case "SDI": return "Storage Dimensions, Inc."; - case "SDS": return "Solid Data Systems"; - case "SEAC": return "SeaChange International, Inc."; - case "SEAGATE": return "Seagate"; - case "SEAGRAND": return "SEAGRAND In Japan"; - case "Seanodes": return "Seanodes"; - case "Sec. Key": return "SecureKey Technologies Inc."; - case "SEQUOIA": return "Sequoia Advanced Technologies, Inc."; - case "SGI": return "Silicon Graphics International"; - case "Shannon": return "Shannon Systems Co., Ltd."; - case "Shinko": return "Shinko Electric Co., Ltd."; - case "SIEMENS": return "Siemens"; - case "SigmaTel": return "SigmaTel, Inc."; - case "SII": return "Seiko Instruments Inc."; - case "SIMPLE": return "SimpleTech, Inc."; - case "SIVMSD": return "IMAGO SOFTWARE SL"; - case "SKhynix": return "SK hynix Inc."; - case "SLCNSTOR": return "SiliconStor, Inc."; - case "SLI": return "Sierra Logic, Inc."; - case "SMCI": return "Super Micro Computer, Inc."; - case "SmrtStor": return "Smart Storage Systems"; - case "SMS": return "Scientific Micro Systems/OMTI"; - case "SMSC": return "SMSC Storage, Inc."; - case "SMX": return "Smartronix, Inc."; - case "SNYSIDE": return "Sunnyside Computing Inc."; - case "SoftLock": return "Softlock Digital Security Provider"; - case "SolidFir": return "SolidFire, Inc."; - case "SONIC": return "Sonic Solutions"; - case "SoniqCas": return "SoniqCast"; - case "SONY": return "Sony Corporation Japan"; - case "SOUL": return "Soul Storage Technology (Wuxi) Co., Ltd"; - case "SPD": return "Storage Products Distribution, Inc."; - case "SPECIAL": return "Special Computing Co."; - case "SPECTRA": return "Spectra Logic, a Division of Western Automation Labs, Inc."; - case "SPERRY": return "Sperry"; - case "Spintso": return "Spintso International AB"; - case "STARBORD": return "Starboard Storage Systems, Inc."; - case "STARWIND": return "StarWind Software, Inc."; - case "STEC": return "STEC, Inc."; - case "Sterling": return "Sterling Diagnostic Imaging, Inc."; - case "STK": return "Storage Technology Corporation"; - case "STNWOOD": return "Stonewood Group"; - case "STONEFLY": return "StoneFly Networks, Inc."; - case "STOR": return "StorageNetworks, Inc."; - case "STORAPP": return "StorageApps, Inc."; - case "STORCIUM": return "Intelligent Systems Services Inc."; - case "STORCOMP": return "Storage Computer Corporation"; - case "STORM": return "Storm Technology, Inc."; - case "StorMagc": return "StorMagic"; - case "Stratus": return "Stratus Technologies"; - case "StrmLgc": return "StreamLogic Corp."; - case "SUMITOMO": return "Sumitomo Electric Industries, Ltd."; - case "SUN": return "Sun Microsystems, Inc."; - case "SUNCORP": return "SunCorporation"; - case "suntx": return "Suntx System Co., Ltd"; - case "SUSE": return "SUSE Linux"; - case "Swinxs": return "Swinxs BV"; - case "SYMANTEC": return "Symantec Corporation"; - case "SYMBIOS": return "Symbios Logic Inc."; - case "SYMWAVE": return "Symwave, Inc."; - case "SYNCSORT": return "Syncsort Incorporated"; - case "SYNERWAY": return "Synerway"; - case "SYNOLOGY": return "Synology, Inc."; - case "SyQuest": return "SyQuest Technology, Inc."; - case "SYSGEN": return "Sysgen"; - case "T-MITTON": return "Transmitton England"; - case "T-MOBILE": return "T-Mobile USA, Inc."; - case "T11": return "INCITS Technical Committee T11"; - case "TALARIS": return "Talaris Systems, Inc."; - case "TALLGRAS": return "Tallgrass Technologies"; - case "TANDBERG": return "Tandberg Data A/S"; - case "TANDEM": return "Tandem"; - case "TANDON": return "Tandon"; - case "TCL": return "TCL Shenzhen ASIC MIcro-electronics Ltd"; - case "TDK": return "TDK Corporation"; - case "TEAC": return "TEAC Japan"; - case "TECOLOTE": return "Tecolote Designs"; - case "TEGRA": return "Tegra Varityper"; - case "Teilch": return "Teilch"; - case "Tek": return "Tektronix"; - case "TELLERT": return "Tellert Elektronik GmbH"; - case "TENTIME": return "Laura Technologies, Inc."; - case "TFDATACO": return "TimeForge"; - case "TGEGROUP": return "TGE Group Co.,LTD."; - case "Thecus": return "Thecus Technology Corp."; - case "TI-DSG": return "Texas Instruments"; - case "TiGi": return "TiGi Corporation"; - case "TILDESGN": return "Tildesign bv"; - case "Tite": return "Tite Technology Limited"; - case "TKS Inc.": return "TimeKeeping Systems, Inc."; - case "TLMKS": return "Telemakus LLC"; - case "TMS": return "Texas Memory Systems, Inc."; - case "TMS100": return "TechnoVas"; - case "TOLISGRP": return "The TOLIS Group"; - case "TOSHIBA": return "Toshiba Japan"; - case "TOYOU": return "TOYOU FEIJI ELECTRONICS CO.,LTD."; - case "Tracker": return "Tracker, LLC"; - case "TRIOFLEX": return "Trioflex Oy"; - case "TRIPACE": return "Tripace"; - case "TRLogger": return "TrueLogger Ltd."; - case "TROIKA": return "Troika Networks, Inc."; - case "TRULY": return "TRULY Electronics MFG. LTD."; - case "TRUSTED": return "Trusted Data Corporation"; - case "TSSTcorp": return "Toshiba Samsung Storage Technology Corporation"; - case "TZM": return "TZ Medical"; - case "UD-DVR": return "Bigstone Project."; - case "UDIGITAL": return "United Digital Limited"; - case "UIT": return "United Infomation Technology"; - case "ULTRA": return "UltraStor Corporation"; - case "UNISTOR": return "Unistor Networks, Inc."; - case "UNISYS": return "Unisys"; - case "USCORE": return "Underscore, Inc."; - case "USDC": return "US Design Corp."; - case "Top VASCO": return "Vasco Data Security"; - case "VDS": return "Victor Data Systems Co., Ltd."; - case "VELDANA": return "VELDANA MEDICAL SA"; - case "VENTANA": return "Ventana Medical Systems"; - case "Verari": return "Verari Systems, Inc."; - case "VERBATIM": return "Verbatim Corporation"; - case "Vercet": return "Vercet LLC"; - case "VERITAS": return "VERITAS Software Corporation"; - case "Vexata": return "Vexata Inc"; - case "VEXCEL": return "VEXCEL IMAGING GmbH"; - case "VICOMSL1": return "Vicom Systems, Inc."; - case "VicomSys": return "Vicom Systems, Inc."; - case "VIDEXINC": return "Videx, Inc."; - case "VIOLIN": return "Violin Memory, Inc."; - case "VIRIDENT": return "Virident Systems, Inc."; - case "VITESSE": return "Vitesse Semiconductor Corporation"; - case "VIXEL": return "Vixel Corporation"; - case "VLS": return "Van Lent Systems BV"; - case "VMAX": return "VMAX Technologies Corp."; - case "VMware": return "VMware Inc."; - case "Vobis": return "Vobis Microcomputer AG"; - case "VOLTAIRE": return "Voltaire Ltd."; - case "VRC": return "Vermont Research Corp."; - case "VRugged": return "Vanguard Rugged Storage"; - case "VTGadget": return "Vermont Gadget Company"; - case "Waitec": return "Waitec NV"; - case "WangDAT": return "WangDAT"; - case "WANGTEK": return "Wangtek"; - case "Wasabi": return "Wasabi Systems"; - case "WAVECOM": return "Wavecom"; - case "WD": return "Western Digital Corporation"; - case "WDC": return "Western Digital Corporation"; - case "WDIGTL": return "Western Digital"; - case "WDTI": return "Western Digital Technologies, Inc."; - case "WEARNES": return "Wearnes Technology Corporation"; - case "WeeraRes": return "Weera Research Pte Ltd"; - case "Wildflwr": return "Wildflower Technologies, Inc."; - case "WSC0001": return "Wisecom, Inc."; - case "X3": return "InterNational Committee for Information Technology Standards (INCITS)"; - case "XEBEC": return "Xebec Corporation"; - case "XENSRC": return "XenSource, Inc."; - case "Xerox": return "Xerox Corporation"; - case "XIOtech": return "XIOtech Corporation"; - case "XIRANET": return "Xiranet Communications GmbH"; - case "XIV": return "XIV"; - case "XtremIO": return "XtremIO"; - case "XYRATEX": return "Xyratex"; - case "YINHE": return "NUDT Computer Co."; - case "YIXUN": return "Yixun Electronic Co.,Ltd."; - case "YOTTA": return "YottaYotta, Inc."; - case "Zarva": return "Zarva Digital Technology Co., Ltd."; - case "ZETTA": return "Zetta Systems, Inc."; - case "ZTE": return "ZTE Corporation"; - case "ZVAULT": return "Zetavault"; - default: return scsiVendorString; - } + case "0B4C": return "MOOSIK Ltd."; + case "13FE": return "PHISON"; + case "2AI": return "2AI (Automatisme et Avenir Informatique)"; + case "3M": return "3M Company"; + case "3nhtech": return "3NH Technologies"; + case "3PARdata": return "3PARdata, Inc."; + case "A-Max": return "A-Max Technology Co., Ltd"; + case "ABSOLUTE": return "Absolute Analysis"; + case "ACARD": return "ACARD Technology Corp."; + case "Accusys": return "Accusys INC."; + case "Acer": return "Acer, Inc."; + case "ACL": return "Automated Cartridge Librarys, Inc."; + case "Actifio": return "Actifio"; + case "Acuid": return "Acuid Corporation Ltd."; + case "AcuLab": return "AcuLab, Inc. (Tulsa, OK)"; + case "ADAPTEC": return "Adaptec"; + case "ADIC": return "Advanced Digital Information Corporation"; + case "ADSI": return "Adaptive Data Systems, Inc. (a Western Digital subsidiary)"; + case "ADTX": return "ADTX Co., Ltd."; + case "ADVA": return "ADVA Optical Networking AG"; + case "AEM": return "AEM Performance Electronics"; + case "AERONICS": return "Aeronics, Inc."; + case "AGFA": return "AGFA"; + case "Agilent": return "Agilent Technologies"; + case "AIC": return "Advanced Industrial Computer, Inc."; + case "AIPTEK": return "AIPTEK International Inc."; + case "Alcohol": return "Alcohol Soft"; + case "ALCOR": return "Alcor Micro, Corp."; + case "AMCC": return "Applied Micro Circuits Corporation"; + case "AMCODYNE": return "Amcodyne"; + case "Amgeon": return "Amgeon LLC"; + case "AMI": return "American Megatrends, Inc."; + case "AMPEX": return "Ampex Data Systems"; + case "Amphenol": return "Amphenol"; + case "Amtl": return "Tenlon Technology Co.,Ltd"; + case "ANAMATIC": return "Anamartic Limited (England)"; + case "Ancor": return "Ancor Communications, Inc."; + case "ANCOT": return "ANCOT Corp."; + case "ANDATACO": return "Andataco"; + case "andiamo": return "Andiamo Systems, Inc."; + case "ANOBIT": return "Anobit"; + case "ANRITSU": return "Anritsu Corporation"; + case "ANTONIO": return "Antonio Precise Products Manufactory Ltd."; + case "AoT": return "Art of Technology AG"; + case "APPLE": return "Apple Computer, Inc."; + case "ARCHIVE": return "Archive"; + case "ARDENCE": return "Ardence Inc"; + case "Areca": return "Areca Technology Corporation"; + case "Arena": return "MaxTronic International Co., Ltd."; + case "Argent": return "Argent Data Systems, Inc."; + case "ARIO": return "Ario Data Networks, Inc."; + case "ARISTOS": return "Aristos Logic Corp."; + case "ARK": return "ARK Research Corporation"; + case "ARL:UT@A": return "Applied Research Laboratories : University of Texas at Austin"; + case "ARTECON": return "Artecon Inc."; + case "Artistic": return "Artistic Licence (UK) Ltd"; + case "ARTON": return "Arton Int."; + case "ASACA": return "ASACA Corp."; + case "ASC": return "Advanced Storage Concepts, Inc."; + case "ASPEN": return "Aspen Peripherals"; + case "AST": return "AST Research"; + case "ASTEK": return "Astek Corporation"; + case "ASTK": return "Alcatel STK A/S"; + case "AStor": return "AccelStor, Inc."; + case "ASTUTE": return "Astute Networks, Inc."; + case "AT&T": return "AT&T"; + case "ATA": return "SCSI / ATA Translator Software (Organization Not Specified)"; + case "ATARI": return "Atari Corporation"; + case "ATech": return "ATech electronics"; + case "ATG CYG": return "ATG Cygnet Inc."; + case "ATL": return "Quantum|ATL Products"; + case "ATTO": return "ATTO Technology Inc."; + case "ATTRATEC": return "Attratech Ltd liab. Co"; + case "ATX": return "Alphatronix"; + case "AURASEN": return "Aurasen Limited"; + case "Avago": return "Avago Technologies"; + case "AVC": return "AVC Technology Ltd"; + case "AVIDVIDR": return "AVID Technologies, Inc."; + case "AVR": return "Advanced Vision Research"; + case "AXSTOR": return "AXSTOR"; + case "Axxana": return "Axxana Ltd."; + case "B*BRIDGE": return "Blockbridge Networks LLC"; + case "BALLARD": return "Ballard Synergy Corp."; + case "Barco": return "Barco"; + case "BAROMTEC": return "Barom Technologies Co., Ltd."; + case "Bassett": return "Bassett Electronic Systems Ltd"; + case "BC Hydro": return "BC Hydro"; + case "BDT": return "BDT AG"; + case "BECEEM": return "Beceem Communications, Inc"; + case "BENQ": return "BENQ Corporation."; + case "BERGSWD": return "Berg Software Design"; + case "BEZIER": return "Bezier Systems, Inc."; + case "BHTi": return "Breece Hill Technologies"; + case "biodata": return "Biodata Devices SL"; + case "BIOS": return "BIOS Corporation"; + case "BIR": return "Bio-Imaging Research, Inc."; + case "BiT": return "BiT Microsystems"; + case "BITMICRO": return "BiT Microsystems, Inc."; + case "Blendlgy": return "Blendology Limited"; + case "BLOOMBAS": return "Bloombase Technologies Limited"; + case "BlueArc": return "BlueArc Corporation"; + case "bluecog": return "bluecog"; + case "BME-HVT": return "Broadband Infocommunicatons and Electromagnetic Theory Department"; + case "BNCHMARK": return "Benchmark Tape Systems Corporation"; + case "Bosch": return "Robert Bosch GmbH"; + case "Botman": return "Botmanfamily Electronics"; + case "BoxHill": return "Box Hill Systems Corporation"; + case "BRDGWRKS": return "Bridgeworks Ltd."; + case "BREA": return "BREA Technologies, Inc."; + case "BREECE": return "Breece Hill LLC"; + case "BreqLabs": return "BreqLabs Inc."; + case "Broadcom": return "Broadcom Corporation"; + case "BROCADE": return "Brocade Communications Systems, Incorporated"; + case "BUFFALO": return "BUFFALO INC."; + case "BULL": return "Bull Peripherals Corp."; + case "BUSLOGIC": return "BusLogic Inc."; + case "BVIRTUAL": return "B-Virtual N.V."; + case "CACHEIO": return "CacheIO LLC"; + case "CalComp": return "CalComp, A Lockheed Company"; + case "CALCULEX": return "CALCULEX, Inc."; + case "CALIPER": return "Caliper (California Peripheral Corp.)"; + case "CAMBEX": return "Cambex Corporation"; + case "CAMEOSYS": return "Cameo Systems Inc."; + case "CANDERA": return "Candera Inc."; + case "CAPTION": return "CAPTION BANK"; + case "CAST": return "Advanced Storage Tech"; + case "CATALYST": return "Catalyst Enterprises"; + case "CCDISK": return "iSCSI Cake"; + case "CDC": return "Control Data or MPI"; + case "CDP": return "Columbia Data Products"; + case "Celsia": return "A M Bromley Limited"; + case "CenData": return "Central Data Corporation"; + case "Cereva": return "Cereva Networks Inc."; + case "CERTANCE": return "Certance"; + case "Chantil": return "Chantil Technology"; + case "CHEROKEE": return "Cherokee Data Systems"; + case "CHINON": return "Chinon"; + case "CHRISTMA": return "Christmann Informationstechnik + Medien GmbH & Co KG"; + case "CIE&YED": return "YE Data, C.Itoh Electric Corp."; + case "CIPHER": return "Cipher Data Products"; + case "Ciprico": return "Ciprico, Inc."; + case "CIRRUSL": return "Cirrus Logic Inc."; + case "CISCO": return "Cisco Systems, Inc."; + case "CLEARSKY": return "ClearSky Data, Inc."; + case "CLOVERLF": return "Cloverleaf Communications, Inc"; + case "CLS": return "Celestica"; + case "CMD": return "CMD Technology Inc."; + case "CMTechno": return "CMTech"; + case "CNGR SFW": return "Congruent Software, Inc."; + case "CNSi": return "Chaparral Network Storage, Inc."; + case "CNT": return "Computer Network Technology"; + case "COBY": return "Coby Electronics Corporation, USA"; + case "COGITO": return "Cogito"; + case "COMAY": return "Corerise Electronics"; + case "COMPAQ": return "Compaq Computer Corporation"; + case "COMPELNT": return "Compellent Technologies, Inc."; + case "COMPORT": return "Comport Corp."; + case "COMPSIG": return "Computer Signal Corporation"; + case "COMPTEX": return "Comptex Pty Limited"; + case "CONNER": return "Conner Peripherals"; + case "COPANSYS": return "COPAN SYSTEMS INC"; + case "CORAID": return "Coraid, Inc"; + case "CORE": return "Core International, Inc."; + case "CORERISE": return "Corerise Electronics"; + case "COVOTE": return "Covote GmbH & Co KG"; + case "COWON": return "COWON SYSTEMS, Inc."; + case "CPL": return "Cross Products Ltd"; + case "CPU TECH": return "CPU Technology, Inc."; + case "CREO": return "Creo Products Inc."; + case "CROSFLD": return "Crosfield Electronics"; + case "CROSSRDS": return "Crossroads Systems, Inc."; + case "crosswlk": return "Crosswalk, Inc."; + case "CSCOVRTS": return "Cisco - Veritas"; + case "CSM, INC": return "Computer SM, Inc."; + case "Cunuqui": return "CUNUQUI SLU"; + case "CYBERNET": return "Cybernetics"; + case "Cygnal": return "Dekimo"; + case "CYPRESS": return "Cypress Semiconductor Corp."; + case "D Bit": return "Digby's Bitpile, Inc. DBA D Bit"; + case "DALSEMI": return "Dallas Semiconductor"; + case "DANEELEC": return "Dane-Elec"; + case "DANGER": return "Danger Inc."; + case "DAT-MG": return "DAT Manufacturers Group"; + case "Data Com": return "Data Com Information Systems Pty. Ltd."; + case "DATABOOK": return "Databook, Inc."; + case "DATACOPY": return "Datacopy Corp."; + case "DataCore": return "DataCore Software Corporation"; + case "DataG": return "DataGravity"; + case "DATAPT": return "Datapoint Corp."; + case "DATARAM": return "Dataram Corporation"; + case "DATC": return "Datum Champion Technology Co., Ltd"; + case "DAVIS": return "Daviscomms (S) Pte Ltd"; + case "DCS": return "ShenZhen DCS Group Co.,Ltd"; + case "DDN": return "DataDirect Networks, Inc."; + case "DDRDRIVE": return "DDRdrive LLC"; + case "DE": return "Dimension Engineering LLC"; + case "DEC": return "Digital Equipment Corporation"; + case "DEI": return "Digital Engineering, Inc."; + case "DELL": return "Dell, Inc."; + case "Dell(tm)": return "Dell, Inc"; + case "DELPHI": return "Delphi Data Div. of Sparks Industries, Inc."; + case "DENON": return "Denon/Nippon Columbia"; + case "DenOptix": return "DenOptix, Inc."; + case "DEST": return "DEST Corp."; + case "DFC": return "DavioFranke.com"; + case "DFT": return "Data Fault Tolerance System CO.,LTD."; + case "DGC": return "Data General Corp."; + case "DIGIDATA": return "Digi-Data Corporation"; + case "DigiIntl": return "Digi International"; + case "Digital": return "Digital Equipment Corporation"; + case "DILOG": return "Distributed Logic Corp."; + case "DISC": return "Document Imaging Systems Corp."; + case "DiscSoft": return "Disc Soft Ltd"; + case "DLNET": return "Driveline"; + case "DNS": return "Data and Network Security"; + case "DNUK": return "Digital Networks Uk Ltd"; + case "DotHill": return "Dot Hill Systems Corp."; + case "DP": return "Dell, Inc."; + case "DPT": return "Distributed Processing Technology"; + case "Drewtech": return "Drew Technologies, Inc."; + case "DROBO": return "Data Robotics, Inc."; + case "DSC": return "DigitalStream Corporation"; + case "DSI": return "Data Spectrum, Inc."; + case "DSM": return "Deterner Steuerungs- und Maschinenbau GmbH & Co."; + case "DSNET": return "Cleversafe, Inc."; + case "DT": return "Double-Take Software, INC."; + case "DTC QUME": return "Data Technology Qume"; + case "DXIMAGIN": return "DX Imaging"; + case "E-Motion": return "E-Motion LLC"; + case "EARTHLAB": return "EarthLabs"; + case "EarthLCD": return "Earth Computer Technologies, Inc."; + case "ECCS": return "ECCS, Inc."; + case "ECMA": return "European Computer Manufacturers Association"; + case "EDS": return "Embedded Data Systems"; + case "EIM": return "InfoCore"; + case "ELE Intl": return "ELE International"; + case "ELEGANT": return "Elegant Invention, LLC"; + case "Elektron": return "Elektron Music Machines MAV AB"; + case "elipsan": return "Elipsan UK Ltd."; + case "Elms": return "Elms Systems Corporation"; + case "ELSE": return "ELSE Ltd."; + case "ELSEC": return "Littlemore Scientific"; + case "EMASS": return "EMASS, Inc."; + case "EMC": return "EMC Corp."; + case "EMiT": return "EMiT Conception Eletronique"; + case "EMTEC": return "EMTEC Magnetics"; + case "EMULEX": return "Emulex"; + case "ENERGY-B": return "Energybeam Corporation"; + case "ENGENIO": return "Engenio Information Technologies, Inc."; + case "ENMOTUS": return "Enmotus Inc"; + case "Entacore": return "Entacore"; + case "EPOS": return "EPOS Technologies Ltd."; + case "EPSON": return "Epson"; + case "EQLOGIC": return "EqualLogic"; + case "Eris/RSI": return "RSI Systems, Inc."; + case "ETERNE": return "EterneData Technology Co.,Ltd.(China PRC.)"; + case "EuroLogc": return "Eurologic Systems Limited"; + case "evolve": return "Evolution Technologies, Inc"; + case "EXABYTE": return "Exabyte Corp."; + case "EXATEL": return "Exatelecom Co., Ltd."; + case "EXAVIO": return "Exavio, Inc."; + case "Exsequi": return "Exsequi Ltd"; + case "Exxotest": return "Annecy Electronique"; + case "FAIRHAVN": return "Fairhaven Health, LLC"; + case "FALCON": return "FalconStor, Inc."; + case "FDS": return "Formation Data Systems"; + case "FFEILTD": return "FujiFilm Electonic Imaging Ltd"; + case "Fibxn": return "Fiberxon, Inc."; + case "FID": return "First International Digital, Inc."; + case "FILENET": return "FileNet Corp."; + case "FirmFact": return "Firmware Factory Ltd"; + case "FLYFISH": return "Flyfish Technologies"; + case "FOXCONN": return "Foxconn Technology Group"; + case "FRAMDRV": return "FRAMEDRIVE Corp."; + case "FREECION": return "Nable Communications, Inc."; + case "FRESHDTK": return "FreshDetect GmbH"; + case "FSC": return "Fujitsu Siemens Computers"; + case "FTPL": return "Frontline Technologies Pte Ltd"; + case "FUJI": return "Fuji Electric Co., Ltd. (Japan)"; + case "FUJIFILM": return "Fuji Photo Film, Co., Ltd."; + case "FUJITSU": return "Fujitsu"; + case "FUNAI": return "Funai Electric Co., Ltd."; + case "FUSIONIO": return "Fusion-io Inc."; + case "FUTURED": return "Future Domain Corp."; + case "G&D": return "Giesecke & Devrient GmbH"; + case "G.TRONIC": return "Globaltronic - Electronica e Telecomunicacoes, S.A."; + case "Gadzoox": return "Gadzoox Networks, Inc."; + case "Gammaflx": return "Gammaflux L.P."; + case "GDI": return "Generic Distribution International"; + case "GEMALTO": return "gemalto"; + case "Gen_Dyn": return "General Dynamics"; + case "Generic": return "Generic Technology Co., Ltd."; + case "GENSIG": return "General Signal Networks"; + case "GEO": return "Green Energy Options Ltd"; + case "GIGATAPE": return "GIGATAPE GmbH"; + case "GIGATRND": return "GigaTrend Incorporated"; + case "Global": return "Global Memory Test Consortium"; + case "Gnutek": return "Gnutek Ltd."; + case "Goidelic": return "Goidelic Precision, Inc."; + case "GoldKey": return "GoldKey Security Corporation"; + case "GoldStar": return "LG Electronics Inc."; + case "GOOGLE": return "Google, Inc."; + case "GORDIUS": return "Gordius"; + case "GOULD": return "Gould"; + case "HAGIWARA": return "Hagiwara Sys-Com Co., Ltd."; + case "HAPP3": return "Inventec Multimedia and Telecom co., ltd"; + case "HDS": return "Horizon Data Systems, Inc."; + case "Helldyne": return "Helldyne, Inc"; + case "Heydays": return "Mazo Technology Co., Ltd."; + case "HGST": return "HGST a Western Digital Company"; + case "HI-TECH": return "HI-TECH Software Pty. Ltd."; + case "HITACHI": return "Hitachi America Ltd or Nissei Sangyo America Ltd"; + case "HL-DT-ST": return "Hitachi-LG Data Storage, Inc."; + case "HONEYWEL": return "Honeywell Inc."; + case "Hoptroff": return "HexWax Ltd"; + case "HORIZONT": return "Horizontigo Software"; + case "HP": return "Hewlett Packard"; + case "HPE": return "Hewlett Packard Enterprise"; + case "HPI": return "HP Inc."; + case "HPQ": return "Hewlett Packard"; + case "HUALU": return "CHINA HUALU GROUP CO., LTD"; + case "HUASY": return "Huawei Symantec Technologies Co., Ltd."; + case "HYLINX": return "Hylinx Ltd."; + case "HYUNWON": return "HYUNWON inc"; + case "i-cubed": return "i-cubed ltd."; + case "IBM": return "International Business Machines"; + case "Icefield": return "Icefield Tools Corporation"; + case "Iceweb": return "Iceweb Storage Corp"; + case "ICL": return "ICL"; + case "ICP": return "ICP vortex Computersysteme GmbH"; + case "IDE": return "International Data Engineering, Inc."; + case "IDG": return "Interface Design Group"; + case "IET": return "ISCSI ENTERPRISE TARGET"; + case "IFT": return "Infortrend Technology, Inc."; + case "IGR": return "Intergraph Corp."; + case "IMAGINE": return "Imagine Communications Corp."; + case "IMAGO": return "IMAGO SOFTWARE SL"; + case "IMATION": return "Imation"; + case "IMPLTD": return "Integrated Micro Products Ltd."; + case "IMPRIMIS": return "Imprimis Technology Inc."; + case "INCIPNT": return "Incipient Technologies Inc."; + case "INCITS": return "InterNational Committee for Information Technology"; + case "INDCOMP": return "Industrial Computing Limited"; + case "Indigita": return "Indigita Corporation"; + case "INFOCORE": return "InfoCore"; + case "INITIO": return "Initio Corporation"; + case "INRANGE": return "INRANGE Technologies Corporation"; + case "Insight": return "L-3 Insight Technology Inc"; + case "INSITE": return "Insite Peripherals"; + case "integrix": return "Integrix, Inc."; + case "INTEL": return "Intel Corporation"; + case "Intransa": return "Intransa, Inc."; + case "IOC": return "I/O Concepts, Inc."; + case "iofy": return "iofy Corporation"; + case "IOMEGA": return "Iomega"; + case "IOT": return "IO Turbine, Inc."; + case "iPaper": return "intelliPaper, LLC"; + case "iqstor": return "iQstor Networks, Inc."; + case "iQue": return "iQue"; + case "ISi": return "Information Storage inc."; + case "Isilon": return "Isilon Systems, Inc."; + case "ISO": return "International Standards Organization"; + case "iStor": return "iStor Networks, Inc."; + case "ITC": return "International Tapetronics Corporation"; + case "iTwin": return "iTwin Pte Ltd"; + case "IVIVITY": return "iVivity, Inc."; + case "IVMMLTD": return "InnoVISION Multimedia Ltd."; + case "JABIL001": return "Jabil Circuit"; + case "JETWAY": return "Jetway Information Co., Ltd"; + case "JMR": return "JMR Electronics Inc."; + case "JOFEMAR": return "Jofemar"; + case "JOLLYLOG": return "Jolly Logic"; + case "JPC Inc.": return "JPC Inc."; + case "JSCSI": return "jSCSI Project"; + case "Juniper": return "Juniper Networks"; + case "JVC": return "JVC Information Products Co."; + case "KASHYA": return "Kashya, Inc."; + case "KENNEDY": return "Kennedy Company"; + case "KENWOOD": return "KENWOOD Corporation"; + case "KEWL": return "Shanghai KEWL Imp&Exp Co., Ltd."; + case "Key Tech": return "Key Technologies, Inc"; + case "KMNRIO": return "Kaminario Technologies Ltd."; + case "KODAK": return "Eastman Kodak"; + case "KONAN": return "Konan"; + case "koncepts": return "koncepts International Ltd."; + case "KONICA": return "Konica Japan"; + case "KOVE": return "KOVE"; + case "KSCOM": return "KSCOM Co. Ltd.,"; + case "KUDELSKI": return "Nagravision SA - Kudelski Group"; + case "Kyocera": return "Kyocera Corporation"; + case "Lapida": return "Gonmalo Electronics"; + case "LAPINE": return "Lapine Technology"; + case "LASERDRV": return "LaserDrive Limited"; + case "LASERGR": return "Lasergraphics, Inc."; + case "LeapFrog": return "LeapFrog Enterprises, Inc."; + case "LEFTHAND": return "LeftHand Networks"; + case "Leica": return "Leica Camera AG"; + case "Lexar": return "Lexar Media, Inc."; + case "LEYIO": return "LEYIO"; + case "LG": return "LG Electronics Inc."; + case "LGE": return "LG Electronics Inc."; + case "LIBNOVA": return "LIBNOVA, SL Digital Preservation Systems"; + case "LION": return "Lion Optics Corporation"; + case "LMS": return "Laser Magnetic Storage International Company"; + case "LoupTech": return "Loup Technologies, Inc."; + case "LSI": return "LSI Corp. (was LSI Logic Corp.)"; + case "LSILOGIC": return "LSI Logic Storage Systems, Inc."; + case "LTO-CVE": return "Linear Tape - Open, Compliance Verification Entity"; + case "LUXPRO": return "Luxpro Corporation"; + case "MacroSAN": return "MacroSAN Technologies Co., Ltd."; + case "Malakite": return "Malachite Technologies (New VID is: Sandial)"; + case "MarcBoon": return "marcboon.com"; + case "Marner": return "Marner Storage Technologies, Inc."; + case "MARVELL": return "Marvell Semiconductor, Inc."; + case "Matrix": return "Matrix Orbital Corp."; + case "MATSHITA": return "Matsushita"; + case "MAXELL": return "Hitachi Maxell, Ltd."; + case "MAXIM-IC": return "Maxim Integrated Products"; + case "MaxOptix": return "Maxoptix Corp."; + case "MAXSTRAT": return "Maximum Strategy, Inc."; + case "MAXTOR": return "Maxtor Corp."; + case "MaXXan": return "MaXXan Systems, Inc."; + case "MAYCOM": return "maycom Co., Ltd."; + case "MBEAT": return "K-WON C&C Co.,Ltd"; + case "MCC": return "Measurement Computing Corporation"; + case "McDATA": return "McDATA Corporation"; + case "MCUBE": return "Mcube Technology Co., Ltd."; + case "MDI": return "Micro Design International, Inc."; + case "MEADE": return "Meade Instruments Corporation"; + case "mediamat": return "mediamatic"; + case "MegaElec": return "Mega Electronics Ltd"; + case "MEII": return "Mountain Engineering II, Inc."; + case "MELA": return "Mitsubishi Electronics America"; + case "MELCO": return "Mitsubishi Electric (Japan)"; + case "mellanox": return "Mellanox Technologies Ltd."; + case "MEMOREX": return "Memorex Telex Japan Ltd."; + case "MEMREL": return "Memrel Corporation"; + case "MEMTECH": return "MemTech Technology"; + case "Mendocin": return "Mendocino Software"; + case "MendoCno": return "Mendocino Software"; + case "MERIDATA": return "Oy Meridata Finland Ltd"; + case "METHODEI": return "Methode Electronics India pvt ltd"; + case "METRUM": return "Metrum, Inc."; + case "MHTL": return "Matsunichi Hi-Tech Limited"; + case "MICROBTX": return "Microbotics Inc."; + case "Microchp": return "Microchip Technology, Inc."; + case "MICROLIT": return "Microlite Corporation"; + case "MICRON": return "Micron Technology, Inc."; + case "MICROP": return "Micropolis"; + case "MICROTEK": return "Microtek Storage Corp"; + case "Minitech": return "Minitech (UK) Limited"; + case "Minolta": return "Minolta Corporation"; + case "MINSCRIB": return "Miniscribe"; + case "MiraLink": return "MiraLink Corporation"; + case "Mirifica": return "Mirifica s.r.l."; + case "MITSUMI": return "Mitsumi Electric Co., Ltd."; + case "MKM": return "Mitsubishi Kagaku Media Co., LTD."; + case "Mobii": return "Mobii Systems (Pty.) Ltd."; + case "MOL": return "Petrosoft Sdn. Bhd."; + case "MOSAID": return "Mosaid Technologies Inc."; + case "MOTOROLA": return "Motorola"; + case "MP-400": return "Daiwa Manufacturing Limited"; + case "MPC": return "MPC Corporation"; + case "MPCCORP": return "MPC Computers"; + case "MPEYE": return "Touchstone Technology Co., Ltd"; + case "MPIO": return "DKT Co.,Ltd"; + case "MPM": return "Mitsubishi Paper Mills, Ltd."; + case "MPMan": return "MPMan.com, Inc."; + case "MSFT": return "Microsoft Corporation"; + case "MSI": return "Micro-Star International Corp."; + case "MST": return "Morning Star Technologies, Inc."; + case "MSystems": return "M-Systems Flash Disk Pioneers"; + case "MTI": return "MTI Technology Corporation"; + case "MTNGATE": return "MountainGate Data Systems"; + case "MXI": return "Memory Experts International"; + case "nac": return "nac Image Technology Inc."; + case "NAGRA": return "Nagravision SA - Kudelski Group"; + case "NAI": return "North Atlantic Industries"; + case "NAKAMICH": return "Nakamichi Corporation"; + case "NatInst": return "National Instruments"; + case "NatSemi": return "National Semiconductor Corp."; + case "NCITS": return "InterNational Committee for Information Technology Standards (INCITS)"; + case "NCL": return "NCL America"; + case "NCR": return "NCR Corporation"; + case "NDBTECH": return "NDB Technologie Inc."; + case "Neartek": return "Neartek, Inc."; + case "NEC": return "NEC"; + case "NETAPP": return "NetApp, Inc. (was Network Appliance)"; + case "NetBSD": return "The NetBSD Foundation"; + case "Netcom": return "Netcom Storage"; + case "NETENGIN": return "NetEngine, Inc."; + case "NEWISYS": return "Newisys Data Storage"; + case "Newtech": return "Newtech Co., Ltd."; + case "NEXSAN": return "Nexsan Technologies, Ltd."; + case "NFINIDAT": return "Infinidat Ltd."; + case "NHR": return "NH Research, Inc."; + case "Nike": return "Nike, Inc."; + case "Nimble": return "Nimble Storage"; + case "NISCA": return "NISCA Inc."; + case "NISHAN": return "Nishan Systems Inc."; + case "Nitz": return "Nitz Associates, Inc."; + case "NKK": return "NKK Corp."; + case "NRC": return "Nakamichi Research Corporation"; + case "NSD": return "Nippon Systems Development Co.,Ltd."; + case "NSM": return "NSM Jukebox GmbH"; + case "nStor": return "nStor Technologies, Inc."; + case "NT": return "Northern Telecom"; + case "NUCONNEX": return "NuConnex"; + case "NUSPEED": return "NuSpeed, Inc."; + case "NVIDIA": return "NVIDIA Corporation"; + case "NVMe": return "NVM Express Working Group"; + case "OAI": return "Optical Access International"; + case "OCE": return "Oce Graphics"; + case "ODS": return "ShenZhen DCS Group Co.,Ltd"; + case "OHDEN": return "Ohden Co., Ltd."; + case "OKI": return "OKI Electric Industry Co.,Ltd (Japan)"; + case "Olidata": return "Olidata S.p.A."; + case "OMI": return "Optical Media International"; + case "OMNIFI": return "Rockford Corporation - Omnifi Media"; + case "OMNIS": return "OMNIS Company (FRANCE)"; + case "Ophidian": return "Ophidian Designs"; + case "opslag": return "Tyrone Systems"; + case "Optelec": return "Optelec BV"; + case "Optiarc": return "Sony Optiarc Inc."; + case "OPTIMEM": return "Cipher/Optimem"; + case "OPTOTECH": return "Optotech"; + case "ORACLE": return "Oracle Corporation"; + case "ORANGE": return "Orange Micro, Inc."; + case "ORCA": return "Orca Technology"; + case "Origin": return "Origin Energy"; + case "OSI": return "Optical Storage International"; + case "OSNEXUS": return "OS NEXUS, Inc."; + case "OTL": return "OTL Engineering"; + case "OVERLAND": return "Overland Storage Inc."; + case "pacdigit": return "Pacific Digital Corp"; + case "Packard": return "Parkard Bell"; + case "Panasas": return "Panasas, Inc."; + case "PARALAN": return "Paralan Corporation"; + case "PASCOsci": return "Pasco Scientific"; + case "PATHLGHT": return "Pathlight Technology, Inc."; + case "PCS": return "Pro Charging Systems, LLC"; + case "PerStor": return "Perstor"; + case "PERTEC": return "Pertec Peripherals Corporation"; + case "PFTI": return "Performance Technology Inc."; + case "PFU": return "PFU Limited"; + case "Phigment": return "Phigment Technologies"; + case "PHILIPS": return "Philips Electronics"; + case "PICO": return "Packard Instrument Company"; + case "PIK": return "TECHNILIENT & MCS"; + case "Pillar": return "Pillar Data Systems"; + case "PIONEER": return "Pioneer Electronic Corp."; + case "Pirus": return "Pirus Networks"; + case "PIVOT3": return "Pivot3, Inc."; + case "PLASMON": return "Plasmon Data"; + case "Pliant": return "Pliant Technology, Inc."; + case "PMCSIERA": return "PMC-Sierra"; + case "PME": return "Precision Measurement Engineering"; + case "PNNMed": return "PNN Medical SA"; + case "POKEN": return "Poken SA"; + case "POLYTRON": return "PT. HARTONO ISTANA TEKNOLOGI"; + case "PRAIRIE": return "PrairieTek"; + case "PREPRESS": return "PrePRESS Solutions"; + case "PRESOFT": return "PreSoft Architects"; + case "PRESTON": return "Preston Scientific"; + case "PRIAM": return "Priam"; + case "PRIMAGFX": return "Primagraphics Ltd"; + case "PRIMOS": return "Primos"; + case "PROCOM": return "Procom Technology"; + case "PROLIFIC": return "Prolific Technology Inc."; + case "PROMISE": return "PROMISE TECHNOLOGY, Inc"; + case "PROSTOR": return "ProStor Systems, Inc."; + case "PROSUM": return "PROSUM"; + case "PROWARE": return "Proware Technology Corp."; + case "PTI": return "Peripheral Technology Inc."; + case "PTICO": return "Pacific Technology International"; + case "PURE": return "PURE Storage"; + case "Qi-Hardw": return "Qi Hardware"; + case "QIC": return "Quarter-Inch Cartridge Drive Standards, Inc."; + case "QLogic": return "QLogic Corporation"; + case "QNAP": return "QNAP Systems"; + case "Qsan": return "QSAN Technology, Inc."; + case "QUALSTAR": return "Qualstar"; + case "QUANTEL": return "Quantel Ltd."; + case "QUANTUM": return "Quantum Corp."; + case "QUIX": return "Quix Computerware AG"; + case "R-BYTE": return "R-Byte, Inc."; + case "RACALREC": return "Racal Recorders"; + case "RADITEC": return "Radikal Technologies Deutschland GmbH"; + case "RADSTONE": return "Radstone Technology"; + case "RAIDINC": return "RAID Inc."; + case "RASSYS": return "Rasilient Systems Inc."; + case "RASVIA": return "Rasvia Systems, Inc."; + case "rave-mp": return "Go Video"; + case "RDKMSTG": return "MMS Dipl. Ing. Rolf-Dieter Klein"; + case "RDStor": return "Rorke China"; + case "Readboy": return "Readboy Ltd Co."; + case "Realm": return "Realm Systems"; + case "realtek": return "Realtek Semiconductor Corp."; + case "REDUXIO": return "Reduxio Systems Ltd."; + case "rehanltd": return "Rehan Electronics Ltd"; + case "REKA": return "REKA HEALTH PTE LTD"; + case "RELDATA": return "RELDATA Inc"; + case "RENAGmbH": return "RENA GmbH"; + case "ReThinkM": return "RETHINK MEDICAL, INC"; + case "Revivio": return "Revivio, Inc."; + case "RGBLaser": return "RGB Lasersysteme GmbH"; + case "RGI": return "Raster Graphics, Inc."; + case "RHAPSODY": return "Rhapsody Networks, Inc."; + case "RHS": return "Racal-Heim Systems GmbH"; + case "RICOH": return "Ricoh"; + case "RODIME": return "Rodime"; + case "Rorke": return "RD DATA Technology (ShenZhen) Limited"; + case "Royaltek": return "RoyalTek company Ltd."; + case "RPS": return "RPS"; + case "RTI": return "Reference Technology"; + case "S-D": return "Sauer-Danfoss"; + case "S-flex": return "Storageflex Inc"; + case "S-SYSTEM": return "S-SYSTEM"; + case "S1": return "storONE"; + case "SAMSUNG": return "Samsung Electronics Co., Ltd."; + case "SAN": return "Storage Area Networks, Ltd."; + case "Sandial": return "Sandial Systems, Inc."; + case "SanDisk": return "SanDisk Corporation"; + case "SANKYO": return "Sankyo Seiki"; + case "SANRAD": return "SANRAD Inc."; + case "SANYO": return "SANYO Electric Co., Ltd."; + case "SC.Net": return "StorageConnections.Net"; + case "SCALE": return "Scale Computing, Inc."; + case "SCIENTEK": return "SCIENTEK CORP"; + case "SCInc.": return "Storage Concepts, Inc."; + case "SCREEN": return "Dainippon Screen Mfg. Co., Ltd."; + case "SDI": return "Storage Dimensions, Inc."; + case "SDS": return "Solid Data Systems"; + case "SEAC": return "SeaChange International, Inc."; + case "SEAGATE": return "Seagate"; + case "SEAGRAND": return "SEAGRAND In Japan"; + case "Seanodes": return "Seanodes"; + case "Sec. Key": return "SecureKey Technologies Inc."; + case "SEQUOIA": return "Sequoia Advanced Technologies, Inc."; + case "SGI": return "Silicon Graphics International"; + case "Shannon": return "Shannon Systems Co., Ltd."; + case "Shinko": return "Shinko Electric Co., Ltd."; + case "SIEMENS": return "Siemens"; + case "SigmaTel": return "SigmaTel, Inc."; + case "SII": return "Seiko Instruments Inc."; + case "SIMPLE": return "SimpleTech, Inc."; + case "SIVMSD": return "IMAGO SOFTWARE SL"; + case "SKhynix": return "SK hynix Inc."; + case "SLCNSTOR": return "SiliconStor, Inc."; + case "SLI": return "Sierra Logic, Inc."; + case "SMCI": return "Super Micro Computer, Inc."; + case "SmrtStor": return "Smart Storage Systems"; + case "SMS": return "Scientific Micro Systems/OMTI"; + case "SMSC": return "SMSC Storage, Inc."; + case "SMX": return "Smartronix, Inc."; + case "SNYSIDE": return "Sunnyside Computing Inc."; + case "SoftLock": return "Softlock Digital Security Provider"; + case "SolidFir": return "SolidFire, Inc."; + case "SONIC": return "Sonic Solutions"; + case "SoniqCas": return "SoniqCast"; + case "SONY": return "Sony Corporation Japan"; + case "SOUL": return "Soul Storage Technology (Wuxi) Co., Ltd"; + case "SPD": return "Storage Products Distribution, Inc."; + case "SPECIAL": return "Special Computing Co."; + case "SPECTRA": return "Spectra Logic, a Division of Western Automation Labs, Inc."; + case "SPERRY": return "Sperry"; + case "Spintso": return "Spintso International AB"; + case "STARBORD": return "Starboard Storage Systems, Inc."; + case "STARWIND": return "StarWind Software, Inc."; + case "STEC": return "STEC, Inc."; + case "Sterling": return "Sterling Diagnostic Imaging, Inc."; + case "STK": return "Storage Technology Corporation"; + case "STNWOOD": return "Stonewood Group"; + case "STONEFLY": return "StoneFly Networks, Inc."; + case "STOR": return "StorageNetworks, Inc."; + case "STORAPP": return "StorageApps, Inc."; + case "STORCIUM": return "Intelligent Systems Services Inc."; + case "STORCOMP": return "Storage Computer Corporation"; + case "STORM": return "Storm Technology, Inc."; + case "StorMagc": return "StorMagic"; + case "Stratus": return "Stratus Technologies"; + case "StrmLgc": return "StreamLogic Corp."; + case "SUMITOMO": return "Sumitomo Electric Industries, Ltd."; + case "SUN": return "Sun Microsystems, Inc."; + case "SUNCORP": return "SunCorporation"; + case "suntx": return "Suntx System Co., Ltd"; + case "SUSE": return "SUSE Linux"; + case "Swinxs": return "Swinxs BV"; + case "SYMANTEC": return "Symantec Corporation"; + case "SYMBIOS": return "Symbios Logic Inc."; + case "SYMWAVE": return "Symwave, Inc."; + case "SYNCSORT": return "Syncsort Incorporated"; + case "SYNERWAY": return "Synerway"; + case "SYNOLOGY": return "Synology, Inc."; + case "SyQuest": return "SyQuest Technology, Inc."; + case "SYSGEN": return "Sysgen"; + case "T-MITTON": return "Transmitton England"; + case "T-MOBILE": return "T-Mobile USA, Inc."; + case "T11": return "INCITS Technical Committee T11"; + case "TALARIS": return "Talaris Systems, Inc."; + case "TALLGRAS": return "Tallgrass Technologies"; + case "TANDBERG": return "Tandberg Data A/S"; + case "TANDEM": return "Tandem"; + case "TANDON": return "Tandon"; + case "TCL": return "TCL Shenzhen ASIC MIcro-electronics Ltd"; + case "TDK": return "TDK Corporation"; + case "TEAC": return "TEAC Japan"; + case "TECOLOTE": return "Tecolote Designs"; + case "TEGRA": return "Tegra Varityper"; + case "Teilch": return "Teilch"; + case "Tek": return "Tektronix"; + case "TELLERT": return "Tellert Elektronik GmbH"; + case "TENTIME": return "Laura Technologies, Inc."; + case "TFDATACO": return "TimeForge"; + case "TGEGROUP": return "TGE Group Co.,LTD."; + case "Thecus": return "Thecus Technology Corp."; + case "TI-DSG": return "Texas Instruments"; + case "TiGi": return "TiGi Corporation"; + case "TILDESGN": return "Tildesign bv"; + case "Tite": return "Tite Technology Limited"; + case "TKS Inc.": return "TimeKeeping Systems, Inc."; + case "TLMKS": return "Telemakus LLC"; + case "TMS": return "Texas Memory Systems, Inc."; + case "TMS100": return "TechnoVas"; + case "TOLISGRP": return "The TOLIS Group"; + case "TOSHIBA": return "Toshiba Japan"; + case "TOYOU": return "TOYOU FEIJI ELECTRONICS CO.,LTD."; + case "Tracker": return "Tracker, LLC"; + case "TRIOFLEX": return "Trioflex Oy"; + case "TRIPACE": return "Tripace"; + case "TRLogger": return "TrueLogger Ltd."; + case "TROIKA": return "Troika Networks, Inc."; + case "TRULY": return "TRULY Electronics MFG. LTD."; + case "TRUSTED": return "Trusted Data Corporation"; + case "TSSTcorp": return "Toshiba Samsung Storage Technology Corporation"; + case "TZM": return "TZ Medical"; + case "UD-DVR": return "Bigstone Project."; + case "UDIGITAL": return "United Digital Limited"; + case "UIT": return "United Infomation Technology"; + case "ULTRA": return "UltraStor Corporation"; + case "UNISTOR": return "Unistor Networks, Inc."; + case "UNISYS": return "Unisys"; + case "USCORE": return "Underscore, Inc."; + case "USDC": return "US Design Corp."; + case "Top VASCO": return "Vasco Data Security"; + case "VDS": return "Victor Data Systems Co., Ltd."; + case "VELDANA": return "VELDANA MEDICAL SA"; + case "VENTANA": return "Ventana Medical Systems"; + case "Verari": return "Verari Systems, Inc."; + case "VERBATIM": return "Verbatim Corporation"; + case "Vercet": return "Vercet LLC"; + case "VERITAS": return "VERITAS Software Corporation"; + case "Vexata": return "Vexata Inc"; + case "VEXCEL": return "VEXCEL IMAGING GmbH"; + case "VICOMSL1": return "Vicom Systems, Inc."; + case "VicomSys": return "Vicom Systems, Inc."; + case "VIDEXINC": return "Videx, Inc."; + case "VIOLIN": return "Violin Memory, Inc."; + case "VIRIDENT": return "Virident Systems, Inc."; + case "VITESSE": return "Vitesse Semiconductor Corporation"; + case "VIXEL": return "Vixel Corporation"; + case "VLS": return "Van Lent Systems BV"; + case "VMAX": return "VMAX Technologies Corp."; + case "VMware": return "VMware Inc."; + case "Vobis": return "Vobis Microcomputer AG"; + case "VOLTAIRE": return "Voltaire Ltd."; + case "VRC": return "Vermont Research Corp."; + case "VRugged": return "Vanguard Rugged Storage"; + case "VTGadget": return "Vermont Gadget Company"; + case "Waitec": return "Waitec NV"; + case "WangDAT": return "WangDAT"; + case "WANGTEK": return "Wangtek"; + case "Wasabi": return "Wasabi Systems"; + case "WAVECOM": return "Wavecom"; + case "WD": return "Western Digital Corporation"; + case "WDC": return "Western Digital Corporation"; + case "WDIGTL": return "Western Digital"; + case "WDTI": return "Western Digital Technologies, Inc."; + case "WEARNES": return "Wearnes Technology Corporation"; + case "WeeraRes": return "Weera Research Pte Ltd"; + case "Wildflwr": return "Wildflower Technologies, Inc."; + case "WSC0001": return "Wisecom, Inc."; + case "X3": return "InterNational Committee for Information Technology Standards (INCITS)"; + case "XEBEC": return "Xebec Corporation"; + case "XENSRC": return "XenSource, Inc."; + case "Xerox": return "Xerox Corporation"; + case "XIOtech": return "XIOtech Corporation"; + case "XIRANET": return "Xiranet Communications GmbH"; + case "XIV": return "XIV"; + case "XtremIO": return "XtremIO"; + case "XYRATEX": return "Xyratex"; + case "YINHE": return "NUDT Computer Co."; + case "YIXUN": return "Yixun Electronic Co.,Ltd."; + case "YOTTA": return "YottaYotta, Inc."; + case "Zarva": return "Zarva Digital Technology Co., Ltd."; + case "ZETTA": return "Zetta Systems, Inc."; + case "ZTE": return "ZTE Corporation"; + case "ZVAULT": return "Zetavault"; + default: return scsiVendorString; } } } \ No newline at end of file diff --git a/SecureDigital/CID.cs b/SecureDigital/CID.cs index 0316b85..10a899c 100644 --- a/SecureDigital/CID.cs +++ b/SecureDigital/CID.cs @@ -35,95 +35,94 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SecureDigital +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class CID { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class CID + public string ApplicationID; + public byte CRC; + public byte Manufacturer; + public ushort ManufacturingDate; + public string ProductName; + public byte ProductRevision; + public uint ProductSerialNumber; +} + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Decoders +{ + public static CID DecodeCID(uint[] response) { - public string ApplicationID; - public byte CRC; - public byte Manufacturer; - public ushort ManufacturingDate; - public string ProductName; - public byte ProductRevision; - public uint ProductSerialNumber; + if(response?.Length != 4) + return null; + + byte[] data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCID(data); } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Decoders + public static CID DecodeCID(byte[] response) { - public static CID DecodeCID(uint[] response) + if(response?.Length != 16) + return null; + + var cid = new CID { - if(response?.Length != 4) - return null; + Manufacturer = response[0], + ProductRevision = response[8], + ProductSerialNumber = Swapping.Swap(BitConverter.ToUInt32(response, 9)), + ManufacturingDate = (ushort)(((response[13] & 0x0F) << 8) + response[14]), + CRC = (byte)((response[15] & 0xFE) >> 1) + }; - byte[] data = new byte[16]; + byte[] tmp = new byte[2]; + Array.Copy(response, 1, tmp, 0, 2); + cid.ApplicationID = StringHandlers.CToString(tmp); + tmp = new byte[5]; + Array.Copy(response, 3, tmp, 0, 5); + cid.ProductName = StringHandlers.CToString(tmp); - byte[] tmp = BitConverter.GetBytes(response[0]); - Array.Copy(tmp, 0, data, 0, 4); - tmp = BitConverter.GetBytes(response[1]); - Array.Copy(tmp, 0, data, 4, 4); - tmp = BitConverter.GetBytes(response[2]); - Array.Copy(tmp, 0, data, 8, 4); - tmp = BitConverter.GetBytes(response[3]); - Array.Copy(tmp, 0, data, 12, 4); - - return DecodeCID(data); - } - - public static CID DecodeCID(byte[] response) - { - if(response?.Length != 16) - return null; - - var cid = new CID - { - Manufacturer = response[0], - ProductRevision = response[8], - ProductSerialNumber = Swapping.Swap(BitConverter.ToUInt32(response, 9)), - ManufacturingDate = (ushort)(((response[13] & 0x0F) << 8) + response[14]), - CRC = (byte)((response[15] & 0xFE) >> 1) - }; - - byte[] tmp = new byte[2]; - Array.Copy(response, 1, tmp, 0, 2); - cid.ApplicationID = StringHandlers.CToString(tmp); - tmp = new byte[5]; - Array.Copy(response, 3, tmp, 0, 5); - cid.ProductName = StringHandlers.CToString(tmp); - - return cid; - } - - public static string PrettifyCID(CID cid) - { - if(cid == null) - return null; - - var sb = new StringBuilder(); - - sb.AppendLine("SecureDigital Device Identification Register:"); - sb.AppendFormat("\tManufacturer: {0}", VendorString.Prettify(cid.Manufacturer)).AppendLine(); - 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(); - - sb.AppendFormat("\tDevice manufactured month {0} of {1}", (cid.ManufacturingDate & 0xF00) >> 8, - (cid.ManufacturingDate & 0xFF) + 2000).AppendLine(); - - sb.AppendFormat("\tCID CRC: 0x{0:X2}", cid.CRC).AppendLine(); - - return sb.ToString(); - } - - public static string PrettifyCID(uint[] response) => PrettifyCID(DecodeCID(response)); - - public static string PrettifyCID(byte[] response) => PrettifyCID(DecodeCID(response)); + return cid; } + + public static string PrettifyCID(CID cid) + { + if(cid == null) + return null; + + var sb = new StringBuilder(); + + sb.AppendLine("SecureDigital Device Identification Register:"); + sb.AppendFormat("\tManufacturer: {0}", VendorString.Prettify(cid.Manufacturer)).AppendLine(); + 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(); + + sb.AppendFormat("\tDevice manufactured month {0} of {1}", (cid.ManufacturingDate & 0xF00) >> 8, + (cid.ManufacturingDate & 0xFF) + 2000).AppendLine(); + + sb.AppendFormat("\tCID CRC: 0x{0:X2}", cid.CRC).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyCID(uint[] response) => PrettifyCID(DecodeCID(response)); + + public static string PrettifyCID(byte[] response) => PrettifyCID(DecodeCID(response)); } \ No newline at end of file diff --git a/SecureDigital/CSD.cs b/SecureDigital/CSD.cs index 76e9841..e43e26e 100644 --- a/SecureDigital/CSD.cs +++ b/SecureDigital/CSD.cs @@ -34,621 +34,620 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SecureDigital +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public class CSD { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public class CSD + public ushort Classes; + public bool Copy; + public byte CRC; + public bool DSRImplemented; + public bool EraseBlockEnable; + public byte EraseSectorSize; + public byte FileFormat; + 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 uint Size; + public byte SizeMultiplier; + public byte Speed; + public byte Structure; + public byte TAAC; + public bool TemporaryWriteProtect; + 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", "MemberCanBePrivate.Global")] +public static partial class Decoders +{ + public static CSD DecodeCSD(uint[] response) { - public ushort Classes; - public bool Copy; - public byte CRC; - public bool DSRImplemented; - public bool EraseBlockEnable; - public byte EraseSectorSize; - public byte FileFormat; - 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 uint Size; - public byte SizeMultiplier; - public byte Speed; - public byte Structure; - public byte TAAC; - public bool TemporaryWriteProtect; - public byte WriteBlockLength; - public byte WriteCurrentAtVddMax; - public byte WriteCurrentAtVddMin; - public bool WriteMisalignment; - public bool WriteProtectGroupEnable; - public byte WriteProtectGroupSize; - public bool WritesPartialBlocks; - public byte WriteSpeedFactor; + if(response?.Length != 4) + return null; + + byte[] data = new byte[16]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + tmp = BitConverter.GetBytes(response[2]); + Array.Copy(tmp, 0, data, 8, 4); + tmp = BitConverter.GetBytes(response[3]); + Array.Copy(tmp, 0, data, 12, 4); + + return DecodeCSD(data); } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Decoders + public static CSD DecodeCSD(byte[] response) { - public static CSD DecodeCSD(uint[] response) + if(response?.Length != 16) + return null; + + var csd = new CSD { - if(response?.Length != 4) - return null; + Structure = (byte)((response[0] & 0xC0) >> 6), + 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, + EraseBlockEnable = (response[10] & 0x40) == 0x40, + EraseSectorSize = (byte)(((response[10] & 0x3F) << 1) + ((response[11] & 0x80) >> 7)), + WriteProtectGroupSize = (byte)(response[11] & 0x7F), + WriteProtectGroupEnable = (response[12] & 0x80) == 0x80, + WriteSpeedFactor = (byte)((response[12] & 0x1C) >> 2), + WriteBlockLength = (byte)(((response[12] & 0x03) << 2) + ((response[13] & 0xC0) >> 6)), + WritesPartialBlocks = (response[13] & 0x20) == 0x20, + FileFormatGroup = (response[14] & 0x80) == 0x80, + Copy = (response[14] & 0x40) == 0x40, + PermanentWriteProtect = (response[14] & 0x20) == 0x20, + TemporaryWriteProtect = (response[14] & 0x10) == 0x10, + FileFormat = (byte)((response[14] & 0x0C) >> 2), + CRC = (byte)((response[15] & 0xFE) >> 1) + }; - byte[] data = new byte[16]; + if(csd.Structure == 0) + { + csd.Size = (ushort)(((response[6] & 0x03) << 10) + (response[7] << 2) + ((response[8] & 0xC0) >> 6)); - byte[] tmp = BitConverter.GetBytes(response[0]); - Array.Copy(tmp, 0, data, 0, 4); - tmp = BitConverter.GetBytes(response[1]); - Array.Copy(tmp, 0, data, 4, 4); - tmp = BitConverter.GetBytes(response[2]); - Array.Copy(tmp, 0, data, 8, 4); - tmp = BitConverter.GetBytes(response[3]); - Array.Copy(tmp, 0, data, 12, 4); + csd.ReadCurrentAtVddMin = (byte)((response[8] & 0x38) >> 3); + csd.ReadCurrentAtVddMax = (byte)(response[8] & 0x07); + csd.WriteCurrentAtVddMin = (byte)((response[9] & 0xE0) >> 5); + csd.WriteCurrentAtVddMax = (byte)((response[9] & 0x1C) >> 2); + csd.SizeMultiplier = (byte)(((response[9] & 0x03) << 1) + ((response[10] & 0x80) >> 7)); + } + else + csd.Size = (uint)(((response[7] & 0x3F) << 16) + (response[8] << 8) + response[9]); - return DecodeCSD(data); + return csd; + } + + public static string PrettifyCSD(CSD csd) + { + if(csd == null) + return null; + + double unitFactor = 0; + double multiplier = 0; + string unit = ""; + + var sb = new StringBuilder(); + sb.AppendLine("SecureDigital Device Specific Data Register:"); + + switch(csd.Structure) + { + case 0: + sb.AppendLine("\tRegister version 1.0"); + + break; + case 1: + sb.AppendLine("\tRegister version 2.0"); + + break; } - public static CSD DecodeCSD(byte[] response) + switch(csd.TAAC & 0x07) { - if(response?.Length != 16) - return null; + case 0: + unit = "ns"; + unitFactor = 1; - var csd = new CSD + 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; + } + + switch((csd.TAAC & 0x78) >> 3) + { + 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; + } + + double result = unitFactor * multiplier; + sb.AppendFormat("\tAsynchronous data access time is {0}{1}", result, unit).AppendLine(); + + sb.AppendFormat("\tClock dependent part of data access is {0} clock cycles", csd.NSAC * 100).AppendLine(); + + unit = "MBit/s"; + + 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; + } + + switch((csd.Speed & 0x78) >> 3) + { + 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; + } + + result = unitFactor * multiplier; + sb.AppendFormat("\tDevice's transfer speed: {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(); + 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.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.Structure == 0) + { + result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2); + 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(); + } + else + { + sb.AppendFormat("\tDevice has {0} blocks", (csd.Size + 1) * 1024).AppendLine(); + result = ((ulong)csd.Size + 1) * 1024 * 512; + + if(result > 1099511627776) + sb.AppendFormat("\tDevice has {0} TiB", result / 1099511627776.0).AppendLine(); + else 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(csd.Structure == 0) + { + switch(csd.ReadCurrentAtVddMin & 0x07) { - Structure = (byte)((response[0] & 0xC0) >> 6), - 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, - EraseBlockEnable = (response[10] & 0x40) == 0x40, - EraseSectorSize = (byte)(((response[10] & 0x3F) << 1) + ((response[11] & 0x80) >> 7)), - WriteProtectGroupSize = (byte)(response[11] & 0x7F), - WriteProtectGroupEnable = (response[12] & 0x80) == 0x80, - WriteSpeedFactor = (byte)((response[12] & 0x1C) >> 2), - WriteBlockLength = (byte)(((response[12] & 0x03) << 2) + ((response[13] & 0xC0) >> 6)), - WritesPartialBlocks = (response[13] & 0x20) == 0x20, - FileFormatGroup = (response[14] & 0x80) == 0x80, - Copy = (response[14] & 0x40) == 0x40, - PermanentWriteProtect = (response[14] & 0x20) == 0x20, - TemporaryWriteProtect = (response[14] & 0x10) == 0x10, - FileFormat = (byte)((response[14] & 0x0C) >> 2), - CRC = (byte)((response[15] & 0xFE) >> 1) - }; + case 0: + sb.AppendLine("\tDevice uses a maximum of 0.5mA for reading at minimum voltage"); - if(csd.Structure == 0) + 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; + } + + switch(csd.ReadCurrentAtVddMax & 0x07) { - csd.Size = (ushort)(((response[6] & 0x03) << 10) + (response[7] << 2) + ((response[8] & 0xC0) >> 6)); + case 0: + sb.AppendLine("\tDevice uses a maximum of 1mA for reading at maximum voltage"); - csd.ReadCurrentAtVddMin = (byte)((response[8] & 0x38) >> 3); - csd.ReadCurrentAtVddMax = (byte)(response[8] & 0x07); - csd.WriteCurrentAtVddMin = (byte)((response[9] & 0xE0) >> 5); - csd.WriteCurrentAtVddMax = (byte)((response[9] & 0x1C) >> 2); - csd.SizeMultiplier = (byte)(((response[9] & 0x03) << 1) + ((response[10] & 0x80) >> 7)); + 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; + } + + switch(csd.WriteCurrentAtVddMin & 0x07) + { + 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; + } + + switch(csd.WriteCurrentAtVddMax & 0x07) + { + 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; + } + + if(csd.EraseBlockEnable) + sb.AppendLine("\tDevice can erase multiple blocks"); + + // TODO: Check specification + sb.AppendFormat("\tDevice must erase a minimum of {0} blocks at a time", + Convert.ToUInt32(csd.EraseSectorSize) + 1).AppendLine(); + + 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(); } else - csd.Size = (uint)(((response[7] & 0x3F) << 16) + (response[8] << 8) + response[9]); - - return csd; + sb.AppendLine("\tDevice can't write protect regions"); } - public static string PrettifyCSD(CSD csd) - { - if(csd == null) - return null; + sb.AppendFormat("\tWriting is {0} times slower than reading", Math.Pow(2, csd.WriteSpeedFactor)). + AppendLine(); - double unitFactor = 0; - double multiplier = 0; - string unit = ""; + sb.AppendFormat("\tWrite block length is {0} bytes", Math.Pow(2, csd.WriteBlockLength)).AppendLine(); - var sb = new StringBuilder(); - sb.AppendLine("SecureDigital Device Specific Data Register:"); + if(csd.WritesPartialBlocks) + sb.AppendLine("\tDevice allows writing partial blocks"); - switch(csd.Structure) + if(!csd.Copy) + sb.AppendLine("\tDevice contents are original"); + + if(csd.PermanentWriteProtect) + sb.AppendLine("\tDevice is permanently write protected"); + + if(csd.TemporaryWriteProtect) + sb.AppendLine("\tDevice is temporarily write protected"); + + if(!csd.FileFormatGroup) + switch(csd.FileFormat) { case 0: - sb.AppendLine("\tRegister version 1.0"); + sb.AppendLine("\tDevice is formatted like a hard disk"); break; case 1: - sb.AppendLine("\tRegister version 2.0"); - - break; - } - - switch(csd.TAAC & 0x07) - { - case 0: - unit = "ns"; - unitFactor = 1; - - break; - case 1: - unit = "ns"; - unitFactor = 10; + sb.AppendLine("\tDevice is formatted like a floppy disk using Microsoft FAT"); 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; - } - - switch((csd.TAAC & 0x78) >> 3) - { - 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; - } - - double result = unitFactor * multiplier; - sb.AppendFormat("\tAsynchronous data access time is {0}{1}", result, unit).AppendLine(); - - sb.AppendFormat("\tClock dependent part of data access is {0} clock cycles", csd.NSAC * 100).AppendLine(); - - unit = "MBit/s"; - - switch(csd.Speed & 0x07) - { - case 0: - unitFactor = 0.1; - - break; - case 1: - unitFactor = 1; - - break; - case 2: - unitFactor = 10; - - break; - case 3: - unitFactor = 100; + sb.AppendLine("\tDevice uses Universal File Format"); break; default: - unit = "unknown"; - unitFactor = 0; + sb.AppendFormat("\tDevice uses unknown file format code {0}", csd.FileFormat).AppendLine(); break; } - - switch((csd.Speed & 0x78) >> 3) - { - 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; - } - - result = unitFactor * multiplier; - sb.AppendFormat("\tDevice's transfer speed: {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(); - 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.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.Structure == 0) - { - result = (csd.Size + 1) * Math.Pow(2, csd.SizeMultiplier + 2); - 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(); - } - else - { - sb.AppendFormat("\tDevice has {0} blocks", (csd.Size + 1) * 1024).AppendLine(); - result = ((ulong)csd.Size + 1) * 1024 * 512; - - if(result > 1099511627776) - sb.AppendFormat("\tDevice has {0} TiB", result / 1099511627776.0).AppendLine(); - else 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(csd.Structure == 0) - { - 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; - } - - switch(csd.ReadCurrentAtVddMax & 0x07) - { - 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; - } - - switch(csd.WriteCurrentAtVddMin & 0x07) - { - 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; - } - - switch(csd.WriteCurrentAtVddMax & 0x07) - { - 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; - } - - if(csd.EraseBlockEnable) - sb.AppendLine("\tDevice can erase multiple blocks"); - - // TODO: Check specification - sb.AppendFormat("\tDevice must erase a minimum of {0} blocks at a time", - Convert.ToUInt32(csd.EraseSectorSize) + 1).AppendLine(); - - 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(); - } - else - sb.AppendLine("\tDevice can't write protect regions"); - } - - sb.AppendFormat("\tWriting is {0} times slower than reading", Math.Pow(2, csd.WriteSpeedFactor)). + else + sb.AppendFormat("\tDevice uses unknown file format code {0} and file format group 1", csd.FileFormat). AppendLine(); - sb.AppendFormat("\tWrite block length is {0} bytes", Math.Pow(2, csd.WriteBlockLength)).AppendLine(); + sb.AppendFormat("\tCSD CRC: 0x{0:X2}", csd.CRC).AppendLine(); - if(csd.WritesPartialBlocks) - sb.AppendLine("\tDevice allows writing partial blocks"); - - if(!csd.Copy) - sb.AppendLine("\tDevice contents are original"); - - if(csd.PermanentWriteProtect) - sb.AppendLine("\tDevice is permanently 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("\tCSD CRC: 0x{0:X2}", csd.CRC).AppendLine(); - - return sb.ToString(); - } - - public static string PrettifyCSD(uint[] response) => PrettifyCSD(DecodeCSD(response)); - - public static string PrettifyCSD(byte[] response) => PrettifyCSD(DecodeCSD(response)); + return sb.ToString(); } + + public static string PrettifyCSD(uint[] response) => PrettifyCSD(DecodeCSD(response)); + + public static string PrettifyCSD(byte[] response) => PrettifyCSD(DecodeCSD(response)); } \ No newline at end of file diff --git a/SecureDigital/OCR.cs b/SecureDigital/OCR.cs index 8d44575..8f63cd1 100644 --- a/SecureDigital/OCR.cs +++ b/SecureDigital/OCR.cs @@ -35,110 +35,109 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.SecureDigital +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"), + SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class OCR { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnassignedField.Global"), - SuppressMessage("ReSharper", "NotAccessedField.Global")] - public class OCR + public bool CCS; + public bool LowPower; + public bool OneEight; + public bool PowerUp; + public bool ThreeFive; + public bool ThreeFour; + public bool ThreeOne; + public bool ThreeThree; + public bool ThreeTwo; + public bool ThreeZero; + public bool TwoEight; + public bool TwoNine; + public bool TwoSeven; + public bool UHS; +} + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static partial class Decoders +{ + public static OCR DecodeOCR(uint response) { - public bool CCS; - public bool LowPower; - public bool OneEight; - public bool PowerUp; - public bool ThreeFive; - public bool ThreeFour; - public bool ThreeOne; - public bool ThreeThree; - public bool ThreeTwo; - public bool ThreeZero; - public bool TwoEight; - public bool TwoNine; - public bool TwoSeven; - public bool UHS; + response = Swapping.Swap(response); + + return new OCR + { + PowerUp = (response & 0x80000000) == 0x80000000, + CCS = (response & 0x40000000) == 0x40000000, + UHS = (response & 0x20000000) == 0x20000000, + OneEight = (response & 0x01000000) == 0x01000000, + 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, + LowPower = (response & 0x00000080) == 0x00000080 + }; } - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static partial class Decoders + public static OCR DecodeOCR(byte[] response) => + response?.Length != 4 ? null : DecodeOCR(BitConverter.ToUInt32(response, 0)); + + public static string PrettifyOCR(OCR ocr) { - public static OCR DecodeOCR(uint response) - { - response = Swapping.Swap(response); + if(ocr == null) + return null; - return new OCR - { - PowerUp = (response & 0x80000000) == 0x80000000, - CCS = (response & 0x40000000) == 0x40000000, - UHS = (response & 0x20000000) == 0x20000000, - OneEight = (response & 0x01000000) == 0x01000000, - 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, - LowPower = (response & 0x00000080) == 0x00000080 - }; - } + var sb = new StringBuilder(); + sb.AppendLine("SecureDigital Operation Conditions Register:"); - public static OCR DecodeOCR(byte[] response) => - response?.Length != 4 ? null : DecodeOCR(BitConverter.ToUInt32(response, 0)); + if(!ocr.PowerUp) + sb.AppendLine("\tDevice is powering up"); - public static string PrettifyOCR(OCR ocr) - { - if(ocr == null) - return null; + if(ocr.CCS) + sb.AppendLine("\tDevice is SDHC, SDXC or higher"); - var sb = new StringBuilder(); - sb.AppendLine("SecureDigital Operation Conditions Register:"); + if(ocr.UHS) + sb.AppendLine("\tDevice is UHS-II or higher"); - if(!ocr.PowerUp) - sb.AppendLine("\tDevice is powering up"); + if(ocr.ThreeFive) + sb.AppendLine("\tDevice can work with supply 3.5~3.6V"); - if(ocr.CCS) - sb.AppendLine("\tDevice is SDHC, SDXC or higher"); + if(ocr.ThreeFour) + sb.AppendLine("\tDevice can work with supply 3.4~3.5V"); - if(ocr.UHS) - sb.AppendLine("\tDevice is UHS-II or higher"); + if(ocr.ThreeThree) + sb.AppendLine("\tDevice can work with supply 3.3~3.4V"); - if(ocr.ThreeFive) - sb.AppendLine("\tDevice can work with supply 3.5~3.6V"); + if(ocr.ThreeTwo) + sb.AppendLine("\tDevice can work with supply 3.2~3.3V"); - if(ocr.ThreeFour) - sb.AppendLine("\tDevice can work with supply 3.4~3.5V"); + if(ocr.ThreeOne) + sb.AppendLine("\tDevice can work with supply 3.1~3.2V"); - if(ocr.ThreeThree) - sb.AppendLine("\tDevice can work with supply 3.3~3.4V"); + if(ocr.TwoNine) + sb.AppendLine("\tDevice can work with supply 2.9~3.0V"); - if(ocr.ThreeTwo) - sb.AppendLine("\tDevice can work with supply 3.2~3.3V"); + if(ocr.TwoEight) + sb.AppendLine("\tDevice can work with supply 2.8~2.9V"); - if(ocr.ThreeOne) - sb.AppendLine("\tDevice can work with supply 3.1~3.2V"); + if(ocr.TwoSeven) + sb.AppendLine("\tDevice can work with supply 2.7~2.8V"); - if(ocr.TwoNine) - sb.AppendLine("\tDevice can work with supply 2.9~3.0V"); + if(ocr.OneEight) + sb.AppendLine("\tDevice can switch to work with 1.8V supply"); - if(ocr.TwoEight) - sb.AppendLine("\tDevice can work with supply 2.8~2.9V"); + if(ocr.LowPower) + sb.AppendLine("\tDevice is in low power mode"); - if(ocr.TwoSeven) - sb.AppendLine("\tDevice can work with supply 2.7~2.8V"); - - if(ocr.OneEight) - sb.AppendLine("\tDevice can switch to work with 1.8V supply"); - - if(ocr.LowPower) - sb.AppendLine("\tDevice is in low power mode"); - - return sb.ToString(); - } - - public static string PrettifyOCR(byte[] response) => PrettifyOCR(DecodeOCR(response)); - - public static string PrettifyOCR(uint response) => PrettifyOCR(DecodeOCR(response)); + return sb.ToString(); } + + public static string PrettifyOCR(byte[] response) => PrettifyOCR(DecodeOCR(response)); + + public static string PrettifyOCR(uint response) => PrettifyOCR(DecodeOCR(response)); } \ No newline at end of file diff --git a/SecureDigital/SCR.cs b/SecureDigital/SCR.cs index 4e767e5..746999c 100644 --- a/SecureDigital/SCR.cs +++ b/SecureDigital/SCR.cs @@ -34,199 +34,198 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Text; -namespace Aaru.Decoders.SecureDigital +namespace Aaru.Decoders.SecureDigital; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public class SCR { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public class SCR + public BusWidth BusWidth; + public CommandSupport CommandSupport; + public bool DataStatusAfterErase; + public byte ExtendedSecurity; + public byte[] ManufacturerReserved; + public byte Security; + public byte Spec; + public bool Spec3; + public bool Spec4; + public byte SpecX; + public byte Structure; +} + +[Flags] +public enum BusWidth : byte +{ + OneBit = 1 << 0, FourBit = 1 << 2 +} + +[Flags] +public enum CommandSupport : byte +{ + SpeedClassControl = 1 << 0, SetBlockCount = 1 << 1, ExtensionRegisterSingleBlock = 1 << 2, + ExtensionRegisterMultiBlock = 1 << 3 +} + +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "InconsistentNaming")] +public static partial class Decoders +{ + public static SCR DecodeSCR(uint[] response) { - public BusWidth BusWidth; - public CommandSupport CommandSupport; - public bool DataStatusAfterErase; - public byte ExtendedSecurity; - public byte[] ManufacturerReserved; - public byte Security; - public byte Spec; - public bool Spec3; - public bool Spec4; - public byte SpecX; - public byte Structure; + if(response?.Length != 2) + return null; + + byte[] data = new byte[8]; + + byte[] tmp = BitConverter.GetBytes(response[0]); + Array.Copy(tmp, 0, data, 0, 4); + tmp = BitConverter.GetBytes(response[1]); + Array.Copy(tmp, 0, data, 4, 4); + + return DecodeSCR(data); } - [Flags] - public enum BusWidth : byte + public static SCR DecodeSCR(byte[] response) { - OneBit = 1 << 0, FourBit = 1 << 2 - } + if(response?.Length != 8) + return null; - [Flags] - public enum CommandSupport : byte - { - SpeedClassControl = 1 << 0, SetBlockCount = 1 << 1, ExtensionRegisterSingleBlock = 1 << 2, - ExtensionRegisterMultiBlock = 1 << 3 - } - - [SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "InconsistentNaming")] - public static partial class Decoders - { - public static SCR DecodeSCR(uint[] response) + var scr = new SCR { - if(response?.Length != 2) - return null; + Structure = (byte)((response[0] & 0xF0) >> 4), + Spec = (byte)(response[0] & 0x0F), + DataStatusAfterErase = (response[1] & 0x80) == 0x80, + Security = (byte)((response[1] & 0x70) >> 4), + BusWidth = (BusWidth)(response[1] & 0x0F), + Spec3 = (response[2] & 0x80) == 0x80, + ExtendedSecurity = (byte)((response[2] & 0x78) >> 3), + Spec4 = (response[2] & 0x04) == 0x04, + SpecX = (byte)(((response[2] & 0x03) << 2) + ((response[3] & 0xC0) >> 6)), + CommandSupport = (CommandSupport)(response[3] & 0x0F), + ManufacturerReserved = new byte[4] + }; - byte[] data = new byte[8]; + Array.Copy(response, 4, scr.ManufacturerReserved, 0, 4); - byte[] tmp = BitConverter.GetBytes(response[0]); - Array.Copy(tmp, 0, data, 0, 4); - tmp = BitConverter.GetBytes(response[1]); - Array.Copy(tmp, 0, data, 4, 4); + return scr; + } - return DecodeSCR(data); + public static string PrettifySCR(SCR scr) + { + if(scr == null) + return null; + + var sb = new StringBuilder(); + sb.AppendLine("SecureDigital Device Configuration Register:"); + + if(scr.Structure != 0) + sb.AppendFormat("\tUnknown register version {0}", scr.Structure).AppendLine(); + + switch(scr.Spec) + { + case 0 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 1.0x"); + + break; + case 1 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 1.10"); + + break; + case 2 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 2.00"); + + break; + case 2 when scr.Spec3 && scr.Spec4 == false && scr.SpecX == 0: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 3.0x"); + + break; + case 2 when scr.Spec3 && scr.Spec4 && scr.SpecX == 0: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 4.xx"); + + break; + case 2 when scr.Spec3: + switch(scr.SpecX) + { + case 1: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 5.xx"); + + break; + case 2: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 6.xx"); + + break; + case 3: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 7.xx"); + + break; + case 4: + sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 8.xx"); + + break; + } + + break; + default: + sb. + AppendFormat("\tDevice follows SecureDigital Physical Layer Specification with unknown version {0}.{1}.{2}.{3}", + scr.Spec, scr.Spec3, scr.Spec4, scr.SpecX).AppendLine(); + + break; } - public static SCR DecodeSCR(byte[] response) + switch(scr.Security) { - if(response?.Length != 8) - return null; + case 0: + sb.AppendLine("\tDevice does not support CPRM"); - var scr = new SCR - { - Structure = (byte)((response[0] & 0xF0) >> 4), - Spec = (byte)(response[0] & 0x0F), - DataStatusAfterErase = (response[1] & 0x80) == 0x80, - Security = (byte)((response[1] & 0x70) >> 4), - BusWidth = (BusWidth)(response[1] & 0x0F), - Spec3 = (response[2] & 0x80) == 0x80, - ExtendedSecurity = (byte)((response[2] & 0x78) >> 3), - Spec4 = (response[2] & 0x04) == 0x04, - SpecX = (byte)(((response[2] & 0x03) << 2) + ((response[3] & 0xC0) >> 6)), - CommandSupport = (CommandSupport)(response[3] & 0x0F), - ManufacturerReserved = new byte[4] - }; + break; + case 1: + sb.AppendLine("\tDevice does not use CPRM"); - Array.Copy(response, 4, scr.ManufacturerReserved, 0, 4); + break; + case 2: + sb.AppendLine("\tDevice uses CPRM according to specification version 1.01"); - return scr; + break; + case 3: + sb.AppendLine("\tDevice uses CPRM according to specification version 2.00"); + + break; + case 4: + sb.AppendLine("\tDevice uses CPRM according to specification version 3.xx"); + + break; + default: + sb.AppendFormat("\tDevice uses unknown CPRM specification with code {0}", scr.Security). + AppendLine(); + + break; } - public static string PrettifySCR(SCR scr) - { - if(scr == null) - return null; + if(scr.BusWidth.HasFlag(BusWidth.OneBit)) + sb.AppendLine("\tDevice supports 1-bit data bus"); - var sb = new StringBuilder(); - sb.AppendLine("SecureDigital Device Configuration Register:"); + if(scr.BusWidth.HasFlag(BusWidth.FourBit)) + sb.AppendLine("\tDevice supports 4-bit data bus"); - if(scr.Structure != 0) - sb.AppendFormat("\tUnknown register version {0}", scr.Structure).AppendLine(); + if(scr.ExtendedSecurity != 0) + sb.AppendLine("\tDevice supports extended security"); - switch(scr.Spec) - { - case 0 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 1.0x"); + if(scr.CommandSupport.HasFlag(CommandSupport.ExtensionRegisterMultiBlock)) + sb.AppendLine("\tDevice supports extension register multi-block commands"); - break; - case 1 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 1.10"); + if(scr.CommandSupport.HasFlag(CommandSupport.ExtensionRegisterSingleBlock)) + sb.AppendLine("\tDevice supports extension register single-block commands"); - break; - case 2 when scr.Spec3 == false && scr.Spec4 == false && scr.SpecX == 0: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 2.00"); + if(scr.CommandSupport.HasFlag(CommandSupport.SetBlockCount)) + sb.AppendLine("\tDevice supports set block count command"); - break; - case 2 when scr.Spec3 && scr.Spec4 == false && scr.SpecX == 0: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 3.0x"); + if(scr.CommandSupport.HasFlag(CommandSupport.SpeedClassControl)) + sb.AppendLine("\tDevice supports speed class control command"); - break; - case 2 when scr.Spec3 && scr.Spec4 && scr.SpecX == 0: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 4.xx"); - - break; - case 2 when scr.Spec3: - switch(scr.SpecX) - { - case 1: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 5.xx"); - - break; - case 2: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 6.xx"); - - break; - case 3: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 7.xx"); - - break; - case 4: - sb.AppendLine("\tDevice follows SecureDigital Physical Layer Specification version 8.xx"); - - break; - } - - break; - default: - sb. - AppendFormat("\tDevice follows SecureDigital Physical Layer Specification with unknown version {0}.{1}.{2}.{3}", - scr.Spec, scr.Spec3, scr.Spec4, scr.SpecX).AppendLine(); - - break; - } - - switch(scr.Security) - { - case 0: - sb.AppendLine("\tDevice does not support CPRM"); - - break; - case 1: - sb.AppendLine("\tDevice does not use CPRM"); - - break; - case 2: - sb.AppendLine("\tDevice uses CPRM according to specification version 1.01"); - - break; - case 3: - sb.AppendLine("\tDevice uses CPRM according to specification version 2.00"); - - break; - case 4: - sb.AppendLine("\tDevice uses CPRM according to specification version 3.xx"); - - break; - default: - sb.AppendFormat("\tDevice uses unknown CPRM specification with code {0}", scr.Security). - AppendLine(); - - break; - } - - if(scr.BusWidth.HasFlag(BusWidth.OneBit)) - sb.AppendLine("\tDevice supports 1-bit data bus"); - - if(scr.BusWidth.HasFlag(BusWidth.FourBit)) - sb.AppendLine("\tDevice supports 4-bit data bus"); - - if(scr.ExtendedSecurity != 0) - sb.AppendLine("\tDevice supports extended security"); - - if(scr.CommandSupport.HasFlag(CommandSupport.ExtensionRegisterMultiBlock)) - sb.AppendLine("\tDevice supports extension register multi-block commands"); - - if(scr.CommandSupport.HasFlag(CommandSupport.ExtensionRegisterSingleBlock)) - sb.AppendLine("\tDevice supports extension register single-block commands"); - - if(scr.CommandSupport.HasFlag(CommandSupport.SetBlockCount)) - sb.AppendLine("\tDevice supports set block count command"); - - if(scr.CommandSupport.HasFlag(CommandSupport.SpeedClassControl)) - sb.AppendLine("\tDevice supports speed class control command"); - - return sb.ToString(); - } - - public static string PrettifySCR(uint[] response) => PrettifySCR(DecodeSCR(response)); - - public static string PrettifySCR(byte[] response) => PrettifySCR(DecodeSCR(response)); + return sb.ToString(); } + + public static string PrettifySCR(uint[] response) => PrettifySCR(DecodeSCR(response)); + + public static string PrettifySCR(byte[] response) => PrettifySCR(DecodeSCR(response)); } \ No newline at end of file diff --git a/SecureDigital/VendorString.cs b/SecureDigital/VendorString.cs index d1bad28..8dc747c 100644 --- a/SecureDigital/VendorString.cs +++ b/SecureDigital/VendorString.cs @@ -30,22 +30,21 @@ // Copyright © 2011-2022 Natalia Portillo // ****************************************************************************/ -namespace Aaru.Decoders.SecureDigital +namespace Aaru.Decoders.SecureDigital; + +/// Decodes SecureDigital vendors +public static class VendorString { - /// Decodes SecureDigital vendors - public static class VendorString + /// Converts the byte value of a SecureDigital vendor ID to the manufacturer's name string + /// SD vendor ID + /// Manufacturer + public static string Prettify(byte sdVendorId) => sdVendorId switch { - /// Converts the byte value of a SecureDigital vendor ID to the manufacturer's name string - /// SD vendor ID - /// Manufacturer - public static string Prettify(byte sdVendorId) => sdVendorId switch - { - 0x41 => "Kingston", - 0x02 => "Kingston", - 0x03 => "Sandisk", - 0x27 => "CnMemory", - 0xAA => "QEMU", - _ => $"Unknown manufacturer ID 0x{sdVendorId:X2}" - }; - } + 0x41 => "Kingston", + 0x02 => "Kingston", + 0x03 => "Sandisk", + 0x27 => "CnMemory", + 0xAA => "QEMU", + _ => $"Unknown manufacturer ID 0x{sdVendorId:X2}" + }; } \ No newline at end of file diff --git a/Sega/CD.cs b/Sega/CD.cs index a5abf3a..d95a3a3 100644 --- a/Sega/CD.cs +++ b/Sega/CD.cs @@ -38,348 +38,347 @@ using System.Text; using Aaru.Console; using Marshal = Aaru.Helpers.Marshal; -namespace Aaru.Decoders.Sega +namespace Aaru.Decoders.Sega; + +/// Represents the IP.BIN from a SEGA CD / MEGA CD +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class CD { - /// Represents the IP.BIN from a SEGA CD / MEGA CD - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class CD + /// Decodes an IP.BIN sector in SEGA CD / MEGA CD format + /// IP.BIN sector + /// Decoded IP.BIN + public static IPBin? DecodeIPBin(byte[] ipbin_sector) { - /// Decodes an IP.BIN sector in SEGA CD / MEGA CD format - /// IP.BIN sector - /// Decoded IP.BIN - public static IPBin? DecodeIPBin(byte[] ipbin_sector) + if(ipbin_sector == null) + return null; + + if(ipbin_sector.Length < 512) + return null; + + IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.volume_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.volume_name)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.system_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.system_name)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.volume_version = \"{0:X}\"", + ipbin.volume_version); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.volume_type = 0x{0:X8}", + ipbin.volume_type); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.system_version = 0x{0:X8}", + ipbin.system_version); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_address = 0x{0:X8}", ipbin.ip_address); + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_loadsize = {0}", ipbin.ip_loadsize); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_entry_address = 0x{0:X8}", + ipbin.ip_entry_address); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_work_ram_size = {0}", + ipbin.ip_work_ram_size); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_address = 0x{0:X8}", ipbin.sp_address); + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_loadsize = {0}", ipbin.sp_loadsize); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_entry_address = 0x{0:X8}", + ipbin.sp_entry_address); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_work_ram_size = {0}", + ipbin.sp_work_ram_size); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.release_date = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.release_date2 = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date2)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.developer_code = \"{0}\"", + Encoding.ASCII.GetString(ipbin.developer_code)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.domestic_title = \"{0}\"", + Encoding.ASCII.GetString(ipbin.domestic_title)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.overseas_title = \"{0}\"", + Encoding.ASCII.GetString(ipbin.overseas_title)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.product_code = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_code)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.peripherals = \"{0}\"", + Encoding.ASCII.GetString(ipbin.peripherals)); + + AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.region_codes = \"{0}\"", + Encoding.ASCII.GetString(ipbin.region_codes)); + + string id = Encoding.ASCII.GetString(ipbin.SegaHardwareID); + + return id == "SEGADISCSYSTEM " || id == "SEGADATADISC " || id == "SEGAOS " ? ipbin + : (IPBin?)null; + } + + /// Pretty prints a decoded IP.BIN in SEGA CD / MEGA CD format + /// Decoded IP.BIN + /// Description of the IP.BIN contents + public static string Prettify(IPBin? decoded) + { + if(decoded == null) + return null; + + IPBin ipbin = decoded.Value; + + var IPBinInformation = new StringBuilder(); + + IPBinInformation.AppendLine("--------------------------------"); + IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:"); + IPBinInformation.AppendLine("--------------------------------"); + + // Decoding all data + DateTime ipbindate = DateTime.MinValue; + CultureInfo provider = CultureInfo.InvariantCulture; + + try { - if(ipbin_sector == null) - return null; - - if(ipbin_sector.Length < 512) - return null; - - IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.volume_name = \"{0}\"", - Encoding.ASCII.GetString(ipbin.volume_name)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.system_name = \"{0}\"", - Encoding.ASCII.GetString(ipbin.system_name)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.volume_version = \"{0:X}\"", - ipbin.volume_version); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.volume_type = 0x{0:X8}", - ipbin.volume_type); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.system_version = 0x{0:X8}", - ipbin.system_version); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_address = 0x{0:X8}", ipbin.ip_address); - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_loadsize = {0}", ipbin.ip_loadsize); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_entry_address = 0x{0:X8}", - ipbin.ip_entry_address); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.ip_work_ram_size = {0}", - ipbin.ip_work_ram_size); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_address = 0x{0:X8}", ipbin.sp_address); - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_loadsize = {0}", ipbin.sp_loadsize); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_entry_address = 0x{0:X8}", - ipbin.sp_entry_address); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.sp_work_ram_size = {0}", - ipbin.sp_work_ram_size); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.release_date = \"{0}\"", - Encoding.ASCII.GetString(ipbin.release_date)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.release_date2 = \"{0}\"", - Encoding.ASCII.GetString(ipbin.release_date2)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.developer_code = \"{0}\"", - Encoding.ASCII.GetString(ipbin.developer_code)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.domestic_title = \"{0}\"", - Encoding.ASCII.GetString(ipbin.domestic_title)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.overseas_title = \"{0}\"", - Encoding.ASCII.GetString(ipbin.overseas_title)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.product_code = \"{0}\"", - Encoding.ASCII.GetString(ipbin.product_code)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.peripherals = \"{0}\"", - Encoding.ASCII.GetString(ipbin.peripherals)); - - AaruConsole.DebugWriteLine("SegaCD IP.BIN Decoder", "segacd_ipbin.region_codes = \"{0}\"", - Encoding.ASCII.GetString(ipbin.region_codes)); - - string id = Encoding.ASCII.GetString(ipbin.SegaHardwareID); - - return id == "SEGADISCSYSTEM " || id == "SEGADATADISC " || id == "SEGAOS " ? ipbin - : (IPBin?)null; + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "MMddyyyy", provider); } - - /// Pretty prints a decoded IP.BIN in SEGA CD / MEGA CD format - /// Decoded IP.BIN - /// Description of the IP.BIN contents - public static string Prettify(IPBin? decoded) + catch { - if(decoded == null) - return null; - - IPBin ipbin = decoded.Value; - - var IPBinInformation = new StringBuilder(); - - IPBinInformation.AppendLine("--------------------------------"); - IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:"); - IPBinInformation.AppendLine("--------------------------------"); - - // Decoding all data - DateTime ipbindate = DateTime.MinValue; - CultureInfo provider = CultureInfo.InvariantCulture; - try { - ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "MMddyyyy", provider); + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date2), "yyyy.MMM", + provider); } + #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { - try - { - ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date2), "yyyy.MMM", - provider); - } - #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body - catch - { - // ignored - } - #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body + // ignored } - - /* - switch (Encoding.ASCII.GetString(application_type)) - { - case "GM": - IPBinInformation.AppendLine("Disc is a game."); - break; - case "AI": - IPBinInformation.AppendLine("Disc is an application."); - break; - default: - IPBinInformation.AppendLine("Disc is from unknown type."); - break; - } - */ - - IPBinInformation.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(ipbin.volume_name)).AppendLine(); - - //IPBinInformation.AppendFormat("Volume version: {0}", Encoding.ASCII.GetString(ipbin.volume_version)).AppendLine(); - //IPBinInformation.AppendFormat("{0}", Encoding.ASCII.GetString(ipbin.volume_type)).AppendLine(); - IPBinInformation.AppendFormat("System name: {0}", Encoding.ASCII.GetString(ipbin.system_name)).AppendLine(); - - //IPBinInformation.AppendFormat("System version: {0}", Encoding.ASCII.GetString(ipbin.system_version)).AppendLine(); - IPBinInformation.AppendFormat("Initial program address: 0x{0:X8}", ipbin.ip_address).AppendLine(); - IPBinInformation.AppendFormat("Initial program load size: {0} bytes", ipbin.ip_loadsize).AppendLine(); - - IPBinInformation.AppendFormat("Initial program entry address: 0x{0:X8}", ipbin.ip_entry_address). - AppendLine(); - - IPBinInformation.AppendFormat("Initial program work RAM: {0} bytes", ipbin.ip_work_ram_size).AppendLine(); - IPBinInformation.AppendFormat("System program address: 0x{0:X8}", ipbin.sp_address).AppendLine(); - IPBinInformation.AppendFormat("System program load size: {0} bytes", ipbin.sp_loadsize).AppendLine(); - - IPBinInformation.AppendFormat("System program entry address: 0x{0:X8}", ipbin.sp_entry_address). - AppendLine(); - - IPBinInformation.AppendFormat("System program work RAM: {0} bytes", ipbin.sp_work_ram_size).AppendLine(); - - if(ipbindate != DateTime.MinValue) - IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); - - //IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine(); - IPBinInformation.AppendFormat("Hardware ID: {0}", Encoding.ASCII.GetString(ipbin.hardware_id)).AppendLine(); - - IPBinInformation.AppendFormat("Developer code: {0}", Encoding.ASCII.GetString(ipbin.developer_code)). - AppendLine(); - - IPBinInformation.AppendFormat("Domestic title: {0}", Encoding.ASCII.GetString(ipbin.domestic_title)). - AppendLine(); - - IPBinInformation.AppendFormat("Overseas title: {0}", Encoding.ASCII.GetString(ipbin.overseas_title)). - AppendLine(); - - IPBinInformation.AppendFormat("Product code: {0}", Encoding.ASCII.GetString(ipbin.product_code)). - AppendLine(); - - IPBinInformation.AppendFormat("Peripherals:").AppendLine(); - - foreach(byte peripheral in ipbin.peripherals) - switch((char)peripheral) - { - case 'A': - IPBinInformation.AppendLine("Game supports analog controller."); - - break; - case 'B': - IPBinInformation.AppendLine("Game supports trackball."); - - break; - case 'G': - IPBinInformation.AppendLine("Game supports light gun."); - - break; - case 'J': - IPBinInformation.AppendLine("Game supports JoyPad."); - - break; - case 'K': - IPBinInformation.AppendLine("Game supports keyboard."); - - break; - case 'M': - IPBinInformation.AppendLine("Game supports mouse."); - - break; - case 'O': - IPBinInformation.AppendLine("Game supports Master System's JoyPad."); - - break; - case 'P': - IPBinInformation.AppendLine("Game supports printer interface."); - - break; - case 'R': - IPBinInformation.AppendLine("Game supports serial (RS-232C) interface."); - - break; - case 'T': - IPBinInformation.AppendLine("Game supports tablet interface."); - - break; - case 'V': - IPBinInformation.AppendLine("Game supports paddle controller."); - - break; - case ' ': break; - default: - IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral).AppendLine(); - - break; - } - - IPBinInformation.AppendLine("Regions supported:"); - - foreach(byte region in ipbin.region_codes) - switch((char)region) - { - case 'J': - IPBinInformation.AppendLine("Japanese NTSC."); - - break; - case 'U': - IPBinInformation.AppendLine("USA NTSC."); - - break; - case 'E': - IPBinInformation.AppendLine("Europe PAL."); - - break; - case ' ': break; - default: - IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine(); - - break; - } - - return IPBinInformation.ToString(); + #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body } - // TODO: Check if it is big or little endian - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct IPBin + /* + switch (Encoding.ASCII.GetString(application_type)) { - /// Must be "SEGADISCSYSTEM " or "SEGADATADISC " or "SEGAOS " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] SegaHardwareID; - /// 0x010, Varies - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public byte[] volume_name; - /// 0x01B, 0x00 - public byte spare_space1; - /// 0x01C, Volume version in BCD. <100 = Prerelease. - public ushort volume_version; - /// 0x01E, Bit 0 = 1 => CD-ROM. Rest should be 0. - public ushort volume_type; - /// 0x020, Unknown, varies! - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] - public byte[] system_name; - /// 0x02B, 0x00 - public byte spare_space2; - /// 0x02C, Should be 1 - public ushort system_version; - /// 0x02E, 0x0000 - public ushort spare_space3; - /// 0x030, Initial program address - public uint ip_address; - /// 0x034, Load size of initial program - public uint ip_loadsize; - /// 0x038, Initial program entry address - public uint ip_entry_address; - /// 0x03C, Initial program work RAM size in bytes - public uint ip_work_ram_size; - /// 0x040, System program address - public uint sp_address; - /// 0x044, Load size of system program - public uint sp_loadsize; - /// 0x048, System program entry address - public uint sp_entry_address; - /// 0x04C, System program work RAM size in bytes - public uint sp_work_ram_size; - /// 0x050, MMDDYYYY - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] release_date; - /// 0x058, Seems to be all 0x20s - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] - public byte[] unknown1; - /// 0x05F, 0x00 ? - public byte spare_space4; - /// 0x060, System Reserved Area - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 160)] - public byte[] system_reserved; - /// 0x100, Hardware ID - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] hardware_id; - /// 0x113 or 0x110, "SEGA" or "T-xx" - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public byte[] developer_code; - /// 0x118, Another release date, this with month in letters? - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] release_date2; - /// 0x120, Domestic version of the game title - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] - public byte[] domestic_title; - /// 0x150, Overseas version of the game title - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] - public byte[] overseas_title; - /// 0x180, Official product code - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] - public byte[] product_code; - /// 0x190, Supported peripherals, see above - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] peripherals; - /// 0x1A0, 0x20 - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] spare_space6; - /// 0x1B0, Inside here should be modem information, but I need to get a modem-enabled game - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public byte[] spare_space7; - /// 0x1F0, Region codes, space-filled - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] region_codes; + case "GM": + IPBinInformation.AppendLine("Disc is a game."); + break; + case "AI": + IPBinInformation.AppendLine("Disc is an application."); + break; + default: + IPBinInformation.AppendLine("Disc is from unknown type."); + break; } + */ + + IPBinInformation.AppendFormat("Volume name: {0}", Encoding.ASCII.GetString(ipbin.volume_name)).AppendLine(); + + //IPBinInformation.AppendFormat("Volume version: {0}", Encoding.ASCII.GetString(ipbin.volume_version)).AppendLine(); + //IPBinInformation.AppendFormat("{0}", Encoding.ASCII.GetString(ipbin.volume_type)).AppendLine(); + IPBinInformation.AppendFormat("System name: {0}", Encoding.ASCII.GetString(ipbin.system_name)).AppendLine(); + + //IPBinInformation.AppendFormat("System version: {0}", Encoding.ASCII.GetString(ipbin.system_version)).AppendLine(); + IPBinInformation.AppendFormat("Initial program address: 0x{0:X8}", ipbin.ip_address).AppendLine(); + IPBinInformation.AppendFormat("Initial program load size: {0} bytes", ipbin.ip_loadsize).AppendLine(); + + IPBinInformation.AppendFormat("Initial program entry address: 0x{0:X8}", ipbin.ip_entry_address). + AppendLine(); + + IPBinInformation.AppendFormat("Initial program work RAM: {0} bytes", ipbin.ip_work_ram_size).AppendLine(); + IPBinInformation.AppendFormat("System program address: 0x{0:X8}", ipbin.sp_address).AppendLine(); + IPBinInformation.AppendFormat("System program load size: {0} bytes", ipbin.sp_loadsize).AppendLine(); + + IPBinInformation.AppendFormat("System program entry address: 0x{0:X8}", ipbin.sp_entry_address). + AppendLine(); + + IPBinInformation.AppendFormat("System program work RAM: {0} bytes", ipbin.sp_work_ram_size).AppendLine(); + + if(ipbindate != DateTime.MinValue) + IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); + + //IPBinInformation.AppendFormat("Release date (other format): {0}", Encoding.ASCII.GetString(release_date2)).AppendLine(); + IPBinInformation.AppendFormat("Hardware ID: {0}", Encoding.ASCII.GetString(ipbin.hardware_id)).AppendLine(); + + IPBinInformation.AppendFormat("Developer code: {0}", Encoding.ASCII.GetString(ipbin.developer_code)). + AppendLine(); + + IPBinInformation.AppendFormat("Domestic title: {0}", Encoding.ASCII.GetString(ipbin.domestic_title)). + AppendLine(); + + IPBinInformation.AppendFormat("Overseas title: {0}", Encoding.ASCII.GetString(ipbin.overseas_title)). + AppendLine(); + + IPBinInformation.AppendFormat("Product code: {0}", Encoding.ASCII.GetString(ipbin.product_code)). + AppendLine(); + + IPBinInformation.AppendFormat("Peripherals:").AppendLine(); + + foreach(byte peripheral in ipbin.peripherals) + switch((char)peripheral) + { + case 'A': + IPBinInformation.AppendLine("Game supports analog controller."); + + break; + case 'B': + IPBinInformation.AppendLine("Game supports trackball."); + + break; + case 'G': + IPBinInformation.AppendLine("Game supports light gun."); + + break; + case 'J': + IPBinInformation.AppendLine("Game supports JoyPad."); + + break; + case 'K': + IPBinInformation.AppendLine("Game supports keyboard."); + + break; + case 'M': + IPBinInformation.AppendLine("Game supports mouse."); + + break; + case 'O': + IPBinInformation.AppendLine("Game supports Master System's JoyPad."); + + break; + case 'P': + IPBinInformation.AppendLine("Game supports printer interface."); + + break; + case 'R': + IPBinInformation.AppendLine("Game supports serial (RS-232C) interface."); + + break; + case 'T': + IPBinInformation.AppendLine("Game supports tablet interface."); + + break; + case 'V': + IPBinInformation.AppendLine("Game supports paddle controller."); + + break; + case ' ': break; + default: + IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral).AppendLine(); + + break; + } + + IPBinInformation.AppendLine("Regions supported:"); + + foreach(byte region in ipbin.region_codes) + switch((char)region) + { + case 'J': + IPBinInformation.AppendLine("Japanese NTSC."); + + break; + case 'U': + IPBinInformation.AppendLine("USA NTSC."); + + break; + case 'E': + IPBinInformation.AppendLine("Europe PAL."); + + break; + case ' ': break; + default: + IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine(); + + break; + } + + return IPBinInformation.ToString(); + } + + // TODO: Check if it is big or little endian + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IPBin + { + /// Must be "SEGADISCSYSTEM " or "SEGADATADISC " or "SEGAOS " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, Varies + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] volume_name; + /// 0x01B, 0x00 + public byte spare_space1; + /// 0x01C, Volume version in BCD. <100 = Prerelease. + public ushort volume_version; + /// 0x01E, Bit 0 = 1 => CD-ROM. Rest should be 0. + public ushort volume_type; + /// 0x020, Unknown, varies! + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] system_name; + /// 0x02B, 0x00 + public byte spare_space2; + /// 0x02C, Should be 1 + public ushort system_version; + /// 0x02E, 0x0000 + public ushort spare_space3; + /// 0x030, Initial program address + public uint ip_address; + /// 0x034, Load size of initial program + public uint ip_loadsize; + /// 0x038, Initial program entry address + public uint ip_entry_address; + /// 0x03C, Initial program work RAM size in bytes + public uint ip_work_ram_size; + /// 0x040, System program address + public uint sp_address; + /// 0x044, Load size of system program + public uint sp_loadsize; + /// 0x048, System program entry address + public uint sp_entry_address; + /// 0x04C, System program work RAM size in bytes + public uint sp_work_ram_size; + /// 0x050, MMDDYYYY + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x058, Seems to be all 0x20s + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] unknown1; + /// 0x05F, 0x00 ? + public byte spare_space4; + /// 0x060, System Reserved Area + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 160)] + public byte[] system_reserved; + /// 0x100, Hardware ID + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] hardware_id; + /// 0x113 or 0x110, "SEGA" or "T-xx" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public byte[] developer_code; + /// 0x118, Another release date, this with month in letters? + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date2; + /// 0x120, Domestic version of the game title + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] domestic_title; + /// 0x150, Overseas version of the game title + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] + public byte[] overseas_title; + /// 0x180, Official product code + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] + public byte[] product_code; + /// 0x190, Supported peripherals, see above + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] peripherals; + /// 0x1A0, 0x20 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] spare_space6; + /// 0x1B0, Inside here should be modem information, but I need to get a modem-enabled game + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public byte[] spare_space7; + /// 0x1F0, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] region_codes; } } \ No newline at end of file diff --git a/Sega/Dreamcast.cs b/Sega/Dreamcast.cs index f1b89b0..9194f56 100644 --- a/Sega/Dreamcast.cs +++ b/Sega/Dreamcast.cs @@ -38,290 +38,289 @@ using System.Text; using Aaru.Console; using Marshal = Aaru.Helpers.Marshal; -namespace Aaru.Decoders.Sega +namespace Aaru.Decoders.Sega; + +/// Represents the IP.BIN from a SEGA Dreamcast +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Dreamcast { - /// Represents the IP.BIN from a SEGA Dreamcast - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Dreamcast + /// Decodes an IP.BIN sector in Dreamcast format + /// IP.BIN sector + /// Decoded IP.BIN + public static IPBin? DecodeIPBin(byte[] ipbin_sector) { - /// Decodes an IP.BIN sector in Dreamcast format - /// IP.BIN sector - /// Decoded IP.BIN - public static IPBin? DecodeIPBin(byte[] ipbin_sector) + if(ipbin_sector == null) + return null; + + if(ipbin_sector.Length < 512) + return null; + + IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.maker_id = \"{0}\"", + Encoding.ASCII.GetString(ipbin.maker_id)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.spare_space1 = \"{0}\"", + (char)ipbin.spare_space1); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.dreamcast_media = \"{0}\"", + Encoding.ASCII.GetString(ipbin.dreamcast_media)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.disc_no = {0}", + (char)ipbin.disc_no); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.disc_no_separator = \"{0}\"", + (char)ipbin.disc_no_separator); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.disc_total_nos = \"{0}\"", + (char)ipbin.disc_total_nos); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.spare_space2 = \"{0}\"", + Encoding.ASCII.GetString(ipbin.spare_space2)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.region_codes = \"{0}\"", + Encoding.ASCII.GetString(ipbin.region_codes)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.peripherals = \"{0}\"", + Encoding.ASCII.GetString(ipbin.peripherals)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.product_no = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_no)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.product_version = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_version)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.release_date = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.spare_space3 = \"{0}\"", + (char)ipbin.spare_space3); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.boot_filename = \"{0}\"", + Encoding.ASCII.GetString(ipbin.boot_filename)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.producer = \"{0}\"", + Encoding.ASCII.GetString(ipbin.producer)); + + AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.product_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_name)); + + return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGAKATANA " ? ipbin : (IPBin?)null; + } + + /// Pretty prints a decoded IP.BIN in Dreamcast format + /// Decoded IP.BIN + /// Description of the IP.BIN contents + public static string Prettify(IPBin? decoded) + { + if(decoded == null) + return null; + + IPBin ipbin = decoded.Value; + + var IPBinInformation = new StringBuilder(); + + IPBinInformation.AppendLine("--------------------------------"); + IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:"); + IPBinInformation.AppendLine("--------------------------------"); + + // Decoding all data + DateTime ipbindate; + CultureInfo provider = CultureInfo.InvariantCulture; + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "yyyyMMdd", provider); + + IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(ipbin.product_name)). + AppendLine(); + + IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(ipbin.product_version)). + AppendLine(); + + IPBinInformation.AppendFormat("Product CRC: 0x{0:X8}", ipbin.dreamcast_crc).AppendLine(); + IPBinInformation.AppendFormat("Producer: {0}", Encoding.ASCII.GetString(ipbin.producer)).AppendLine(); + + IPBinInformation.AppendFormat("Disc media: {0}", Encoding.ASCII.GetString(ipbin.dreamcast_media)). + AppendLine(); + + IPBinInformation.AppendFormat("Disc number {0} of {1}", (char)ipbin.disc_no, (char)ipbin.disc_total_nos). + AppendLine(); + + IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); + + switch(Encoding.ASCII.GetString(ipbin.boot_filename)) { - if(ipbin_sector == null) - return null; + case "1ST_READ.BIN": + IPBinInformation.AppendLine("Disc boots natively."); - if(ipbin_sector.Length < 512) - return null; + break; + case "0WINCE.BIN ": + IPBinInformation.AppendLine("Disc boots using Windows CE."); - IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); + break; + default: + IPBinInformation.AppendFormat("Disc boots using unknown loader: {0}.", + Encoding.ASCII.GetString(ipbin.boot_filename)).AppendLine(); - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.maker_id = \"{0}\"", - Encoding.ASCII.GetString(ipbin.maker_id)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.spare_space1 = \"{0}\"", - (char)ipbin.spare_space1); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.dreamcast_media = \"{0}\"", - Encoding.ASCII.GetString(ipbin.dreamcast_media)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.disc_no = {0}", - (char)ipbin.disc_no); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.disc_no_separator = \"{0}\"", - (char)ipbin.disc_no_separator); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.disc_total_nos = \"{0}\"", - (char)ipbin.disc_total_nos); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.spare_space2 = \"{0}\"", - Encoding.ASCII.GetString(ipbin.spare_space2)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.region_codes = \"{0}\"", - Encoding.ASCII.GetString(ipbin.region_codes)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.peripherals = \"{0}\"", - Encoding.ASCII.GetString(ipbin.peripherals)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.product_no = \"{0}\"", - Encoding.ASCII.GetString(ipbin.product_no)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.product_version = \"{0}\"", - Encoding.ASCII.GetString(ipbin.product_version)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.release_date = \"{0}\"", - Encoding.ASCII.GetString(ipbin.release_date)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.spare_space3 = \"{0}\"", - (char)ipbin.spare_space3); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.boot_filename = \"{0}\"", - Encoding.ASCII.GetString(ipbin.boot_filename)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.producer = \"{0}\"", - Encoding.ASCII.GetString(ipbin.producer)); - - AaruConsole.DebugWriteLine("Dreamcast IP.BIN Decoder", "dreamcast_ipbin.product_name = \"{0}\"", - Encoding.ASCII.GetString(ipbin.product_name)); - - return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGAKATANA " ? ipbin : (IPBin?)null; + break; } - /// Pretty prints a decoded IP.BIN in Dreamcast format - /// Decoded IP.BIN - /// Description of the IP.BIN contents - public static string Prettify(IPBin? decoded) - { - if(decoded == null) - return null; + IPBinInformation.AppendLine("Regions supported:"); - IPBin ipbin = decoded.Value; - - var IPBinInformation = new StringBuilder(); - - IPBinInformation.AppendLine("--------------------------------"); - IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:"); - IPBinInformation.AppendLine("--------------------------------"); - - // Decoding all data - DateTime ipbindate; - CultureInfo provider = CultureInfo.InvariantCulture; - ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "yyyyMMdd", provider); - - IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(ipbin.product_name)). - AppendLine(); - - IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(ipbin.product_version)). - AppendLine(); - - IPBinInformation.AppendFormat("Product CRC: 0x{0:X8}", ipbin.dreamcast_crc).AppendLine(); - IPBinInformation.AppendFormat("Producer: {0}", Encoding.ASCII.GetString(ipbin.producer)).AppendLine(); - - IPBinInformation.AppendFormat("Disc media: {0}", Encoding.ASCII.GetString(ipbin.dreamcast_media)). - AppendLine(); - - IPBinInformation.AppendFormat("Disc number {0} of {1}", (char)ipbin.disc_no, (char)ipbin.disc_total_nos). - AppendLine(); - - IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); - - switch(Encoding.ASCII.GetString(ipbin.boot_filename)) + foreach(byte region in ipbin.region_codes) + switch((char)region) { - case "1ST_READ.BIN": - IPBinInformation.AppendLine("Disc boots natively."); + case 'J': + IPBinInformation.AppendLine("Japanese NTSC."); break; - case "0WINCE.BIN ": - IPBinInformation.AppendLine("Disc boots using Windows CE."); + case 'U': + IPBinInformation.AppendLine("North America NTSC."); break; + case 'E': + IPBinInformation.AppendLine("Europe PAL."); + + break; + case ' ': break; default: - IPBinInformation.AppendFormat("Disc boots using unknown loader: {0}.", - Encoding.ASCII.GetString(ipbin.boot_filename)).AppendLine(); + IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine(); break; } - IPBinInformation.AppendLine("Regions supported:"); + int iPeripherals = int.Parse(Encoding.ASCII.GetString(ipbin.peripherals), NumberStyles.HexNumber); - foreach(byte region in ipbin.region_codes) - switch((char)region) - { - case 'J': - IPBinInformation.AppendLine("Japanese NTSC."); + if((iPeripherals & 0x00000001) == 0x00000001) + IPBinInformation.AppendLine("Game uses Windows CE."); - break; - case 'U': - IPBinInformation.AppendLine("North America NTSC."); + IPBinInformation.AppendFormat("Peripherals:").AppendLine(); - break; - case 'E': - IPBinInformation.AppendLine("Europe PAL."); + if((iPeripherals & 0x00000010) == 0x00000010) + IPBinInformation.AppendLine("Game supports the VGA Box."); - break; - case ' ': break; - default: - IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine(); + if((iPeripherals & 0x00000100) == 0x00000100) + IPBinInformation.AppendLine("Game supports other expansion."); - break; - } + if((iPeripherals & 0x00000200) == 0x00000200) + IPBinInformation.AppendLine("Game supports Puru Puru pack."); - int iPeripherals = int.Parse(Encoding.ASCII.GetString(ipbin.peripherals), NumberStyles.HexNumber); + if((iPeripherals & 0x00000400) == 0x00000400) + IPBinInformation.AppendLine("Game supports Mike Device."); - if((iPeripherals & 0x00000001) == 0x00000001) - IPBinInformation.AppendLine("Game uses Windows CE."); + if((iPeripherals & 0x00000800) == 0x00000800) + IPBinInformation.AppendLine("Game supports Memory Card."); - IPBinInformation.AppendFormat("Peripherals:").AppendLine(); + if((iPeripherals & 0x00001000) == 0x00001000) + IPBinInformation.AppendLine("Game requires A + B + Start buttons and D-Pad."); - if((iPeripherals & 0x00000010) == 0x00000010) - IPBinInformation.AppendLine("Game supports the VGA Box."); + if((iPeripherals & 0x00002000) == 0x00002000) + IPBinInformation.AppendLine("Game requires C button."); - if((iPeripherals & 0x00000100) == 0x00000100) - IPBinInformation.AppendLine("Game supports other expansion."); + if((iPeripherals & 0x00004000) == 0x00004000) + IPBinInformation.AppendLine("Game requires D button."); - if((iPeripherals & 0x00000200) == 0x00000200) - IPBinInformation.AppendLine("Game supports Puru Puru pack."); + if((iPeripherals & 0x00008000) == 0x00008000) + IPBinInformation.AppendLine("Game requires X button."); - if((iPeripherals & 0x00000400) == 0x00000400) - IPBinInformation.AppendLine("Game supports Mike Device."); + if((iPeripherals & 0x00010000) == 0x00010000) + IPBinInformation.AppendLine("Game requires Y button."); - if((iPeripherals & 0x00000800) == 0x00000800) - IPBinInformation.AppendLine("Game supports Memory Card."); + if((iPeripherals & 0x00020000) == 0x00020000) + IPBinInformation.AppendLine("Game requires Z button."); - if((iPeripherals & 0x00001000) == 0x00001000) - IPBinInformation.AppendLine("Game requires A + B + Start buttons and D-Pad."); + if((iPeripherals & 0x00040000) == 0x00040000) + IPBinInformation.AppendLine("Game requires expanded direction buttons."); - if((iPeripherals & 0x00002000) == 0x00002000) - IPBinInformation.AppendLine("Game requires C button."); + if((iPeripherals & 0x00080000) == 0x00080000) + IPBinInformation.AppendLine("Game requires analog R trigger."); - if((iPeripherals & 0x00004000) == 0x00004000) - IPBinInformation.AppendLine("Game requires D button."); + if((iPeripherals & 0x00100000) == 0x00100000) + IPBinInformation.AppendLine("Game requires analog L trigger."); - if((iPeripherals & 0x00008000) == 0x00008000) - IPBinInformation.AppendLine("Game requires X button."); + if((iPeripherals & 0x00200000) == 0x00200000) + IPBinInformation.AppendLine("Game requires analog horizontal controller."); - if((iPeripherals & 0x00010000) == 0x00010000) - IPBinInformation.AppendLine("Game requires Y button."); + if((iPeripherals & 0x00400000) == 0x00400000) + IPBinInformation.AppendLine("Game requires analog vertical controller."); - if((iPeripherals & 0x00020000) == 0x00020000) - IPBinInformation.AppendLine("Game requires Z button."); + if((iPeripherals & 0x00800000) == 0x00800000) + IPBinInformation.AppendLine("Game requires expanded analog horizontal controller."); - if((iPeripherals & 0x00040000) == 0x00040000) - IPBinInformation.AppendLine("Game requires expanded direction buttons."); + if((iPeripherals & 0x01000000) == 0x01000000) + IPBinInformation.AppendLine("Game requires expanded analog vertical controller."); - if((iPeripherals & 0x00080000) == 0x00080000) - IPBinInformation.AppendLine("Game requires analog R trigger."); + if((iPeripherals & 0x02000000) == 0x02000000) + IPBinInformation.AppendLine("Game supports Gun."); - if((iPeripherals & 0x00100000) == 0x00100000) - IPBinInformation.AppendLine("Game requires analog L trigger."); + if((iPeripherals & 0x04000000) == 0x04000000) + IPBinInformation.AppendLine("Game supports Keyboard."); - if((iPeripherals & 0x00200000) == 0x00200000) - IPBinInformation.AppendLine("Game requires analog horizontal controller."); + if((iPeripherals & 0x08000000) == 0x08000000) + IPBinInformation.AppendLine("Game supports Mouse."); - if((iPeripherals & 0x00400000) == 0x00400000) - IPBinInformation.AppendLine("Game requires analog vertical controller."); + if((iPeripherals & 0xEE) != 0) + IPBinInformation.AppendFormat("Game supports unknown peripherals mask {0:X2}", iPeripherals & 0xEE); - if((iPeripherals & 0x00800000) == 0x00800000) - IPBinInformation.AppendLine("Game requires expanded analog horizontal controller."); + return IPBinInformation.ToString(); + } - if((iPeripherals & 0x01000000) == 0x01000000) - IPBinInformation.AppendLine("Game requires expanded analog vertical controller."); - - if((iPeripherals & 0x02000000) == 0x02000000) - IPBinInformation.AppendLine("Game supports Gun."); - - if((iPeripherals & 0x04000000) == 0x04000000) - IPBinInformation.AppendLine("Game supports Keyboard."); - - if((iPeripherals & 0x08000000) == 0x08000000) - IPBinInformation.AppendLine("Game supports Mouse."); - - if((iPeripherals & 0xEE) != 0) - IPBinInformation.AppendFormat("Game supports unknown peripherals mask {0:X2}", iPeripherals & 0xEE); - - return IPBinInformation.ToString(); - } - - /// SEGA IP.BIN format for Dreamcast - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct IPBin - { - /// Must be "SEGA SEGAKATANA " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] SegaHardwareID; - /// 0x010, "SEGA ENTERPRISES" - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] maker_id; - /// 0x020, CRC of product_no and product_version - public uint dreamcast_crc; - /// 0x024, " " - public byte spare_space1; - /// 0x025, "GD-ROM" - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] dreamcast_media; - /// 0x02B, Disc number - public byte disc_no; - /// 0x02C, '/' - public byte disc_no_separator; - /// 0x02D, Total number of discs - public byte disc_total_nos; - /// 0x02E, " " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] spare_space2; - /// 0x030, Region codes, space-filled - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] region_codes; - /// 0x038, Supported peripherals, bitwise - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] - public byte[] peripherals; - /// 0x03F, ' ' - public byte spare_space3; - /// 0x040, Product number - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public byte[] product_no; - /// 0x04A, Product version - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] product_version; - /// 0x050, YYYYMMDD - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] release_date; - /// 0x058, " " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] spare_space4; - /// 0x060, Usually "1ST_READ.BIN" or "0WINCE.BIN " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] - public byte[] boot_filename; - /// 0x06C, " " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public byte[] spare_space5; - /// 0x070, Game producer, space-filled - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] producer; - /// 0x080, Game name, space-filled - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public byte[] product_name; - } + /// SEGA IP.BIN format for Dreamcast + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IPBin + { + /// Must be "SEGA SEGAKATANA " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, "SEGA ENTERPRISES" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] maker_id; + /// 0x020, CRC of product_no and product_version + public uint dreamcast_crc; + /// 0x024, " " + public byte spare_space1; + /// 0x025, "GD-ROM" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] dreamcast_media; + /// 0x02B, Disc number + public byte disc_no; + /// 0x02C, '/' + public byte disc_no_separator; + /// 0x02D, Total number of discs + public byte disc_total_nos; + /// 0x02E, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] spare_space2; + /// 0x030, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] region_codes; + /// 0x038, Supported peripherals, bitwise + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public byte[] peripherals; + /// 0x03F, ' ' + public byte spare_space3; + /// 0x040, Product number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] product_no; + /// 0x04A, Product version + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] product_version; + /// 0x050, YYYYMMDD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x058, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] spare_space4; + /// 0x060, Usually "1ST_READ.BIN" or "0WINCE.BIN " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] boot_filename; + /// 0x06C, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] spare_space5; + /// 0x070, Game producer, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] producer; + /// 0x080, Game name, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public byte[] product_name; } } \ No newline at end of file diff --git a/Sega/Saturn.cs b/Sega/Saturn.cs index d5462c4..a608a22 100644 --- a/Sega/Saturn.cs +++ b/Sega/Saturn.cs @@ -38,208 +38,207 @@ using System.Text; using Aaru.Console; using Marshal = Aaru.Helpers.Marshal; -namespace Aaru.Decoders.Sega +namespace Aaru.Decoders.Sega; + +/// Represents the IP.BIN from a SEGA Saturn +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] +public static class Saturn { - /// Represents the IP.BIN from a SEGA Saturn - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] - public static class Saturn + /// Decodes an IP.BIN sector in Saturn format + /// IP.BIN sector + /// Decoded IP.BIN + public static IPBin? DecodeIPBin(byte[] ipbin_sector) { - /// Decodes an IP.BIN sector in Saturn format - /// IP.BIN sector - /// Decoded IP.BIN - public static IPBin? DecodeIPBin(byte[] ipbin_sector) - { - if(ipbin_sector == null) - return null; + if(ipbin_sector == null) + return null; - if(ipbin_sector.Length < 512) - return null; + if(ipbin_sector.Length < 512) + return null; - IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); + IPBin ipbin = Marshal.ByteArrayToStructureLittleEndian(ipbin_sector); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.maker_id = \"{0}\"", - Encoding.ASCII.GetString(ipbin.maker_id)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.maker_id = \"{0}\"", + Encoding.ASCII.GetString(ipbin.maker_id)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.product_no = \"{0}\"", - Encoding.ASCII.GetString(ipbin.product_no)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.product_no = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_no)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.product_version = \"{0}\"", - Encoding.ASCII.GetString(ipbin.product_version)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.product_version = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_version)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.release_datedate = \"{0}\"", - Encoding.ASCII.GetString(ipbin.release_date)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.release_datedate = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.saturn_media = \"{0}\"", - Encoding.ASCII.GetString(ipbin.saturn_media)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.saturn_media = \"{0}\"", + Encoding.ASCII.GetString(ipbin.saturn_media)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.disc_no = {0}", (char)ipbin.disc_no); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.disc_no = {0}", (char)ipbin.disc_no); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.disc_no_separator = \"{0}\"", - (char)ipbin.disc_no_separator); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.disc_no_separator = \"{0}\"", + (char)ipbin.disc_no_separator); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.disc_total_nos = {0}", - (char)ipbin.disc_total_nos); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.disc_total_nos = {0}", + (char)ipbin.disc_total_nos); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.release_date = \"{0}\"", - Encoding.ASCII.GetString(ipbin.release_date)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.release_date = \"{0}\"", + Encoding.ASCII.GetString(ipbin.release_date)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.spare_space1 = \"{0}\"", - Encoding.ASCII.GetString(ipbin.spare_space1)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.spare_space1 = \"{0}\"", + Encoding.ASCII.GetString(ipbin.spare_space1)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.region_codes = \"{0}\"", - Encoding.ASCII.GetString(ipbin.region_codes)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.region_codes = \"{0}\"", + Encoding.ASCII.GetString(ipbin.region_codes)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.peripherals = \"{0}\"", - Encoding.ASCII.GetString(ipbin.peripherals)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.peripherals = \"{0}\"", + Encoding.ASCII.GetString(ipbin.peripherals)); - AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.product_name = \"{0}\"", - Encoding.ASCII.GetString(ipbin.product_name)); + AaruConsole.DebugWriteLine("Saturn IP.BIN Decoder", "saturn_ipbin.product_name = \"{0}\"", + Encoding.ASCII.GetString(ipbin.product_name)); - return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGASATURN " ? ipbin : (IPBin?)null; - } + return Encoding.ASCII.GetString(ipbin.SegaHardwareID) == "SEGA SEGASATURN " ? ipbin : (IPBin?)null; + } - /// Pretty prints a decoded IP.BIN in Saturn format - /// Decoded IP.BIN - /// Description of the IP.BIN contents - public static string Prettify(IPBin? decoded) - { - if(decoded == null) - return null; + /// Pretty prints a decoded IP.BIN in Saturn format + /// Decoded IP.BIN + /// Description of the IP.BIN contents + public static string Prettify(IPBin? decoded) + { + if(decoded == null) + return null; - IPBin ipbin = decoded.Value; + IPBin ipbin = decoded.Value; - var IPBinInformation = new StringBuilder(); + var IPBinInformation = new StringBuilder(); - IPBinInformation.AppendLine("--------------------------------"); - IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:"); - IPBinInformation.AppendLine("--------------------------------"); + IPBinInformation.AppendLine("--------------------------------"); + IPBinInformation.AppendLine("SEGA IP.BIN INFORMATION:"); + IPBinInformation.AppendLine("--------------------------------"); - // Decoding all data - DateTime ipbindate; - CultureInfo provider = CultureInfo.InvariantCulture; - ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "yyyyMMdd", provider); + // Decoding all data + DateTime ipbindate; + CultureInfo provider = CultureInfo.InvariantCulture; + ipbindate = DateTime.ParseExact(Encoding.ASCII.GetString(ipbin.release_date), "yyyyMMdd", provider); - IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(ipbin.product_name)). - AppendLine(); + IPBinInformation.AppendFormat("Product name: {0}", Encoding.ASCII.GetString(ipbin.product_name)). + AppendLine(); - IPBinInformation.AppendFormat("Product number: {0}", Encoding.ASCII.GetString(ipbin.product_no)). - AppendLine(); + IPBinInformation.AppendFormat("Product number: {0}", Encoding.ASCII.GetString(ipbin.product_no)). + AppendLine(); - IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(ipbin.product_version)). - AppendLine(); + IPBinInformation.AppendFormat("Product version: {0}", Encoding.ASCII.GetString(ipbin.product_version)). + AppendLine(); - IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); + IPBinInformation.AppendFormat("Release date: {0}", ipbindate).AppendLine(); - IPBinInformation.AppendFormat("Disc number {0} of {1}", (char)ipbin.disc_no, (char)ipbin.disc_total_nos). - AppendLine(); + IPBinInformation.AppendFormat("Disc number {0} of {1}", (char)ipbin.disc_no, (char)ipbin.disc_total_nos). + AppendLine(); - IPBinInformation.AppendFormat("Peripherals:").AppendLine(); + IPBinInformation.AppendFormat("Peripherals:").AppendLine(); - foreach(byte peripheral in ipbin.peripherals) - switch((char)peripheral) - { - case 'A': - IPBinInformation.AppendLine("Game supports analog controller."); + foreach(byte peripheral in ipbin.peripherals) + switch((char)peripheral) + { + case 'A': + IPBinInformation.AppendLine("Game supports analog controller."); - break; - case 'J': - IPBinInformation.AppendLine("Game supports JoyPad."); + break; + case 'J': + IPBinInformation.AppendLine("Game supports JoyPad."); - break; - case 'K': - IPBinInformation.AppendLine("Game supports keyboard."); + break; + case 'K': + IPBinInformation.AppendLine("Game supports keyboard."); - break; - case 'M': - IPBinInformation.AppendLine("Game supports mouse."); + break; + case 'M': + IPBinInformation.AppendLine("Game supports mouse."); - break; - case 'S': - IPBinInformation.AppendLine("Game supports analog steering controller."); + break; + case 'S': + IPBinInformation.AppendLine("Game supports analog steering controller."); - break; - case 'T': - IPBinInformation.AppendLine("Game supports multitap."); + break; + case 'T': + IPBinInformation.AppendLine("Game supports multitap."); - break; - case ' ': break; - default: - IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral).AppendLine(); + break; + case ' ': break; + default: + IPBinInformation.AppendFormat("Game supports unknown peripheral {0}.", peripheral).AppendLine(); - break; - } + break; + } - IPBinInformation.AppendLine("Regions supported:"); + IPBinInformation.AppendLine("Regions supported:"); - foreach(byte region in ipbin.region_codes) - switch((char)region) - { - case 'J': - IPBinInformation.AppendLine("Japanese NTSC."); + foreach(byte region in ipbin.region_codes) + switch((char)region) + { + case 'J': + IPBinInformation.AppendLine("Japanese NTSC."); - break; - case 'U': - IPBinInformation.AppendLine("North America NTSC."); + break; + case 'U': + IPBinInformation.AppendLine("North America NTSC."); - break; - case 'E': - IPBinInformation.AppendLine("Europe PAL."); + break; + case 'E': + IPBinInformation.AppendLine("Europe PAL."); - break; - case 'T': - IPBinInformation.AppendLine("Asia NTSC."); + break; + case 'T': + IPBinInformation.AppendLine("Asia NTSC."); - break; - case ' ': break; - default: - IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine(); + break; + case ' ': break; + default: + IPBinInformation.AppendFormat("Game supports unknown region {0}.", region).AppendLine(); - break; - } + break; + } - return IPBinInformation.ToString(); - } + return IPBinInformation.ToString(); + } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct IPBin - { - /// Must be "SEGA SEGASATURN " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] SegaHardwareID; - /// 0x010, "SEGA ENTERPRISES" - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] maker_id; - /// 0x020, Product number - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public byte[] product_no; - /// 0x02A, Product version - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] product_version; - /// 0x030, YYYYMMDD - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] release_date; - /// 0x038, "CD-" - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] saturn_media; - /// 0x03B, Disc number - public byte disc_no; - /// // 0x03C, '/' - public byte disc_no_separator; - /// // 0x03D, Total number of discs - public byte disc_total_nos; - /// 0x03E, " " - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] spare_space1; - /// 0x040, Region codes, space-filled - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] region_codes; - /// 0x050, Supported peripherals, see above - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] peripherals; - /// 0x060, Game name, space-filled - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)] - public byte[] product_name; - } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct IPBin + { + /// Must be "SEGA SEGASATURN " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] SegaHardwareID; + /// 0x010, "SEGA ENTERPRISES" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] maker_id; + /// 0x020, Product number + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] product_no; + /// 0x02A, Product version + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] product_version; + /// 0x030, YYYYMMDD + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] release_date; + /// 0x038, "CD-" + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] saturn_media; + /// 0x03B, Disc number + public byte disc_no; + /// // 0x03C, '/' + public byte disc_no_separator; + /// // 0x03D, Total number of discs + public byte disc_total_nos; + /// 0x03E, " " + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] spare_space1; + /// 0x040, Region codes, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] region_codes; + /// 0x050, Supported peripherals, see above + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] peripherals; + /// 0x060, Game name, space-filled + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)] + public byte[] product_name; } } \ No newline at end of file diff --git a/Xbox/DMI.cs b/Xbox/DMI.cs index 269953b..de10d3e 100644 --- a/Xbox/DMI.cs +++ b/Xbox/DMI.cs @@ -35,249 +35,248 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; -namespace Aaru.Decoders.Xbox +namespace Aaru.Decoders.Xbox; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class DMI { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class DMI + public static bool IsXbox(byte[] dmi) { - public static bool IsXbox(byte[] dmi) - { - if(dmi?.Length != 2052) + if(dmi?.Length != 2052) + return false; + + // Version is 1 + if(BitConverter.ToUInt32(dmi, 4) != 1) + return false; + + // Catalogue number is two letters, five numbers, one letter + for(int i = 12; i < 14; i++) + if(dmi[i] < 0x41 || + dmi[i] > 0x5A) return false; - // Version is 1 - if(BitConverter.ToUInt32(dmi, 4) != 1) + for(int i = 14; i < 19; i++) + if(dmi[i] < 0x30 || + dmi[i] > 0x39) return false; - // Catalogue number is two letters, five numbers, one letter - for(int i = 12; i < 14; i++) - if(dmi[i] < 0x41 || - dmi[i] > 0x5A) - return false; + if(dmi[19] < 0x41 || + dmi[19] > 0x5A) + return false; - for(int i = 14; i < 19; i++) - if(dmi[i] < 0x30 || - dmi[i] > 0x39) - return false; + long timestamp = BitConverter.ToInt64(dmi, 20); - if(dmi[19] < 0x41 || - dmi[19] > 0x5A) - return false; + // Game cannot exist before the Xbox + return timestamp >= 0x1BD164833DFC000; + } - long timestamp = BitConverter.ToInt64(dmi, 20); + public static bool IsXbox360(byte[] dmi) + { + if(dmi?.Length != 2052) + return false; - // Game cannot exist before the Xbox - return timestamp >= 0x1BD164833DFC000; - } + uint signature = BitConverter.ToUInt32(dmi, 0x7EC); - public static bool IsXbox360(byte[] dmi) + // "XBOX" swapped as .NET is little endian + return signature == 0x584F4258; + } + + public static XboxDMI? DecodeXbox(byte[] response) + { + bool isXbox = IsXbox(response); + + if(!isXbox) + return null; + + var dmi = new XboxDMI { - if(dmi?.Length != 2052) - return false; + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + Version = BitConverter.ToUInt32(response, 4), + Timestamp = BitConverter.ToInt64(response, 20) + }; - uint signature = BitConverter.ToUInt32(dmi, 0x7EC); + byte[] tmp = new byte[8]; + Array.Copy(response, 12, tmp, 0, 8); + dmi.CatalogNumber = StringHandlers.CToString(tmp); - // "XBOX" swapped as .NET is little endian - return signature == 0x584F4258; - } + return dmi; + } - public static XboxDMI? DecodeXbox(byte[] response) + public static Xbox360DMI? DecodeXbox360(byte[] response) + { + bool isX360 = IsXbox360(response); + + if(!isX360) + return null; + + var dmi = new Xbox360DMI { - bool isXbox = IsXbox(response); + DataLength = (ushort)((response[0] << 8) + response[1]), + Reserved1 = response[2], + Reserved2 = response[3], + Version = BitConverter.ToUInt32(response, 4), + Timestamp = BitConverter.ToInt64(response, 20), + MediaID = new byte[16] + }; - if(!isXbox) - return null; + Array.Copy(response, 36, dmi.MediaID, 0, 16); + byte[] tmp = new byte[16]; + Array.Copy(response, 68, tmp, 0, 16); + dmi.CatalogNumber = StringHandlers.CToString(tmp); - var dmi = new XboxDMI - { - DataLength = (ushort)((response[0] << 8) + response[1]), - Reserved1 = response[2], - Reserved2 = response[3], - Version = BitConverter.ToUInt32(response, 4), - Timestamp = BitConverter.ToInt64(response, 20) - }; + return dmi.CatalogNumber == null || dmi.CatalogNumber.Length < 13 ? (Xbox360DMI?)null : dmi; + } - byte[] tmp = new byte[8]; - Array.Copy(response, 12, tmp, 0, 8); - dmi.CatalogNumber = StringHandlers.CToString(tmp); + public static string PrettifyXbox(XboxDMI? dmi) + { + if(dmi == null) + return null; - return dmi; - } + XboxDMI decoded = dmi.Value; + var sb = new StringBuilder(); - public static Xbox360DMI? DecodeXbox360(byte[] response) + sb.Append("Catalogue number: "); + + for(int i = 0; i < 2; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + sb.Append("-"); + + for(int i = 2; i < 7; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + sb.Append("-"); + sb.AppendFormat("{0}", decoded.CatalogNumber[7]); + sb.AppendLine(); + + sb.AppendFormat("Timestamp: {0}", DateTime.FromFileTimeUtc(decoded.Timestamp)).AppendLine(); + + return sb.ToString(); + } + + public static string PrettifyXbox360(Xbox360DMI? dmi) + { + if(dmi == null) + return null; + + Xbox360DMI decoded = dmi.Value; + var sb = new StringBuilder(); + + sb.Append("Catalogue number: "); + + for(int i = 0; i < 2; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + sb.Append("-"); + + for(int i = 2; i < 6; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + sb.Append("-"); + + for(int i = 6; i < 8; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + sb.Append("-"); + + switch(decoded.CatalogNumber.Length) { - bool isX360 = IsXbox360(response); + case 13: + for(int i = 8; i < 10; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - if(!isX360) - return null; + sb.Append("-"); - var dmi = new Xbox360DMI - { - DataLength = (ushort)((response[0] << 8) + response[1]), - Reserved1 = response[2], - Reserved2 = response[3], - Version = BitConverter.ToUInt32(response, 4), - Timestamp = BitConverter.ToInt64(response, 20), - MediaID = new byte[16] - }; + for(int i = 10; i < 13; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - Array.Copy(response, 36, dmi.MediaID, 0, 16); - byte[] tmp = new byte[16]; - Array.Copy(response, 68, tmp, 0, 16); - dmi.CatalogNumber = StringHandlers.CToString(tmp); + break; + case 14: + for(int i = 8; i < 11; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - return dmi.CatalogNumber == null || dmi.CatalogNumber.Length < 13 ? (Xbox360DMI?)null : dmi; + sb.Append("-"); + + for(int i = 11; i < 14; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + break; + default: + for(int i = 8; i < decoded.CatalogNumber.Length - 3; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + sb.Append("-"); + + for(int i = decoded.CatalogNumber.Length - 3; i < decoded.CatalogNumber.Length; i++) + sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + + break; } - public static string PrettifyXbox(XboxDMI? dmi) - { - if(dmi == null) - return null; + sb.AppendLine(); - XboxDMI decoded = dmi.Value; - var sb = new StringBuilder(); + sb.Append("Media ID: "); - sb.Append("Catalogue number: "); + for(int i = 0; i < 12; i++) + sb.AppendFormat("{0:X2}", decoded.MediaID[i]); - for(int i = 0; i < 2; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + sb.Append("-"); - sb.Append("-"); + for(int i = 12; i < 16; i++) + sb.AppendFormat("{0:X2}", decoded.MediaID[i]); - for(int i = 2; i < 7; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + sb.AppendLine(); - sb.Append("-"); - sb.AppendFormat("{0}", decoded.CatalogNumber[7]); - sb.AppendLine(); + sb.AppendFormat("Timestamp: {0}", DateTime.FromFileTimeUtc(decoded.Timestamp)).AppendLine(); - sb.AppendFormat("Timestamp: {0}", DateTime.FromFileTimeUtc(decoded.Timestamp)).AppendLine(); + return sb.ToString(); + } - return sb.ToString(); - } + public static string PrettifyXbox(byte[] response) => PrettifyXbox(DecodeXbox(response)); - public static string PrettifyXbox360(Xbox360DMI? dmi) - { - if(dmi == null) - return null; + public static string PrettifyXbox360(byte[] response) => PrettifyXbox360(DecodeXbox360(response)); - Xbox360DMI decoded = dmi.Value; - var sb = new StringBuilder(); + public struct XboxDMI + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; - sb.Append("Catalogue number: "); + /// Bytes 4 to 7 0x01 in XGD + public uint Version; - for(int i = 0; i < 2; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + /// Bytes 12 to 16 Catalogue number in XX-XXXXX-X + public string CatalogNumber; - sb.Append("-"); + /// Bytes 20 to 27 DMI timestamp + public long Timestamp; + } - for(int i = 2; i < 6; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + public struct Xbox360DMI + { + /// Bytes 0 to 1 Data length + public ushort DataLength; + /// Byte 2 Reserved + public byte Reserved1; + /// Byte 3 Reserved + public byte Reserved2; - sb.Append("-"); + /// Bytes 4 to 7 0x02 in XGD2 and XGD3 + public uint Version; - for(int i = 6; i < 8; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); + /// Bytes 20 to 27 DMI timestamp + public long Timestamp; - sb.Append("-"); + /// Bytes 36 to 51 Media ID in hex XXXXXXXXXXXX-XXXXXXXX + public byte[] MediaID; - switch(decoded.CatalogNumber.Length) - { - case 13: - for(int i = 8; i < 10; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - - sb.Append("-"); - - for(int i = 10; i < 13; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - - break; - case 14: - for(int i = 8; i < 11; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - - sb.Append("-"); - - for(int i = 11; i < 14; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - - break; - default: - for(int i = 8; i < decoded.CatalogNumber.Length - 3; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - - sb.Append("-"); - - for(int i = decoded.CatalogNumber.Length - 3; i < decoded.CatalogNumber.Length; i++) - sb.AppendFormat("{0}", decoded.CatalogNumber[i]); - - break; - } - - sb.AppendLine(); - - sb.Append("Media ID: "); - - for(int i = 0; i < 12; i++) - sb.AppendFormat("{0:X2}", decoded.MediaID[i]); - - sb.Append("-"); - - for(int i = 12; i < 16; i++) - sb.AppendFormat("{0:X2}", decoded.MediaID[i]); - - sb.AppendLine(); - - sb.AppendFormat("Timestamp: {0}", DateTime.FromFileTimeUtc(decoded.Timestamp)).AppendLine(); - - return sb.ToString(); - } - - public static string PrettifyXbox(byte[] response) => PrettifyXbox(DecodeXbox(response)); - - public static string PrettifyXbox360(byte[] response) => PrettifyXbox360(DecodeXbox360(response)); - - public struct XboxDMI - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - - /// Bytes 4 to 7 0x01 in XGD - public uint Version; - - /// Bytes 12 to 16 Catalogue number in XX-XXXXX-X - public string CatalogNumber; - - /// Bytes 20 to 27 DMI timestamp - public long Timestamp; - } - - public struct Xbox360DMI - { - /// Bytes 0 to 1 Data length - public ushort DataLength; - /// Byte 2 Reserved - public byte Reserved1; - /// Byte 3 Reserved - public byte Reserved2; - - /// Bytes 4 to 7 0x02 in XGD2 and XGD3 - public uint Version; - - /// Bytes 20 to 27 DMI timestamp - public long Timestamp; - - /// Bytes 36 to 51 Media ID in hex XXXXXXXXXXXX-XXXXXXXX - public byte[] MediaID; - - /// Bytes 68 to 83 Catalogue number in XX-XXXX-XX-XXY-XXX, Y not always exists - public string CatalogNumber; - } + /// Bytes 68 to 83 Catalogue number in XX-XXXX-XX-XXY-XXX, Y not always exists + public string CatalogNumber; } } \ No newline at end of file diff --git a/Xbox/SS.cs b/Xbox/SS.cs index 5067491..01c6a5b 100644 --- a/Xbox/SS.cs +++ b/Xbox/SS.cs @@ -35,369 +35,368 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Decoders.DVD; -namespace Aaru.Decoders.Xbox +namespace Aaru.Decoders.Xbox; + +[SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), + SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] +public static class SS { - [SuppressMessage("ReSharper", "InconsistentNaming"), SuppressMessage("ReSharper", "MemberCanBeInternal"), - SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "NotAccessedField.Global")] - public static class SS + public static SecuritySector? Decode(byte[] response) { - public static SecuritySector? Decode(byte[] response) + if(response == null) + return null; + + if(response.Length < 2048) + return null; + + var ss = new SecuritySector { - if(response == null) - return null; + DiskCategory = (DiskCategory)((response[0] & 0xF0) >> 4), + PartVersion = (byte)(response[0] & 0x0F), + DiscSize = (DVDSize)((response[1] & 0xF0) >> 4), + MaximumRate = (MaximumRateField)(response[1] & 0x0F), + Reserved3 = (response[2] & 0x80) == 0x80, + Layers = (byte)((response[2] & 0x60) >> 5), + TrackPath = (response[2] & 0x08) == 0x08, + LayerType = (LayerTypeFieldMask)(response[2] & 0x07), + LinearDensity = (LinearDensityField)((response[3] & 0xF0) >> 4), + TrackDensity = (TrackDensityField)(response[3] & 0x0F), + DataAreaStartPSN = (uint)((response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7]), + DataAreaEndPSN = (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), + Layer0EndPSN = (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]), + Unknown1 = response[27], + Unknown2 = new byte[28], + Unknown3 = new byte[436], + Unknown4 = new byte[4], + Unknown5 = new byte[43], + ChallengeTableVersion = response[768], + NoChallengeEntries = response[769], + ChallengeEntries = new ChallengeEntry[23], + Unknown6 = response[1023], + Unknown7 = new byte[48], + Unknown8 = new byte[16], + Unknown9 = new byte[16], + Unknown10 = new byte[303], + Unknown11 = new byte[104], + Extents = new SecuritySectorExtent[23], + ExtentsCopy = new SecuritySectorExtent[23] + }; - if(response.Length < 2048) - return null; + Array.Copy(response, 256, ss.Unknown2, 0, 28); + Array.Copy(response, 284, ss.Unknown3, 0, 436); + Array.Copy(response, 720, ss.Unknown4, 0, 4); + Array.Copy(response, 724, ss.Unknown5, 0, 43); - var ss = new SecuritySector + for(int i = 0; i < 23; i++) + ss.ChallengeEntries[i] = new ChallengeEntry { - DiskCategory = (DiskCategory)((response[0] & 0xF0) >> 4), - PartVersion = (byte)(response[0] & 0x0F), - DiscSize = (DVDSize)((response[1] & 0xF0) >> 4), - MaximumRate = (MaximumRateField)(response[1] & 0x0F), - Reserved3 = (response[2] & 0x80) == 0x80, - Layers = (byte)((response[2] & 0x60) >> 5), - TrackPath = (response[2] & 0x08) == 0x08, - LayerType = (LayerTypeFieldMask)(response[2] & 0x07), - LinearDensity = (LinearDensityField)((response[3] & 0xF0) >> 4), - TrackDensity = (TrackDensityField)(response[3] & 0x0F), - DataAreaStartPSN = (uint)((response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7]), - DataAreaEndPSN = (uint)((response[8] << 24) + (response[9] << 16) + (response[10] << 8) + response[11]), - Layer0EndPSN = (uint)((response[12] << 24) + (response[13] << 16) + (response[14] << 8) + response[15]), - Unknown1 = response[27], - Unknown2 = new byte[28], - Unknown3 = new byte[436], - Unknown4 = new byte[4], - Unknown5 = new byte[43], - ChallengeTableVersion = response[768], - NoChallengeEntries = response[769], - ChallengeEntries = new ChallengeEntry[23], - Unknown6 = response[1023], - Unknown7 = new byte[48], - Unknown8 = new byte[16], - Unknown9 = new byte[16], - Unknown10 = new byte[303], - Unknown11 = new byte[104], - Extents = new SecuritySectorExtent[23], - ExtentsCopy = new SecuritySectorExtent[23] + Level = response[770 + (i * 11) + 0], + ChallengeId = response[770 + (i * 11) + 1], + ChallengeValue = (uint)((response[770 + (i * 11) + 2] << 24) + + (response[770 + (i * 11) + 3] << 16) + (response[770 + (i * 11) + 4] << 8) + + response[770 + (i * 11) + 5]), + ResponseModifier = response[770 + (i * 11) + 6], + ResponseValue = (uint)((response[770 + (i * 11) + 7] << 24) + (response[770 + (i * 11) + 8] << 16) + + (response[770 + (i * 11) + 9] << 8) + response[770 + (i * 11) + 10]) }; - Array.Copy(response, 256, ss.Unknown2, 0, 28); - Array.Copy(response, 284, ss.Unknown3, 0, 436); - Array.Copy(response, 720, ss.Unknown4, 0, 4); - Array.Copy(response, 724, ss.Unknown5, 0, 43); + Array.Copy(response, 1052, ss.Unknown7, 0, 48); + Array.Copy(response, 1120, ss.Unknown8, 0, 16); + Array.Copy(response, 1180, ss.Unknown9, 0, 16); + Array.Copy(response, 1208, ss.Unknown10, 0, 303); + Array.Copy(response, 1528, ss.Unknown11, 0, 104); - for(int i = 0; i < 23; i++) - ss.ChallengeEntries[i] = new ChallengeEntry - { - Level = response[770 + (i * 11) + 0], - ChallengeId = response[770 + (i * 11) + 1], - ChallengeValue = (uint)((response[770 + (i * 11) + 2] << 24) + - (response[770 + (i * 11) + 3] << 16) + (response[770 + (i * 11) + 4] << 8) + - response[770 + (i * 11) + 5]), - ResponseModifier = response[770 + (i * 11) + 6], - ResponseValue = (uint)((response[770 + (i * 11) + 7] << 24) + (response[770 + (i * 11) + 8] << 16) + - (response[770 + (i * 11) + 9] << 8) + response[770 + (i * 11) + 10]) - }; + for(int i = 0; i < 23; i++) + ss.Extents[i] = new SecuritySectorExtent + { + Unknown = (uint)((response[1633 + (i * 9) + 0] << 16) + (response[1633 + (i * 9) + 1] << 8) + + response[1633 + (i * 9) + 2]), + StartPSN = (uint)((response[1633 + (i * 9) + 3] << 16) + (response[1633 + (i * 9) + 4] << 8) + + response[1633 + (i * 9) + 5]), + EndPSN = (uint)((response[1633 + (i * 9) + 6] << 16) + (response[1633 + (i * 9) + 7] << 8) + + response[1633 + (i * 9) + 8]) + }; - Array.Copy(response, 1052, ss.Unknown7, 0, 48); - Array.Copy(response, 1120, ss.Unknown8, 0, 16); - Array.Copy(response, 1180, ss.Unknown9, 0, 16); - Array.Copy(response, 1208, ss.Unknown10, 0, 303); - Array.Copy(response, 1528, ss.Unknown11, 0, 104); + for(int i = 0; i < 23; i++) + ss.ExtentsCopy[i] = new SecuritySectorExtent + { + Unknown = (uint)((response[1840 + (i * 9) + 0] << 16) + (response[1840 + (i * 9) + 1] << 8) + + response[1840 + (i * 9) + 2]), + StartPSN = (uint)((response[1840 + (i * 9) + 3] << 16) + (response[1840 + (i * 9) + 4] << 8) + + response[1840 + (i * 9) + 5]), + EndPSN = (uint)((response[1840 + (i * 9) + 6] << 16) + (response[1840 + (i * 9) + 7] << 8) + + response[1840 + (i * 9) + 8]) + }; - for(int i = 0; i < 23; i++) - ss.Extents[i] = new SecuritySectorExtent - { - Unknown = (uint)((response[1633 + (i * 9) + 0] << 16) + (response[1633 + (i * 9) + 1] << 8) + - response[1633 + (i * 9) + 2]), - StartPSN = (uint)((response[1633 + (i * 9) + 3] << 16) + (response[1633 + (i * 9) + 4] << 8) + - response[1633 + (i * 9) + 5]), - EndPSN = (uint)((response[1633 + (i * 9) + 6] << 16) + (response[1633 + (i * 9) + 7] << 8) + - response[1633 + (i * 9) + 8]) - }; + return ss; + } - for(int i = 0; i < 23; i++) - ss.ExtentsCopy[i] = new SecuritySectorExtent - { - Unknown = (uint)((response[1840 + (i * 9) + 0] << 16) + (response[1840 + (i * 9) + 1] << 8) + - response[1840 + (i * 9) + 2]), - StartPSN = (uint)((response[1840 + (i * 9) + 3] << 16) + (response[1840 + (i * 9) + 4] << 8) + - response[1840 + (i * 9) + 5]), - EndPSN = (uint)((response[1840 + (i * 9) + 6] << 16) + (response[1840 + (i * 9) + 7] << 8) + - response[1840 + (i * 9) + 8]) - }; + public static string Prettify(SecuritySector? ss) + { + if(ss == null) + return null; - return ss; + SecuritySector decoded = ss.Value; + var sb = new StringBuilder(); + + string sizeString; + + switch(decoded.DiscSize) + { + case DVDSize.Eighty: + sizeString = "80mm"; + + break; + case DVDSize.OneTwenty: + sizeString = "120mm"; + + break; + default: + sizeString = $"unknown size identifier {decoded.DiscSize}"; + + break; } - public static string Prettify(SecuritySector? ss) + const string categorySentence = "Disc is a {0} {1} version {2}"; + + switch(decoded.DiskCategory) { - if(ss == null) - return null; + case DiskCategory.DVDPRWDL: + sb.AppendFormat(categorySentence, sizeString, "Xbox Game Disc", decoded.PartVersion).AppendLine(); - SecuritySector decoded = ss.Value; - var sb = new StringBuilder(); + break; + case DiskCategory.DVDPRDL: + sb.AppendFormat(categorySentence, sizeString, "Xbox 360 Game Disc", decoded.PartVersion). + AppendLine(); - string sizeString; + break; + default: + sb.AppendFormat(categorySentence, sizeString, "unknown disc type", decoded.PartVersion). + AppendLine(); - switch(decoded.DiscSize) + break; + } + + switch(decoded.MaximumRate) + { + case MaximumRateField.TwoMbps: + sb.AppendLine("Disc maximum transfer rate is 2,52 Mbit/sec."); + + break; + case MaximumRateField.FiveMbps: + sb.AppendLine("Disc maximum transfer rate is 5,04 Mbit/sec."); + + break; + case MaximumRateField.TenMbps: + sb.AppendLine("Disc maximum transfer rate is 10,08 Mbit/sec."); + + break; + case MaximumRateField.TwentyMbps: + sb.AppendLine("Disc maximum transfer rate is 20,16 Mbit/sec."); + + break; + case MaximumRateField.ThirtyMbps: + sb.AppendLine("Disc maximum transfer rate is 30,24 Mbit/sec."); + + break; + case MaximumRateField.Unspecified: + sb.AppendLine("Disc maximum transfer rate is unspecified."); + + break; + default: + sb.AppendFormat("Disc maximum transfer rate is specified by unknown key {0}", decoded.MaximumRate). + AppendLine(); + + break; + } + + sb.AppendFormat("Disc has {0} layers", decoded.Layers + 1).AppendLine(); + + if(decoded.TrackPath && + decoded.Layers == 1) + sb.AppendLine("Layers are in parallel track path"); + else if(!decoded.TrackPath && + decoded.Layers == 1) + sb.AppendLine("Layers are in opposite track path"); + + switch(decoded.LinearDensity) + { + case LinearDensityField.TwoSix: + sb.AppendLine("Pitch size is 0,267 μm/bit"); + + break; + case LinearDensityField.TwoNine: + sb.AppendLine("Pitch size is 0,147 μm/bit"); + + break; + case LinearDensityField.FourZero: + sb.AppendLine("Pitch size is between 0,409 μm/bit and 0,435 μm/bit"); + + break; + case LinearDensityField.TwoEight: + sb.AppendLine("Pitch size is between 0,140 μm/bit and 0,148 μm/bit"); + + break; + case LinearDensityField.OneFive: + sb.AppendLine("Pitch size is 0,153 μm/bit"); + + break; + case LinearDensityField.OneThree: + sb.AppendLine("Pitch size is between 0,130 μm/bit and 0,140 μm/bit"); + + break; + case LinearDensityField.ThreeFive: + sb.AppendLine("Pitch size is 0,353 μm/bit"); + + break; + default: + sb.AppendFormat("Unknown pitch size key {0}", decoded.LinearDensity).AppendLine(); + + break; + } + + switch(decoded.TrackDensity) + { + case TrackDensityField.Seven: + sb.AppendLine("Track size is 0,74 μm"); + + break; + case TrackDensityField.Eight: + sb.AppendLine("Track size is 0,80 μm"); + + break; + case TrackDensityField.Six: + sb.AppendLine("Track size is 0,615 μm"); + + break; + case TrackDensityField.Four: + sb.AppendLine("Track size is 0,40 μm"); + + break; + case TrackDensityField.Three: + sb.AppendLine("Track size is 0,34 μm"); + + break; + default: + sb.AppendFormat("Unknown track size key {0}", decoded.LinearDensity).AppendLine(); + + break; + } + + if(decoded.DataAreaStartPSN > 0) + if(decoded.DataAreaEndPSN > 0) { - case DVDSize.Eighty: - sizeString = "80mm"; + sb.AppendFormat("Data area starts at PSN {0:X}h", decoded.DataAreaStartPSN).AppendLine(); + sb.AppendFormat("Data area ends at PSN {0:X}h", decoded.DataAreaEndPSN).AppendLine(); - break; - case DVDSize.OneTwenty: - sizeString = "120mm"; - - break; - default: - sizeString = $"unknown size identifier {decoded.DiscSize}"; - - break; + if(decoded.Layers == 1 && + !decoded.TrackPath) + sb.AppendFormat("Layer 0 ends at PSN {0:X}h", decoded.Layer0EndPSN).AppendLine(); } - - const string categorySentence = "Disc is a {0} {1} version {2}"; - - switch(decoded.DiskCategory) - { - case DiskCategory.DVDPRWDL: - sb.AppendFormat(categorySentence, sizeString, "Xbox Game Disc", decoded.PartVersion).AppendLine(); - - break; - case DiskCategory.DVDPRDL: - sb.AppendFormat(categorySentence, sizeString, "Xbox 360 Game Disc", decoded.PartVersion). - AppendLine(); - - break; - default: - sb.AppendFormat(categorySentence, sizeString, "unknown disc type", decoded.PartVersion). - AppendLine(); - - break; - } - - switch(decoded.MaximumRate) - { - case MaximumRateField.TwoMbps: - sb.AppendLine("Disc maximum transfer rate is 2,52 Mbit/sec."); - - break; - case MaximumRateField.FiveMbps: - sb.AppendLine("Disc maximum transfer rate is 5,04 Mbit/sec."); - - break; - case MaximumRateField.TenMbps: - sb.AppendLine("Disc maximum transfer rate is 10,08 Mbit/sec."); - - break; - case MaximumRateField.TwentyMbps: - sb.AppendLine("Disc maximum transfer rate is 20,16 Mbit/sec."); - - break; - case MaximumRateField.ThirtyMbps: - sb.AppendLine("Disc maximum transfer rate is 30,24 Mbit/sec."); - - break; - case MaximumRateField.Unspecified: - sb.AppendLine("Disc maximum transfer rate is unspecified."); - - break; - default: - sb.AppendFormat("Disc maximum transfer rate is specified by unknown key {0}", decoded.MaximumRate). - AppendLine(); - - break; - } - - sb.AppendFormat("Disc has {0} layers", decoded.Layers + 1).AppendLine(); - - if(decoded.TrackPath && - decoded.Layers == 1) - sb.AppendLine("Layers are in parallel track path"); - else if(!decoded.TrackPath && - decoded.Layers == 1) - sb.AppendLine("Layers are in opposite track path"); - - switch(decoded.LinearDensity) - { - case LinearDensityField.TwoSix: - sb.AppendLine("Pitch size is 0,267 μm/bit"); - - break; - case LinearDensityField.TwoNine: - sb.AppendLine("Pitch size is 0,147 μm/bit"); - - break; - case LinearDensityField.FourZero: - sb.AppendLine("Pitch size is between 0,409 μm/bit and 0,435 μm/bit"); - - break; - case LinearDensityField.TwoEight: - sb.AppendLine("Pitch size is between 0,140 μm/bit and 0,148 μm/bit"); - - break; - case LinearDensityField.OneFive: - sb.AppendLine("Pitch size is 0,153 μm/bit"); - - break; - case LinearDensityField.OneThree: - sb.AppendLine("Pitch size is between 0,130 μm/bit and 0,140 μm/bit"); - - break; - case LinearDensityField.ThreeFive: - sb.AppendLine("Pitch size is 0,353 μm/bit"); - - break; - default: - sb.AppendFormat("Unknown pitch size key {0}", decoded.LinearDensity).AppendLine(); - - break; - } - - switch(decoded.TrackDensity) - { - case TrackDensityField.Seven: - sb.AppendLine("Track size is 0,74 μm"); - - break; - case TrackDensityField.Eight: - sb.AppendLine("Track size is 0,80 μm"); - - break; - case TrackDensityField.Six: - sb.AppendLine("Track size is 0,615 μm"); - - break; - case TrackDensityField.Four: - sb.AppendLine("Track size is 0,40 μm"); - - break; - case TrackDensityField.Three: - sb.AppendLine("Track size is 0,34 μm"); - - break; - default: - sb.AppendFormat("Unknown track size key {0}", decoded.LinearDensity).AppendLine(); - - break; - } - - if(decoded.DataAreaStartPSN > 0) - if(decoded.DataAreaEndPSN > 0) - { - sb.AppendFormat("Data area starts at PSN {0:X}h", decoded.DataAreaStartPSN).AppendLine(); - sb.AppendFormat("Data area ends at PSN {0:X}h", decoded.DataAreaEndPSN).AppendLine(); - - if(decoded.Layers == 1 && - !decoded.TrackPath) - sb.AppendFormat("Layer 0 ends at PSN {0:X}h", decoded.Layer0EndPSN).AppendLine(); - } - else - sb.AppendLine("Disc is empty"); else sb.AppendLine("Disc is empty"); + else + sb.AppendLine("Disc is empty"); - sb.AppendLine("Challenges:"); + sb.AppendLine("Challenges:"); - foreach(ChallengeEntry entry in decoded.ChallengeEntries) - { - sb.AppendFormat("\tChallenge ID: {0}", entry.ChallengeId).AppendLine(); - sb.AppendFormat("\tChallenge level: {0}", entry.Level).AppendLine(); - sb.AppendFormat("\tChallenge value: 0x{0:X8}", entry.ChallengeValue).AppendLine(); - sb.AppendFormat("\tResponse modifier: {0}", entry.ResponseModifier).AppendLine(); - sb.AppendFormat("\tResponse value: 0x{0:X8}", entry.ResponseValue).AppendLine(); - } - - for(int i = 0; i < 16; i++) - sb.AppendFormat("Extent starts at PSN {0:X6}h and ends at PSN {1:X6}h", decoded.Extents[i].StartPSN, - decoded.Extents[i].EndPSN).AppendLine(); - - return sb.ToString(); - } - - public static string Prettify(byte[] response) => Prettify(Decode(response)); - - public struct SecuritySector + foreach(ChallengeEntry entry in decoded.ChallengeEntries) { - /// Byte 0, bits 7 to 4 Disk category field - public DiskCategory DiskCategory; - /// Byte 0, bits 3 to 0 Media version - public byte PartVersion; - /// Byte 1, bits 7 to 4 120mm if 0, 80mm if 1. If UMD (60mm) 0 also. Reserved rest of values - public DVDSize DiscSize; - /// Byte 1, bits 3 to 0 Maximum data rate - public MaximumRateField MaximumRate; - /// Byte 2, bit 7 Reserved - public bool Reserved3; - /// Byte 2, bits 6 to 5 Number of layers - public byte Layers; - /// Byte 2, bit 4 Track path - public bool TrackPath; - /// Byte 2, bits 3 to 0 Layer type - public LayerTypeFieldMask LayerType; - /// Byte 3, bits 7 to 4 Linear density field - public LinearDensityField LinearDensity; - /// Byte 3, bits 3 to 0 Track density field - public TrackDensityField TrackDensity; - /// Bytes 4 to 7 PSN where Data Area starts - public uint DataAreaStartPSN; - /// Bytes 8 to 11 PSN where Data Area ends - public uint DataAreaEndPSN; - /// Bytes 12 to 15 PSN where Data Area ends in Layer 0 - public uint Layer0EndPSN; - - /// Byte 27 Always 0x06 on XGD3 - public byte Unknown1; - /// Bytes 256 to 283 Unknown, XGD2 and XGD3 - public byte[] Unknown2; - /// Bytes 284 to 719 Unknown, XGD3 - public byte[] Unknown3; - /// Bytes 720 to 723 Unknown - public byte[] Unknown4; - /// Bytes 724 to 767 Unknown, XGD3 - public byte[] Unknown5; - /// Byte 768 Version of challenge table - public byte ChallengeTableVersion; - /// Byte 769 Number of challenge entries - public byte NoChallengeEntries; - /// Bytes 770 to 1022 Unknown - public ChallengeEntry[] ChallengeEntries; - /// Byte 1023 Unknown - public byte Unknown6; - /// Bytes 1052 to 1099 Unknown, XGD1 only - public byte[] Unknown7; - /// Bytes 1120 to 1135 Unknown, XGD2 and XGD3 - public byte[] Unknown8; - /// Bytes 1180 to 1195 Unknown - public byte[] Unknown9; - /// Bytes 1208 to 1511 Unknown - public byte[] Unknown10; - /// Bytes 1528 to 1632 - public byte[] Unknown11; - /// Bytes 1633 to 1839 Security extents, 23 entries of 9 bytes - public SecuritySectorExtent[] Extents; - /// Bytes 1840 to 2047 Copy of the security extents, 23 entries of 9 bytes - public SecuritySectorExtent[] ExtentsCopy; + sb.AppendFormat("\tChallenge ID: {0}", entry.ChallengeId).AppendLine(); + sb.AppendFormat("\tChallenge level: {0}", entry.Level).AppendLine(); + sb.AppendFormat("\tChallenge value: 0x{0:X8}", entry.ChallengeValue).AppendLine(); + sb.AppendFormat("\tResponse modifier: {0}", entry.ResponseModifier).AppendLine(); + sb.AppendFormat("\tResponse value: 0x{0:X8}", entry.ResponseValue).AppendLine(); } - public struct SecuritySectorExtent - { - /// Bytes 0 to 2 Unknown - public uint Unknown; - /// Bytes 3 to 5 Start PSN of this security extent - public uint StartPSN; - /// Bytes 6 to 8 End PSN of this security extent - public uint EndPSN; - } + for(int i = 0; i < 16; i++) + sb.AppendFormat("Extent starts at PSN {0:X6}h and ends at PSN {1:X6}h", decoded.Extents[i].StartPSN, + decoded.Extents[i].EndPSN).AppendLine(); - public struct ChallengeEntry - { - public byte Level; - public byte ChallengeId; - public uint ChallengeValue; - public byte ResponseModifier; - public uint ResponseValue; - } + return sb.ToString(); + } + + public static string Prettify(byte[] response) => Prettify(Decode(response)); + + public struct SecuritySector + { + /// Byte 0, bits 7 to 4 Disk category field + public DiskCategory DiskCategory; + /// Byte 0, bits 3 to 0 Media version + public byte PartVersion; + /// Byte 1, bits 7 to 4 120mm if 0, 80mm if 1. If UMD (60mm) 0 also. Reserved rest of values + public DVDSize DiscSize; + /// Byte 1, bits 3 to 0 Maximum data rate + public MaximumRateField MaximumRate; + /// Byte 2, bit 7 Reserved + public bool Reserved3; + /// Byte 2, bits 6 to 5 Number of layers + public byte Layers; + /// Byte 2, bit 4 Track path + public bool TrackPath; + /// Byte 2, bits 3 to 0 Layer type + public LayerTypeFieldMask LayerType; + /// Byte 3, bits 7 to 4 Linear density field + public LinearDensityField LinearDensity; + /// Byte 3, bits 3 to 0 Track density field + public TrackDensityField TrackDensity; + /// Bytes 4 to 7 PSN where Data Area starts + public uint DataAreaStartPSN; + /// Bytes 8 to 11 PSN where Data Area ends + public uint DataAreaEndPSN; + /// Bytes 12 to 15 PSN where Data Area ends in Layer 0 + public uint Layer0EndPSN; + + /// Byte 27 Always 0x06 on XGD3 + public byte Unknown1; + /// Bytes 256 to 283 Unknown, XGD2 and XGD3 + public byte[] Unknown2; + /// Bytes 284 to 719 Unknown, XGD3 + public byte[] Unknown3; + /// Bytes 720 to 723 Unknown + public byte[] Unknown4; + /// Bytes 724 to 767 Unknown, XGD3 + public byte[] Unknown5; + /// Byte 768 Version of challenge table + public byte ChallengeTableVersion; + /// Byte 769 Number of challenge entries + public byte NoChallengeEntries; + /// Bytes 770 to 1022 Unknown + public ChallengeEntry[] ChallengeEntries; + /// Byte 1023 Unknown + public byte Unknown6; + /// Bytes 1052 to 1099 Unknown, XGD1 only + public byte[] Unknown7; + /// Bytes 1120 to 1135 Unknown, XGD2 and XGD3 + public byte[] Unknown8; + /// Bytes 1180 to 1195 Unknown + public byte[] Unknown9; + /// Bytes 1208 to 1511 Unknown + public byte[] Unknown10; + /// Bytes 1528 to 1632 + public byte[] Unknown11; + /// Bytes 1633 to 1839 Security extents, 23 entries of 9 bytes + public SecuritySectorExtent[] Extents; + /// Bytes 1840 to 2047 Copy of the security extents, 23 entries of 9 bytes + public SecuritySectorExtent[] ExtentsCopy; + } + + public struct SecuritySectorExtent + { + /// Bytes 0 to 2 Unknown + public uint Unknown; + /// Bytes 3 to 5 Start PSN of this security extent + public uint StartPSN; + /// Bytes 6 to 8 End PSN of this security extent + public uint EndPSN; + } + + public struct ChallengeEntry + { + public byte Level; + public byte ChallengeId; + public uint ChallengeValue; + public byte ResponseModifier; + public uint ResponseValue; } } \ No newline at end of file