#region Copyright 2010-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace CSharpTest.Net.IO
{
/// A stream that marshals bytes from unmanaged memory
public class MarshallingStream : BaseStream
{
readonly IntPtr _ptrBytes;
readonly bool _readOnly;
readonly long _length;
long _position;
/// Constructs a stream that marshals bytes from unmanaged memory
public MarshallingStream(IntPtr ptrBytes, bool readOnly, int start, int length)
{
_ptrBytes = start == 0 ? ptrBytes : new IntPtr(ptrBytes.ToInt64() + start);
_readOnly = readOnly;
_length = length;
_position = 0;
}
/// Constructs a stream that marshals bytes from unmanaged memory
public MarshallingStream(IntPtr ptrBytes, bool readOnly, int length)
: this(ptrBytes, readOnly, 0, length)
{ }
///
/// Releases the unmanaged resources used by the and optionally releases the managed resources.
///
protected override void Dispose(bool disposing)
{
_position = -1;
base.Dispose(disposing);
}
///
/// When overridden in a derived class, gets a value indicating whether the current stream supports reading.
///
public override bool CanRead { get { return true; } }
///
/// When overridden in a derived class, gets a value indicating whether the current stream supports seeking.
///
public override bool CanSeek { get { return true; } }
///
/// When overridden in a derived class, gets a value indicating whether the current stream supports writing.
///
public override bool CanWrite { get { return !_readOnly; } }
///
/// When overridden in a derived class, gets the length in bytes of the stream.
///
public override long Length
{
get
{
CheckDisposed();
return _length;
}
}
///
/// When overridden in a derived class, gets or sets the position within the current stream.
///
public override long Position
{
get
{
CheckDisposed();
return _position;
}
set
{
CheckDisposed();
_position = Check.InRange(value, 0, _length);
}
}
///
/// When overridden in a derived class, sets the position within the current stream.
///
public override long Seek(long offset, SeekOrigin origin)
{
CheckDisposed();
if (origin == SeekOrigin.Current) offset = _position + offset;
else if (origin == SeekOrigin.End) offset = _length + offset;
return this.Position = offset;
}
///
/// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
///
public override int Read(byte[] buffer, int offset, int count)
{
CheckDisposed();
long bytesAvail = _length - _position;
count = (int)Math.Min(count, bytesAvail);
if (count <= 0) return 0;
IntPtr pOffset = new IntPtr(_ptrBytes.ToInt64() + _position);
Marshal.Copy(pOffset, buffer, offset, count);
_position += count;
return count;
}
///
/// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
///
public override void Write(byte[] buffer, int offset, int count)
{
CheckDisposed();
Check.Assert(CanWrite);
long bytesAvail = _length - _position;
Check.InRange(count, 0, bytesAvail);
IntPtr pOffset = new IntPtr(_ptrBytes.ToInt64() + _position);
Marshal.Copy(buffer, offset, pOffset, count);
_position += count;
}
///
/// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
///
public override int ReadByte()
{
byte[] bytes = new byte[1];
return Read(bytes, 0, 1) == 1 ? bytes[0] : -1;
}
///
/// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
///
public override void WriteByte(byte value)
{
Write(new byte[] { value }, 0, 1);
}
private void CheckDisposed() { Check.Assert(_position >= 0, DisposedException); }
private Exception DisposedException() { return new ObjectDisposedException(this.GetType().FullName); }
}
}