BizHawk/BizHawk.Emulation.Cores/ExternalCores/EmuFile.cs

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();
}
}