2017-05-19 20:28:49 +01:00
// /***************************************************************************
2015-10-19 02:40:30 +01:00
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : TOC.cs
2016-07-28 18:13:49 +01:00
// Author(s) : Natalia Portillo <claunia@claunia.com>
2015-10-19 02:40:30 +01:00
//
2016-07-28 18:13:49 +01:00
// Component : Device structures decoders.
2015-10-19 02:40:30 +01:00
//
// --[ Description ] ----------------------------------------------------------
//
2016-07-28 18:13:49 +01:00
// Decodes CD Table of Contents.
2015-10-19 02:40:30 +01:00
//
// --[ License ] --------------------------------------------------------------
//
2016-07-28 18:13:49 +01:00
// 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
2015-10-19 02:40:30 +01:00
// License, or (at your option) any later version.
//
2016-07-28 18:13:49 +01:00
// 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.
2015-10-19 02:40:30 +01:00
//
2016-07-28 18:13:49 +01:00
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
2015-10-19 02:40:30 +01:00
//
// ----------------------------------------------------------------------------
2017-05-19 20:28:49 +01:00
// Copyright © 2011-2017 Natalia Portillo
2015-10-19 02:40:30 +01:00
// ****************************************************************************/
2016-07-28 18:13:49 +01:00
2015-10-19 02:40:30 +01:00
using System ;
using DiscImageChef.Console ;
using System.Text ;
namespace DiscImageChef.Decoders.CD
{
/// <summary>
/// Information from the following standards:
/// ANSI X3.304-1997
/// T10/1048-D revision 9.0
/// T10/1048-D revision 10a
/// T10/1228-D revision 7.0c
/// T10/1228-D revision 11a
/// T10/1363-D revision 10g
/// T10/1545-D revision 1d
/// T10/1545-D revision 5
/// T10/1545-D revision 5a
/// T10/1675-D revision 2c
/// T10/1675-D revision 4
/// T10/1836-D revision 2g
2015-12-03 09:31:06 +00:00
/// ISO/IEC 61104: Compact disc video system - 12 cm CD-V
/// ISO/IEC 60908: Audio recording - Compact disc digital audio system
2015-10-19 02:40:30 +01:00
/// </summary>
public static class TOC
{
public struct CDTOC
{
/// <summary>
/// Total size of returned TOC minus this field
/// </summary>
2016-07-28 22:25:26 +01:00
public ushort DataLength ;
2015-10-19 02:40:30 +01:00
/// <summary>
/// First track number in hex
/// </summary>
public byte FirstTrack ;
/// <summary>
/// Last track number in hex
/// </summary>
public byte LastTrack ;
/// <summary>
/// Track descriptors
/// </summary>
public CDTOCTrackDataDescriptor [ ] TrackDescriptors ;
}
public struct CDTOCTrackDataDescriptor
{
/// <summary>
/// Byte 0
/// Reserved
/// </summary>
public byte Reserved1 ;
/// <summary>
/// Byte 1, bits 7 to 4
/// Type of information in Q subchannel of block where this TOC entry was found
/// </summary>
public byte ADR ;
/// <summary>
/// Byte 1, bits 3 to 0
/// Track attributes
/// </summary>
public byte CONTROL ;
/// <summary>
/// Byte 2
/// Track number
/// </summary>
public byte TrackNumber ;
/// <summary>
/// Byte 3
/// Reserved
/// </summary>
public byte Reserved2 ;
/// <summary>
/// Bytes 4 to 7
/// The track start address in LBA or in MSF
/// </summary>
2016-07-28 22:25:26 +01:00
public uint TrackStartAddress ;
2015-10-19 02:40:30 +01:00
}
2015-10-19 02:46:04 +01:00
public static CDTOC ? Decode ( byte [ ] CDTOCResponse )
2015-10-19 02:40:30 +01:00
{
2016-04-19 02:11:47 +01:00
if ( CDTOCResponse = = null )
2015-10-19 02:40:30 +01:00
return null ;
CDTOC decoded = new CDTOC ( ) ;
BigEndianBitConverter . IsLittleEndian = BitConverter . IsLittleEndian ;
decoded . DataLength = BigEndianBitConverter . ToUInt16 ( CDTOCResponse , 0 ) ;
decoded . FirstTrack = CDTOCResponse [ 2 ] ;
decoded . LastTrack = CDTOCResponse [ 3 ] ;
decoded . TrackDescriptors = new CDTOCTrackDataDescriptor [ ( decoded . DataLength - 2 ) / 8 ] ;
2016-04-19 02:11:47 +01:00
if ( decoded . DataLength + 2 ! = CDTOCResponse . Length )
2015-10-19 02:40:30 +01:00
{
DicConsole . DebugWriteLine ( "CD TOC decoder" , "Expected CDTOC size ({0} bytes) is not received size ({1} bytes), not decoding" , decoded . DataLength + 2 , CDTOCResponse . Length ) ;
return null ;
}
2016-04-19 02:11:47 +01:00
for ( int i = 0 ; i < ( ( decoded . DataLength - 2 ) / 8 ) ; i + + )
2015-10-19 02:40:30 +01:00
{
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 ;
}
2015-10-19 02:46:04 +01:00
public static string Prettify ( CDTOC ? CDTOCResponse )
2015-10-19 02:40:30 +01:00
{
2016-04-19 02:11:47 +01:00
if ( CDTOCResponse = = null )
2015-10-19 02:40:30 +01:00
return null ;
CDTOC response = CDTOCResponse . Value ;
StringBuilder 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 ( ) ;
2016-04-19 02:11:47 +01:00
foreach ( CDTOCTrackDataDescriptor descriptor in response . TrackDescriptors )
2015-10-19 02:40:30 +01:00
{
2016-04-19 02:11:47 +01:00
if ( descriptor . TrackNumber = = 0xAA )
sb . AppendLine ( "Track number: Lead-Out" ) ;
2015-11-24 00:40:33 +00:00
else
sb . AppendFormat ( "Track number: {0}" , descriptor . TrackNumber ) . AppendLine ( ) ;
2015-10-19 02:40:30 +01:00
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 ,
2015-11-24 00:40:33 +00:00
( descriptor . TrackStartAddress & 0xFF000000 ) > > 24 ) . AppendLine ( ) ;
2015-10-19 02:40:30 +01:00
2016-04-19 02:11:47 +01:00
switch ( ( TOC_ADR ) descriptor . ADR )
2015-10-19 02:40:30 +01:00
{
case TOC_ADR . NoInformation :
sb . AppendLine ( "Q subchannel mode not given" ) ;
break ;
2015-12-03 09:31:06 +00:00
case TOC_ADR . TrackPointer :
sb . AppendLine ( "Q subchannel stores track pointer" ) ;
break ;
case TOC_ADR . VideoTrackPointer :
sb . AppendLine ( "Q subchannel stores video track pointer" ) ;
2015-10-19 02:40:30 +01:00
break ;
case TOC_ADR . ISRC :
sb . AppendLine ( "Q subchannel stores ISRC" ) ;
break ;
case TOC_ADR . MediaCatalogNumber :
sb . AppendLine ( "Q subchannel stores media catalog number" ) ;
break ;
2015-12-03 09:31:06 +00:00
default :
sb . AppendFormat ( "Q subchannel mode {0}" , descriptor . ADR ) . AppendLine ( ) ;
break ;
2015-10-19 02:40:30 +01:00
}
if ( ( descriptor . CONTROL & ( byte ) TOC_CONTROL . ReservedMask ) = = ( byte ) TOC_CONTROL . ReservedMask )
sb . AppendFormat ( "Reserved flags 0x{0:X2} set" , descriptor . CONTROL ) . AppendLine ( ) ;
else
{
2016-04-19 02:11:47 +01:00
switch ( ( TOC_CONTROL ) ( descriptor . CONTROL & 0x0D ) )
2015-10-19 02:40:30 +01:00
{
case TOC_CONTROL . TwoChanNoPreEmph :
sb . AppendLine ( "Stereo audio track with no pre-emphasis" ) ;
break ;
case TOC_CONTROL . TwoChanPreEmph :
sb . AppendLine ( "Stereo audio track with 50/15 μs pre-emphasis" ) ;
break ;
case TOC_CONTROL . FourChanNoPreEmph :
sb . AppendLine ( "Quadraphonic audio track with no pre-emphasis" ) ;
break ;
case TOC_CONTROL . FourChanPreEmph :
2015-12-04 01:57:56 +00:00
sb . AppendLine ( "Quadraphonic audio track with 50/15 μs pre-emphasis" ) ;
2015-10-19 02:40:30 +01:00
break ;
case TOC_CONTROL . DataTrack :
sb . AppendLine ( "Data track, recorded uninterrupted" ) ;
break ;
case TOC_CONTROL . DataTrackIncremental :
sb . AppendLine ( "Data track, recorded incrementally" ) ;
break ;
}
2016-04-19 02:11:47 +01:00
if ( ( descriptor . CONTROL & ( byte ) TOC_CONTROL . CopyPermissionMask ) = = ( byte ) TOC_CONTROL . CopyPermissionMask )
2015-10-19 02:40:30 +01:00
sb . AppendLine ( "Digital copy of track is permitted" ) ;
else
sb . AppendLine ( "Digital copy of track is prohibited" ) ;
2016-04-19 02:11:47 +01:00
#if DEBUG
2015-10-19 02:40:30 +01:00
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 ( ) ;
2016-04-19 02:11:47 +01:00
#endif
2015-10-19 02:40:30 +01:00
sb . AppendLine ( ) ;
}
}
return sb . ToString ( ) ;
}
2015-10-19 02:46:04 +01:00
public static string Prettify ( byte [ ] CDTOCResponse )
2015-10-19 02:40:30 +01:00
{
2015-10-19 02:46:04 +01:00
CDTOC ? decoded = Decode ( CDTOCResponse ) ;
return Prettify ( decoded ) ;
2015-10-19 02:40:30 +01:00
}
}
}