2015-06-23 18:57:11 +00:00
using System ;
using System.Runtime.InteropServices ;
2019-12-19 04:16:42 +00:00
using BizHawk.Common ;
2015-06-23 18:57:11 +00:00
namespace BizHawk.Emulation.DiscSystem
{
/// <summary>
/// A resource representing a disc opened and mounted through the MednaDisc component.
/// Does not attempt to virtually present the disc as a BizHawk disc - that will be the
/// responsibility of the user of this code
/// </summary>
public unsafe class MednaDisc : IDisposable
{
2019-12-29 10:52:32 +00:00
/// <exception cref="InvalidOperationException"><see cref="IsLibraryAvailable"/> is <see langword="false"/> (could not load <c>mednadisc.dll</c>), or unmanaged call failed</exception>
2015-06-23 18:57:11 +00:00
public MednaDisc ( string pathToDisc )
{
if ( ! IsLibraryAvailable )
2019-03-28 03:17:14 +00:00
throw new InvalidOperationException ( $"{nameof(MednaDisc)} library is not available!" ) ;
2015-06-23 18:57:11 +00:00
handle = mednadisc_LoadCD ( pathToDisc ) ;
if ( handle = = IntPtr . Zero )
2019-03-28 03:17:14 +00:00
throw new InvalidOperationException ( $"Failed to load {nameof(MednaDisc)}: {pathToDisc}" ) ;
2015-06-23 18:57:11 +00:00
//read the mednafen toc
TOCTracks = new MednadiscTOCTrack [ 101 ] ;
fixed ( MednadiscTOCTrack * _tracks = & TOCTracks [ 0 ] )
fixed ( MednadiscTOC * _toc = & TOC )
mednadisc_ReadTOC ( handle , _toc , _tracks ) ;
//leave the disc open until this is disposed so we can read sectors from it
}
IntPtr handle ;
public MednadiscTOC TOC ;
public MednadiscTOCTrack [ ] TOCTracks ;
[ThreadStatic] static byte [ ] buf2442 = new byte [ 2448 ] ;
[ThreadStatic] static byte [ ] buf96 = new byte [ 96 ] ;
public void Read_2442 ( int LBA , byte [ ] buffer , int offset )
{
//read directly into the target buffer
fixed ( byte * pBuffer = & buffer [ 0 ] )
mednadisc_ReadSector ( handle , LBA , pBuffer + offset ) ;
}
2020-01-13 01:14:16 +00:00
#if false
public void ReadSubcodeDeinterleaved ( int LBA , byte [ ] buffer , int offset )
{
fixed ( byte * pBuffer = buf2442 )
mednadisc_ReadSector ( handle , LBA , pBuffer ) ;
SynthUtils . DeinterleaveSubcode ( buf2442 , 2352 , buffer , offset ) ;
}
public void ReadSubcodeChannel ( int LBA , int number , byte [ ] buffer , int offset )
{
fixed ( byte * pBuffer = buf2442 )
mednadisc_ReadSector ( handle , LBA , pBuffer ) ;
SynthUtils . DeinterleaveSubcode ( buf2442 , 2352 , buf96 , 0 ) ;
for ( int i = 0 ; i < 12 ; i + + )
buffer [ offset + i ] = buf96 [ number * 12 + i ] ;
}
public void Read_2352 ( int LBA , byte [ ] buffer , int offset )
{
fixed ( byte * pBuffer = buf2442 )
mednadisc_ReadSector ( handle , LBA , pBuffer ) ;
Buffer . BlockCopy ( buf2442 , 0 , buffer , offset , 2352 ) ;
}
public void Read_2048 ( int LBA , byte [ ] buffer , int offset )
{
//this depends on CD-XA mode and such. so we need to read the mode bytes
//HEY!!!!!! SHOULD THIS BE DONE BASED ON THE CLAIMED TRACK TYPE, OR ON WHATS IN THE SECTOR?
//this is kind of a function of the CD reader.. it's not clear how this function should work.
//YIKES!!!!!!!!!!!!!!
//well, we need to scrutinize it for CCD files anyway, so...
//this sucks.
fixed ( byte * pBuffer = buf2442 )
mednadisc_ReadSector ( handle , LBA , pBuffer ) ;
byte mode = buf2442 [ 15 ] ;
if ( mode = = 1 )
Buffer . BlockCopy ( buf2442 , 16 , buffer , offset , 2048 ) ;
else
Buffer . BlockCopy ( buf2442 , 24 , buffer , offset , 2048 ) ; //PSX assumptions about CD-XA.. BAD BAD BAD
}
#endif
2015-06-23 18:57:11 +00:00
static void CheckLibrary ( )
{
2019-12-19 04:16:42 +00:00
var lib = OSTailoredCode . LinkedLibManager . LoadOrNull ( "mednadisc.dll" ) ;
_IsLibraryAvailable = lib ! = null
& & OSTailoredCode . LinkedLibManager . GetProcAddrOrNull ( lib . Value , "mednadisc_LoadCD" ) ! = null ;
if ( lib ! = null ) OSTailoredCode . LinkedLibManager . FreeByPtr ( lib . Value ) ;
2015-06-23 18:57:11 +00:00
}
static MednaDisc ( )
{
CheckLibrary ( ) ;
}
static bool _IsLibraryAvailable ;
2020-02-25 20:13:06 +00:00
public static bool IsLibraryAvailable = > _IsLibraryAvailable ;
2015-06-23 18:57:11 +00:00
public void Dispose ( )
{
if ( handle = = IntPtr . Zero ) return ;
mednadisc_CloseCD ( handle ) ;
}
[StructLayout(LayoutKind.Sequential)]
public struct MednadiscTOC
{
public byte first_track ;
public byte last_track ;
public byte disc_type ;
2020-01-25 05:16:12 +00:00
}
2015-06-23 18:57:11 +00:00
[StructLayout(LayoutKind.Explicit)]
public struct MednadiscTOCTrack
{
[FieldOffset(0)] public byte adr ;
[FieldOffset(1)] public byte control ;
[FieldOffset(4)] public uint lba ;
//can't be a bool due to marshalling...
[FieldOffset(8)] public byte _validByte ;
2020-02-25 20:13:06 +00:00
public bool Valid = > _validByte ! = 0 ;
2020-01-25 05:16:12 +00:00
}
2015-06-23 18:57:11 +00:00
[DllImport("mednadisc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mednadisc_LoadCD ( string path ) ;
[DllImport("mednadisc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mednadisc_ReadSector ( IntPtr disc , int lba , byte * buf2448 ) ;
[DllImport("mednadisc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mednadisc_CloseCD ( IntPtr disc ) ;
[DllImport("mednadisc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mednadisc_ReadTOC ( IntPtr disc , MednadiscTOC * toc , MednadiscTOCTrack * tracks101 ) ;
}
}