some stuff for waterbox gpgx, not finished
This commit is contained in:
parent
9aceb512f0
commit
146442cd69
|
@ -90,8 +90,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
if (!disposed)
|
||||
{
|
||||
// KillMemCallbacks(); // not needed when not single instance
|
||||
if (Dll != null)
|
||||
Dll.Dispose();
|
||||
if (NativeData != null)
|
||||
NativeData.Dispose();
|
||||
if (CD != null)
|
||||
CD.Dispose();
|
||||
disposed = true;
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
state.ReadFromHexFast(hex);
|
||||
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||
}
|
||||
#if true
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
|
@ -75,5 +76,58 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
private byte[] _savebuff;
|
||||
private byte[] _savebuff2;
|
||||
|
||||
private void InitStateBuffers()
|
||||
{
|
||||
byte[] tmp = new byte[Core.gpgx_state_max_size()];
|
||||
int size = Core.gpgx_state_size(tmp, tmp.Length);
|
||||
if (size <= 0)
|
||||
throw new Exception("Couldn't Determine GPGX internal state size!");
|
||||
_savebuff = new byte[size];
|
||||
_savebuff2 = new byte[_savebuff.Length + 13];
|
||||
Console.WriteLine("GPGX Internal State Size: {0}", size);
|
||||
}
|
||||
|
||||
#else
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
var elf = (ElfRunner)NativeData;
|
||||
elf.LoadStateBinary(reader);
|
||||
// other variables
|
||||
Frame = reader.ReadInt32();
|
||||
LagCount = reader.ReadInt32();
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
// any managed pointers that we sent to the core need to be resent now!
|
||||
// TODO: sega cd won't work until we fix that!
|
||||
Core.gpgx_set_input_callback(InputCallback);
|
||||
RefreshMemCallbacks();
|
||||
|
||||
UpdateVideo();
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
var elf = (ElfRunner)NativeData;
|
||||
elf.SaveStateBinary(writer);
|
||||
// other variables
|
||||
writer.Write(Frame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(IsLagFrame);
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
var bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
ms.Close();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void InitStateBuffers()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
IInputPollable, IDebuggable, IDriveLight, ICodeDataLogger, IDisassemblable
|
||||
{
|
||||
LibGPGX Core;
|
||||
InstanceDll Dll;
|
||||
IDisposable NativeData;
|
||||
|
||||
DiscSystem.Disc CD;
|
||||
DiscSystem.DiscSectorReader DiscSectorReader;
|
||||
|
@ -68,8 +68,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
try
|
||||
{
|
||||
Dll = new InstanceDll(Path.Combine(comm.CoreFileProvider.DllPath(), LibGPGX.DllName));
|
||||
Core = BizInvoker.GetInvoker<LibGPGX>(Dll);
|
||||
IImportResolver iimp;
|
||||
if (IntPtr.Size == 8) // there is no 64 bit build of gpgx right now otherwise
|
||||
{
|
||||
var elf = new ElfRunner(Path.Combine(comm.CoreFileProvider.DllPath(), "gpgx.elf"), 1024 * 1024 * 4);
|
||||
NativeData = elf;
|
||||
iimp = elf;
|
||||
}
|
||||
else
|
||||
{
|
||||
var dll = new InstanceDll(Path.Combine(comm.CoreFileProvider.DllPath(), LibGPGX.DllName));
|
||||
NativeData = dll;
|
||||
iimp = dll;
|
||||
}
|
||||
Core = BizInvoker.GetInvoker<LibGPGX>(iimp);
|
||||
|
||||
_syncSettings = (GPGXSyncSettings)SyncSettings ?? new GPGXSyncSettings();
|
||||
_settings = (GPGXSettings)Settings ?? new GPGXSettings();
|
||||
|
@ -133,15 +145,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
|
||||
// compute state size
|
||||
{
|
||||
byte[] tmp = new byte[Core.gpgx_state_max_size()];
|
||||
int size = Core.gpgx_state_size(tmp, tmp.Length);
|
||||
if (size <= 0)
|
||||
throw new Exception("Couldn't Determine GPGX internal state size!");
|
||||
_savebuff = new byte[size];
|
||||
_savebuff2 = new byte[_savebuff.Length + 13];
|
||||
Console.WriteLine("GPGX Internal State Size: {0}", size);
|
||||
}
|
||||
InitStateBuffers();
|
||||
|
||||
SetControllerDefinition();
|
||||
|
||||
|
|
|
@ -7,21 +7,34 @@ using ELFSharp.ELF;
|
|||
using ELFSharp.ELF.Sections;
|
||||
using ELFSharp.ELF.Segments;
|
||||
using System.Reflection;
|
||||
using BizHawk.Common;
|
||||
using System.Security.Cryptography;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Emulation.Cores
|
||||
{
|
||||
public sealed class ElfRunner : IDisposable
|
||||
public sealed class ElfRunner : IImportResolver, IDisposable
|
||||
{
|
||||
// TODO: a lot of things only work with our elves and aren't fully generalized
|
||||
|
||||
private ELF<long> _elf;
|
||||
private byte[] _elfhash;
|
||||
|
||||
private MemoryBlock _base;
|
||||
private MemoryBlock _heap;
|
||||
private ulong _heapused;
|
||||
|
||||
private long _loadoffset;
|
||||
private Dictionary<string, SymbolEntry<long>> _symdict;
|
||||
private List<SymbolEntry<long>> _symlist;
|
||||
|
||||
public ElfRunner(string filename)
|
||||
public ElfRunner(string filename, long heapsize)
|
||||
{
|
||||
using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
_elfhash = Hash(fs);
|
||||
}
|
||||
|
||||
// todo: hack up this baby to take Streams
|
||||
_elf = ELFReader.Load<long>(filename);
|
||||
|
||||
|
@ -30,8 +43,16 @@ namespace BizHawk.Emulation.Cores
|
|||
long orig_start = loadsegs.Min(s => s.Address);
|
||||
orig_start &= ~(Environment.SystemPageSize - 1);
|
||||
long orig_end = loadsegs.Max(s => s.Address + s.Size);
|
||||
_base = new MemoryBlock(0, (ulong)(orig_end - orig_start));
|
||||
_loadoffset = (long)_base.Start - orig_start;
|
||||
if (HasRelocations())
|
||||
{
|
||||
_base = new MemoryBlock((ulong)(orig_end - orig_start));
|
||||
_loadoffset = (long)_base.Start - orig_start;
|
||||
}
|
||||
else
|
||||
{
|
||||
_base = new MemoryBlock((ulong)orig_start, (ulong)(orig_end - orig_start));
|
||||
_loadoffset = 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -48,17 +69,33 @@ namespace BizHawk.Emulation.Cores
|
|||
|
||||
_base.Set(_base.Start, _base.Size, MemoryBlock.Protection.R);
|
||||
|
||||
foreach (var sec in _elf.Sections.Where(s => s.Flags.HasFlag(SectionFlags.Allocatable)))
|
||||
foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Allocatable) != 0))
|
||||
{
|
||||
if (sec.Flags.HasFlag(SectionFlags.Executable))
|
||||
if ((sec.Flags & SectionFlags.Executable) != 0)
|
||||
_base.Set((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RX);
|
||||
else if (sec.Flags.HasFlag(SectionFlags.Writable))
|
||||
else if ((sec.Flags & SectionFlags.Writable) != 0)
|
||||
_base.Set((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RW);
|
||||
}
|
||||
|
||||
if (HasRelocations())
|
||||
{
|
||||
_heap = new MemoryBlock((ulong)heapsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for nonrelocatable, create a canonical heap origin starting at the next 16MB
|
||||
ulong heapstart = ((_base.End - 1) | 0xffffff) + 1;
|
||||
_heap = new MemoryBlock(heapstart, (ulong)heapsize);
|
||||
}
|
||||
_heapused = 0;
|
||||
|
||||
//FixupGOT();
|
||||
ConnectAllClibPatches();
|
||||
Console.WriteLine("Loaded {0}@{1:X16}", filename, _base.Start);
|
||||
foreach (var sec in _elf.Sections.Where(s => s.LoadAddress != 0))
|
||||
{
|
||||
Console.WriteLine(" {0}@{1:X16}, size {2}", sec.Name.PadLeft(20), sec.LoadAddress + _loadoffset, sec.Size.ToString().PadLeft(12));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -90,9 +127,15 @@ namespace BizHawk.Emulation.Cores
|
|||
}
|
||||
}
|
||||
|
||||
private bool HasRelocations()
|
||||
{
|
||||
return _elf.Sections.Any(s => s.Name.StartsWith(".rel"));
|
||||
}
|
||||
|
||||
// elfsharp does not read relocation tables, so there
|
||||
private void ProcessRelocations()
|
||||
{
|
||||
// todo: amd64
|
||||
foreach (var rel in _elf.Sections.Where(s => s.Name.StartsWith(".rel")))
|
||||
{
|
||||
byte[] data = rel.GetContents();
|
||||
|
@ -117,7 +160,7 @@ namespace BizHawk.Emulation.Cores
|
|||
switch (rel.Type)
|
||||
{
|
||||
case 0: val = 0; break;
|
||||
case 1: val = S + A; break;
|
||||
case 1: val = S + A; break;
|
||||
case 2: throw new NotImplementedException();
|
||||
case 3: throw new NotImplementedException();
|
||||
case 4: throw new NotImplementedException();
|
||||
|
@ -151,22 +194,6 @@ namespace BizHawk.Emulation.Cores
|
|||
_symlist = symbols.ToList();
|
||||
}
|
||||
|
||||
public void PopulateInterface(object o)
|
||||
{
|
||||
var fields = o.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(fi => typeof(Delegate).IsAssignableFrom(fi.FieldType))
|
||||
.Where(fi => fi.FieldType.GetCustomAttributes(typeof(UnmanagedFunctionPointerAttribute), false).Length > 0);
|
||||
|
||||
foreach (var fi in fields)
|
||||
{
|
||||
var sym = _symdict[fi.Name]; // TODO: allow some sort of EntryPoint attribute
|
||||
if (sym.Type != SymbolType.Function)
|
||||
throw new InvalidOperationException("Unexpected symbol type for alleged function!");
|
||||
IntPtr ptr = (IntPtr)(sym.Value + _loadoffset);
|
||||
fi.SetValue(o, Marshal.GetDelegateForFunctionPointer(ptr, fi.FieldType));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
@ -187,13 +214,10 @@ namespace BizHawk.Emulation.Cores
|
|||
_base.Dispose();
|
||||
_base = null;
|
||||
}
|
||||
if (_heaps != null)
|
||||
if (_heap != null)
|
||||
{
|
||||
foreach (var b in _heaps.Values)
|
||||
{
|
||||
b.Dispose();
|
||||
}
|
||||
_heaps = null;
|
||||
_heap.Dispose();
|
||||
_heap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,57 +228,50 @@ namespace BizHawk.Emulation.Cores
|
|||
// our clib expects a few function pointers to be defined for it
|
||||
|
||||
/// <summary>
|
||||
/// heap free callback
|
||||
/// </summary>
|
||||
/// <param name="p">ptr</param>
|
||||
/// <param name="size">bytesize</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void FreeMem_D(IntPtr p, IntPtr size);
|
||||
/// <summary>
|
||||
/// heap alloc callback
|
||||
/// </summary>
|
||||
/// <param name="size">bytesize</param>
|
||||
/// <returns></returns>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate IntPtr AllocMem_D(IntPtr size);
|
||||
/// <summary>
|
||||
/// exit() callback
|
||||
/// abort() / other abnormal situation
|
||||
/// </summary>
|
||||
/// <param name="status">desired exit code</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void Exit_D(int status);
|
||||
/*
|
||||
[CLibPatch("_ZZFree")]
|
||||
private void FreeMem(IntPtr p, IntPtr size)
|
||||
{
|
||||
MemoryBlock block;
|
||||
if (_heaps.TryGetValue(p, out block))
|
||||
{
|
||||
_heaps.Remove(p);
|
||||
block.Dispose();
|
||||
}
|
||||
}
|
||||
[CLibPatch("_ZZAlloc")]
|
||||
private IntPtr AllocMem(IntPtr size)
|
||||
{
|
||||
var block = new MemoryBlock((long)size);
|
||||
var p = (IntPtr)(long)block.Start;
|
||||
_heaps[p] = block;
|
||||
block.Set(block.Start, block.Size, MemoryBlock.Protection.RW);
|
||||
Console.WriteLine("AllocMem: {0:X8}@{1:X16}", (long)size, (long)block.Start);
|
||||
return p;
|
||||
}*/
|
||||
[CLibPatch("_ZZExit")]
|
||||
private void Exit(int status)
|
||||
{
|
||||
throw new InvalidOperationException("Client code called exit()");
|
||||
}
|
||||
private delegate void Trap_D();
|
||||
|
||||
/// <summary>
|
||||
/// list of memoryblocks that need to be cleaned up
|
||||
/// expand heap
|
||||
/// </summary>
|
||||
private Dictionary<IntPtr, MemoryBlock> _heaps = new Dictionary<IntPtr, MemoryBlock>();
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate IntPtr Sbrk_D(UIntPtr n);
|
||||
|
||||
/// <summary>
|
||||
/// output a string
|
||||
/// </summary>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void DebugPuts_D(string s);
|
||||
|
||||
[CLibPatch("_ecl_trap")]
|
||||
private void Trap()
|
||||
{
|
||||
throw new InvalidOperationException("Waterbox code trapped!");
|
||||
}
|
||||
|
||||
[CLibPatch("_ecl_sbrk")]
|
||||
private IntPtr Sbrk(UIntPtr n)
|
||||
{
|
||||
ulong newused = _heapused + (ulong)n;
|
||||
if (newused > _heap.Size)
|
||||
{
|
||||
throw new InvalidOperationException("Waterbox sbrk will fail!");
|
||||
}
|
||||
Console.WriteLine("Expanding waterbox heap from {0} to {1} bytes", _heapused, newused);
|
||||
var ret = _heap.Start + _heapused;
|
||||
_heap.Set(ret, newused - _heapused, MemoryBlock.Protection.RW);
|
||||
_heapused = newused;
|
||||
return Z.US(ret);
|
||||
}
|
||||
|
||||
[CLibPatch("_ecl_debug_puts")]
|
||||
private void DebugPuts(string s)
|
||||
{
|
||||
Console.WriteLine("Waterbox debug puts: {0}", s);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// list of delegates that need to not be GCed
|
||||
|
@ -275,7 +292,8 @@ namespace BizHawk.Emulation.Cores
|
|||
var sym = _symdict[((CLibPatchAttribute)mi.GetCustomAttributes(typeof(CLibPatchAttribute), false)[0]).NativeName];
|
||||
if (sym.Size != IntPtr.Size)
|
||||
throw new InvalidOperationException("Unexpected function pointer size patching clib!");
|
||||
Marshal.Copy(new[] { ptr }, 0, (IntPtr)(sym.Value + _loadoffset), 1);
|
||||
IntPtr dest = Z.SS(sym.Value + _loadoffset);
|
||||
Marshal.Copy(new[] { ptr }, 0, dest, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,5 +308,107 @@ namespace BizHawk.Emulation.Cores
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public IntPtr Resolve(string entryPoint)
|
||||
{
|
||||
SymbolEntry<long> sym;
|
||||
if (_symdict.TryGetValue(entryPoint, out sym))
|
||||
{
|
||||
return Z.SS(sym.Value + _loadoffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
#region state
|
||||
|
||||
const ulong MAGIC = 0xb00b1e5b00b1e569;
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
bw.Write(MAGIC);
|
||||
bw.Write(_elfhash);
|
||||
bw.Write(_loadoffset);
|
||||
foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Writable) != 0))
|
||||
{
|
||||
var ms = _base.GetStream((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, false);
|
||||
bw.Write(sec.Size);
|
||||
ms.CopyTo(bw.BaseStream);
|
||||
}
|
||||
|
||||
{
|
||||
var ms = _heap.GetStream(_heap.Start, _heapused, false);
|
||||
bw.Write(_heapused);
|
||||
ms.CopyTo(bw.BaseStream);
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
if (br.ReadUInt64() != MAGIC)
|
||||
throw new InvalidOperationException("Magic not magic enough!");
|
||||
if (!br.ReadBytes(_elfhash.Length).SequenceEqual(_elfhash))
|
||||
throw new InvalidOperationException("Elf changed disguise!");
|
||||
if (br.ReadInt64() != _loadoffset)
|
||||
throw new InvalidOperationException("Trickys elves moved on you!");
|
||||
|
||||
foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Writable) != 0))
|
||||
{
|
||||
var len = br.ReadInt64();
|
||||
if (sec.Size != len)
|
||||
throw new InvalidOperationException("Unexpected section size for " + sec.Name);
|
||||
var ms = _base.GetStream((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, true);
|
||||
CopySome(br.BaseStream, ms, len);
|
||||
}
|
||||
|
||||
{
|
||||
var len = br.ReadInt64();
|
||||
if (len > (long)_heap.Size)
|
||||
throw new InvalidOperationException("Heap size mismatch");
|
||||
var ms = _heap.GetStream(_heap.Start, (ulong)len, true);
|
||||
CopySome(br.BaseStream, ms, len);
|
||||
_heapused = (ulong)len;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static void CopySome(Stream src, Stream dst, long len)
|
||||
{
|
||||
var buff = new byte[4096];
|
||||
while (len > 0)
|
||||
{
|
||||
int r = src.Read(buff, 0, (int)Math.Min(len, 4096));
|
||||
dst.Write(buff, 0, r);
|
||||
len -= r;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] Hash(byte[] data)
|
||||
{
|
||||
using (var h = SHA1.Create())
|
||||
{
|
||||
return h.ComputeHash(data);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] Hash(Stream s)
|
||||
{
|
||||
using (var h = SHA1.Create())
|
||||
{
|
||||
return h.ComputeHash(s);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] HashSection(ulong ptr, ulong len)
|
||||
{
|
||||
using (var h = SHA1.Create())
|
||||
{
|
||||
var ms = _base.GetStream(ptr, len, false);
|
||||
return h.ComputeHash(ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Emulation.Cores
|
||||
{
|
||||
|
@ -102,6 +103,17 @@ namespace BizHawk.Emulation.Cores
|
|||
R, RW, RX, None
|
||||
}
|
||||
|
||||
public Stream GetStream(ulong start, ulong length, bool writer)
|
||||
{
|
||||
if (start < Start)
|
||||
throw new ArgumentOutOfRangeException("start");
|
||||
|
||||
if (start + length > End)
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
|
||||
return new MemoryViewStream(!writer, writer, (long)start, (long)length, this);
|
||||
}
|
||||
|
||||
public void Set(ulong start, ulong length, Protection prot)
|
||||
{
|
||||
if (start < Start)
|
||||
|
@ -110,6 +122,9 @@ namespace BizHawk.Emulation.Cores
|
|||
if (start + length > End)
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
#if !MONO
|
||||
Kernel32.MemoryProtection p;
|
||||
switch (prot)
|
||||
|
@ -164,6 +179,101 @@ namespace BizHawk.Emulation.Cores
|
|||
Dispose(false);
|
||||
}
|
||||
|
||||
private class MemoryViewStream : Stream
|
||||
{
|
||||
public MemoryViewStream(bool readable, bool writable, long ptr, long length, MemoryBlock owner)
|
||||
{
|
||||
_readable = readable;
|
||||
_writable = writable;
|
||||
_ptr = ptr;
|
||||
_length = length;
|
||||
_owner = owner;
|
||||
_pos = 0;
|
||||
}
|
||||
|
||||
private void EnsureNotDisposed()
|
||||
{
|
||||
if (_owner.Start == 0)
|
||||
throw new ObjectDisposedException("MemoryBlock");
|
||||
}
|
||||
|
||||
private MemoryBlock _owner;
|
||||
|
||||
private bool _readable;
|
||||
private bool _writable;
|
||||
|
||||
private long _length;
|
||||
private long _pos;
|
||||
private long _ptr;
|
||||
|
||||
public override bool CanRead { get { return _readable; } }
|
||||
public override bool CanSeek { get { return true; } }
|
||||
public override bool CanWrite { get { return _writable; } }
|
||||
public override void Flush() { }
|
||||
public override long Length { get { return _length; } }
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { return _pos; } set
|
||||
{
|
||||
if (value < 0 || value > _length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
_pos = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (!_readable)
|
||||
throw new InvalidOperationException();
|
||||
if (count < 0 || count > buffer.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
EnsureNotDisposed();
|
||||
count = (int)Math.Min(count, _length - _pos);
|
||||
Marshal.Copy(Z.SS(_ptr + _pos), buffer, 0, count);
|
||||
_pos += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
long newpos;
|
||||
switch (origin)
|
||||
{
|
||||
default:
|
||||
case SeekOrigin.Begin:
|
||||
newpos = 0;
|
||||
break;
|
||||
case SeekOrigin.Current:
|
||||
newpos = _pos + offset;
|
||||
break;
|
||||
case SeekOrigin.End:
|
||||
newpos = _length + offset;
|
||||
break;
|
||||
}
|
||||
Position = newpos;
|
||||
return newpos;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (!_writable)
|
||||
throw new InvalidOperationException();
|
||||
if (count < 0 || count > buffer.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
EnsureNotDisposed();
|
||||
count = (int)Math.Min(count, _length - _pos);
|
||||
Marshal.Copy(buffer, 0, Z.SS(_ptr + _pos), count);
|
||||
_pos += count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !MONO
|
||||
private static class Kernel32
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue