diff --git a/DiscImageChef.Decoders/ChangeLog b/DiscImageChef.Decoders/ChangeLog index 325432ac..6f05aefd 100644 --- a/DiscImageChef.Decoders/ChangeLog +++ b/DiscImageChef.Decoders/ChangeLog @@ -1,3 +1,8 @@ +2015-12-02 Natalia Portillo + + * DVD/DDS.cs: + Added DDS decoding. + 2015-12-01 Natalia Portillo * DVD/CSS&CPRM.cs: diff --git a/DiscImageChef.Decoders/DVD/DDS.cs b/DiscImageChef.Decoders/DVD/DDS.cs index 6de2b77f..35b59fa7 100644 --- a/DiscImageChef.Decoders/DVD/DDS.cs +++ b/DiscImageChef.Decoders/DVD/DDS.cs @@ -36,6 +36,7 @@ // ****************************************************************************/ // //$Id$ using System; +using System.Text; namespace DiscImageChef.Decoders.DVD { @@ -53,7 +54,8 @@ namespace DiscImageChef.Decoders.DVD /// T10/1675-D revision 2c /// T10/1675-D revision 4 /// T10/1836-D revision 2g - /// ECMA 365 + /// 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) /// public static class DDS { @@ -74,11 +76,251 @@ namespace DiscImageChef.Decoders.DVD /// Reserved /// public byte Reserved2; + /// - /// Bytes 4 to 2052 - /// DVD-RAM / HD DVD-RAM disc definition structure + /// Bytes 4 to 5 + /// DDS Identifier = 0x0A0A /// - public byte[] DDS; + 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; + } + + public static DiscDefinitionStructure? Decode(byte[] response) + { + if (response == null) + return null; + + if (response.Length != 2052) + return null; + + DiscDefinitionStructure dds = new DiscDefinitionStructure(); + + dds.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; + } + } + + // ECMA-330 + if (dds.Groups == 1) + { + 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) + { + if (dds == null) + return null; + + DiscDefinitionStructure decoded = dds.Value; + StringBuilder sb = new StringBuilder(); + + if (decoded.InProcess) + { + sb.AppendLine("Formatting in progress."); + if (decoded.Groups == 24) + { + if (decoded.PartialCertification) + sb.AppendLine("Formatting is only using partial certification"); + if (decoded.FormattingOnlyAGroup) + sb.AppendLine("Only a group is being formatted"); + } + } + + if (decoded.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) + { + 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.Groups == 1) + { + 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(); + } + + return sb.ToString(); + } + + public static string Prettify(byte[] response) + { + return Prettify(Decode(response)); } } } diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index fe246239..62756095 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,8 @@ +2015-12-02 Natalia Portillo + + * Commands/MediaInfo.cs: + Added DDS decoding. + 2015-12-01 Natalia Portillo * Commands/MediaInfo.cs: diff --git a/DiscImageChef/Commands/MediaInfo.cs b/DiscImageChef/Commands/MediaInfo.cs index 0aa3a2e9..d2bf8519 100644 --- a/DiscImageChef/Commands/MediaInfo.cs +++ b/DiscImageChef/Commands/MediaInfo.cs @@ -415,7 +415,10 @@ namespace DiscImageChef.Commands if(sense) DicConsole.ErrorWriteLine("READ DISC STRUCTURE: DDS\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); else + { doWriteFile(outputPrefix, "_readdiscstructure_dvdram_dds.bin", "SCSI READ DISC STRUCTURE", cmdBuf); + DicConsole.WriteLine("Disc Definition Structure:\n{0}", Decoders.DVD.DDS.Prettify(cmdBuf)); + } sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDRAM_MediumStatus, 0, dev.Timeout, out duration); if(sense) DicConsole.ErrorWriteLine("READ DISC STRUCTURE: Medium Status\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));