193 lines
5.5 KiB
C#
193 lines
5.5 KiB
C#
using System;
|
|
using System.Security;
|
|
using System.Runtime.InteropServices;
|
|
using System.Linq;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Reflection.Emit;
|
|
using System.Threading;
|
|
using BizHawk.DiscSystem;
|
|
|
|
namespace BizHawk
|
|
{
|
|
/// <summary>
|
|
/// represents an external core's interface to a disc
|
|
/// </summary>
|
|
public class DiscInterface : ExternalCore
|
|
{
|
|
public DiscInterface(IExternalCoreAccessor accessor)
|
|
: base(accessor)
|
|
{
|
|
UnmanagedOpaque = QueryCoreCall<Func<IntPtr, IntPtr>>("DiscInterface.Construct")(ManagedOpaque);
|
|
|
|
SetFp("Dispose", new disposeDelegate(Dispose));
|
|
SetFp("GetNumSessions", new GetNumSessionsDelegate(GetNumSessions));
|
|
SetFp("GetNumTracks", new GetNumTracksDelegate(GetNumTracks));
|
|
SetFp("GetTrack", new GetTrackDelegate(GetTrack));
|
|
}
|
|
|
|
bool disposed = false;
|
|
public override void Dispose()
|
|
{
|
|
if (disposed) return;
|
|
disposed = true;
|
|
|
|
QueryCoreCall<Action>("DiscInterface.Delete")();
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
public DiscHopper DiscHopper;
|
|
|
|
void SetFp(string name, Delegate del)
|
|
{
|
|
QueryCoreCall<Action<string, IntPtr>>("DiscInterface.Set_fp")(name, ExportDelegate(del));
|
|
}
|
|
|
|
struct TrackInfo
|
|
{
|
|
public ETrackType TrackType;
|
|
public int length_lba;
|
|
public int start_lba;
|
|
}
|
|
|
|
int GetNumSessions()
|
|
{
|
|
return DiscHopper.CurrentDisc.ReadTOC().Sessions.Count;
|
|
}
|
|
|
|
int GetNumTracks(int session)
|
|
{
|
|
return DiscHopper.CurrentDisc.ReadTOC().Sessions[session].Tracks.Count;
|
|
}
|
|
|
|
TrackInfo GetTrack(int session, int track)
|
|
{
|
|
var ti = new TrackInfo();
|
|
var toc_track = DiscHopper.CurrentDisc.ReadTOC().Sessions[session].Tracks[track];
|
|
ti.TrackType = toc_track.TrackType;
|
|
ti.length_lba = toc_track.length_aba;
|
|
return ti;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate void disposeDelegate();
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate int GetNumSessionsDelegate();
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate int GetNumTracksDelegate(int session);
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate TrackInfo GetTrackDelegate(int session, int track);
|
|
}
|
|
|
|
|
|
public class EmuFile : ExternalCore
|
|
{
|
|
public EmuFile(IExternalCoreAccessor accessor)
|
|
: base(accessor)
|
|
{
|
|
UnmanagedOpaque = QueryCoreCall<Func<IntPtr, IntPtr>>("EmuFile.Construct")(ManagedOpaque);
|
|
|
|
SetFp("fgetc", new fgetcDelegate(fgetc));
|
|
SetFp("fread", new freadDelegate(fread));
|
|
SetFp("fwrite", new fwriteDelegate(fwrite));
|
|
SetFp("fseek", new fseekDelegate(fseek));
|
|
SetFp("ftell", new ftellDelegate(ftell));
|
|
SetFp("size", new sizeDelegate(size));
|
|
SetFp("dispose", new disposeDelegate(Dispose));
|
|
}
|
|
|
|
void SetFp(string name, Delegate del)
|
|
{
|
|
QueryCoreCall<Action<string, IntPtr>>("EmuFile.Set_fp")(name, ExportDelegate(del));
|
|
}
|
|
|
|
public Stream BaseStream { get; set; }
|
|
|
|
//do we want to have a finalizer? not sure.
|
|
bool disposed = false;
|
|
public override void Dispose()
|
|
{
|
|
if (disposed) return;
|
|
disposed = true;
|
|
|
|
//we will call Delete in the c++ side, which will delete the object, and cause Dispose() to get called.
|
|
//but, Dispose() can never be called again due to setting the flag above
|
|
QueryCoreCall<Action>("EmuFile.Delete")();
|
|
|
|
//do we always want to do this? not sure. but usually.
|
|
BaseStream.Dispose();
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
int fgetc()
|
|
{
|
|
return BaseStream.ReadByte();
|
|
}
|
|
|
|
IntPtr fread(
|
|
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
|
|
byte[] ptr,
|
|
IntPtr bytes)
|
|
{
|
|
long len = bytes.ToInt64();
|
|
if (len >= int.MaxValue || len < 0) throw new ArgumentException();
|
|
|
|
int ret = BaseStream.Read(ptr, 0, (int)len);
|
|
return new IntPtr(ret);
|
|
}
|
|
|
|
IntPtr fseek(IntPtr offset, IntPtr origin)
|
|
{
|
|
SeekOrigin so = (SeekOrigin)origin.ToInt32();
|
|
long loffset = offset.ToInt64();
|
|
return new IntPtr(BaseStream.Seek(loffset, so));
|
|
}
|
|
|
|
IntPtr ftell() { return new IntPtr(BaseStream.Position); }
|
|
IntPtr size() { return new IntPtr(BaseStream.Length); }
|
|
|
|
void fwrite(
|
|
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
|
|
byte[] ptr,
|
|
IntPtr bytes)
|
|
{
|
|
long len = bytes.ToInt64();
|
|
if (len >= int.MaxValue || len < 0) throw new ArgumentException();
|
|
|
|
BaseStream.Write(ptr, 0, (int)len);
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate int fgetcDelegate();
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate void disposeDelegate();
|
|
//TODO - for more speed fread and fwrite might appreciate taking pointers
|
|
//(although, we'll have to convert it to an array to deal with an underlying stream anyway -- or will we?
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate IntPtr freadDelegate(
|
|
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
|
|
byte[] ptr,
|
|
IntPtr bytes);
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate void fwriteDelegate(
|
|
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
|
|
byte[] ptr,
|
|
IntPtr bytes);
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate IntPtr fseekDelegate(IntPtr offset, IntPtr origin);
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate IntPtr ftellDelegate();
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
delegate IntPtr sizeDelegate();
|
|
|
|
}
|
|
} |