// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : ATIP.cs // Author(s) : Natalia Portillo // // Component : Device structures decoders. // // --[ Description ] ---------------------------------------------------------- // // Decodes CD Absolute-Time-In-Pregroove // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2025 Natalia Portillo // ****************************************************************************/ using System; using System.Diagnostics.CodeAnalysis; using System.Text; using Aaru.Helpers; using Aaru.Logging; 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 { const string MODULE_NAME = "CD ATIP decoder"; public static CDATIP Decode(byte[] CDATIPResponse) { if(CDATIPResponse is not { Length: > 4 }) return null; var decoded = new CDATIP(); if(CDATIPResponse.Length != 32 && CDATIPResponse.Length != 28) { AaruLogging.Debug(MODULE_NAME, Localization.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; } public static string Prettify(CDATIP response) { if(response == null) return null; var sb = new StringBuilder(); if(response.DDCD) { sb.AppendFormat(Localization.Indicative_Target_Writing_Power_0, response.ITWP).AppendLine(); sb.AppendLine(response.DiscType ? Localization.Disc_is_DDCD_RW : Localization.Disc_is_DDCD_R); switch(response.ReferenceSpeed) { case 2: sb.AppendLine(Localization.Reference_speed_is_4x); break; case 3: sb.AppendLine(Localization.Reference_speed_is_8x); break; default: sb.AppendFormat(Localization.Reference_speed_set_is_unknown_0, response.ReferenceSpeed) .AppendLine(); break; } sb.AppendFormat(Localization.ATIP_Start_time_of_Lead_in_0, (response.LeadInStartMin << 16) + (response.LeadInStartSec << 8) + response.LeadInStartFrame) .AppendLine(); sb.AppendFormat(Localization.ATIP_Last_possible_start_time_of_Lead_out_0, (response.LeadOutStartMin << 16) + (response.LeadOutStartSec << 8) + response.LeadOutStartFrame) .AppendLine(); sb.AppendFormat(Localization.S4_value_0, (response.S4Values[0] << 16) + (response.S4Values[1] << 8) + response.S4Values[2]) .AppendLine(); } else { sb.AppendFormat(Localization.Indicative_Target_Writing_Power_0, response.ITWP & 0x07).AppendLine(); if(response.DiscType) { switch(response.DiscSubType) { case 0: sb.AppendLine(Localization.Disc_is_CD_RW); break; case 1: sb.AppendLine(Localization.Disc_is_High_Speed_CD_RW); break; case 2: sb.AppendLine(Localization.Disc_is_Ultra_Speed_CD_RW); break; case 3: sb.AppendLine(Localization.Disc_is_Ultra_Speed_Plus_CD_RW); break; case 4: sb.AppendLine(Localization.Disc_is_medium_type_B_low_beta_category_CD_RW); break; case 5: sb.AppendLine(Localization.Disc_is_medium_type_B_high_beta_category_CD_RW); break; case 6: sb.AppendLine(Localization.Disc_is_medium_type_C_low_beta_category_CD_RW); break; case 7: sb.AppendLine(Localization.Disc_is_medium_type_C_high_beta_category_CD_RW); break; default: sb.AppendFormat(Localization.Unknown_CD_RW_disc_subtype_0, response.DiscSubType).AppendLine(); break; } switch(response.ReferenceSpeed) { case 1: sb.AppendLine(Localization.Reference_speed_is_2x); break; default: sb.AppendFormat(Localization.Reference_speed_set_is_unknown_0, response.ReferenceSpeed) .AppendLine(); break; } } else { sb.AppendLine(Localization.Disc_is_CD_R); switch(response.DiscSubType) { case 0: sb.AppendLine(Localization.Disc_is_normal_speed_CLV_CD_R); break; case 1: sb.AppendLine(Localization.Disc_is_high_speed_CAV_CD_R); break; case 2: sb.AppendLine(Localization.Disc_is_medium_type_A_low_beta_category_CD_R); break; case 3: sb.AppendLine(Localization.Disc_is_medium_type_A_high_beta_category_CD_R); break; case 4: sb.AppendLine(Localization.Disc_is_medium_type_B_low_beta_category_CD_R); break; case 5: sb.AppendLine(Localization.Disc_is_medium_type_B_high_beta_category__CD_R); break; case 6: sb.AppendLine(Localization.Disc_is_medium_type_C_low_beta_category__CD_R); break; case 7: sb.AppendLine(Localization.Disc_is_medium_type_C_high_beta_category__CD_R); break; default: sb.AppendFormat(Localization.Unknown_CD_R_disc_subtype_0, response.DiscSubType).AppendLine(); break; } } sb.AppendLine(response.URU ? Localization.Disc_use_is_unrestricted : Localization.Disc_use_is_restricted); sb.AppendFormat(Localization.ATIP_Start_time_of_Lead_in_0_1_2, response.LeadInStartMin, response.LeadInStartSec, response.LeadInStartFrame) .AppendLine(); sb.AppendFormat(Localization.ATIP_Last_possible_start_time_of_Lead_out_0_1_2, response.LeadOutStartMin, response.LeadOutStartSec, response.LeadOutStartFrame) .AppendLine(); if(response.A1Valid) { sb.AppendFormat(Localization.A1_value_0, (response.A1Values[0] << 16) + (response.A1Values[1] << 8) + response.A1Values[2]) .AppendLine(); } if(response.A2Valid) { sb.AppendFormat(Localization.A2_value_0, (response.A2Values[0] << 16) + (response.A2Values[1] << 8) + response.A2Values[2]) .AppendLine(); } if(response.A3Valid) { sb.AppendFormat(Localization.A3_value_0, (response.A3Values[0] << 16) + (response.A3Values[1] << 8) + response.A3Values[2]) .AppendLine(); } if(response.S4Values != null) { sb.AppendFormat(Localization.S4_value_0, (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(Localization.Disc_uses_phase_change); else { sb.AppendLine(type < 5 ? Localization.Disc_uses_long_strategy_type_dye_Cyanine_AZO_etc : Localization.Disc_uses_short_strategy_type_dye_Phthalocyanine_etc); } string manufacturer = ManufacturerFromATIP(response.LeadInStartSec, frm); if(manufacturer != "") sb.AppendFormat(Localization.Disc_manufactured_by_0, manufacturer).AppendLine(); return sb.ToString(); } public static string Prettify(byte[] CDATIPResponse) { CDATIP decoded = Decode(CDATIPResponse); return Prettify(decoded); } [SuppressMessage("ReSharper", "StringLiteralTypo")] public static string ManufacturerFromATIP(byte sec, int frm) { switch(sec) { case 10: switch(frm) { case 00: return "Ritek Co."; } 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 ""; } #region Nested type: CDATIP 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; } #endregion }