2007-06-13 19:39:38 +00:00
|
|
|
|
2007-06-14 23:31:57 +00:00
|
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
|
2007-06-13 19:39:38 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
|
|
* This program is released under GNU General Public License
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2007-06-14 23:31:57 +00:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Namespaces
|
|
|
|
|
2007-06-13 19:39:38 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Globalization;
|
|
|
|
using System.Text;
|
|
|
|
using System.IO;
|
|
|
|
|
2007-06-14 23:31:57 +00:00
|
|
|
#endregion
|
|
|
|
|
2007-06-13 19:39:38 +00:00
|
|
|
namespace CodeImp.DoomBuilder.IO
|
|
|
|
{
|
|
|
|
internal class ClippedStream : Stream
|
|
|
|
{
|
|
|
|
#region ================== Variables
|
|
|
|
|
|
|
|
// Base stream
|
|
|
|
private Stream basestream;
|
|
|
|
|
|
|
|
// Data limit
|
|
|
|
private int offset;
|
|
|
|
private int length;
|
|
|
|
private long position;
|
|
|
|
|
|
|
|
// Disposing
|
|
|
|
private bool isdisposed = false;
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Properties
|
|
|
|
|
|
|
|
public override long Length { get { return length; } }
|
|
|
|
public override long Position { get { return position; } set { this.Seek(value, SeekOrigin.Begin); } }
|
|
|
|
public override bool CanRead { get { return basestream.CanRead; } }
|
|
|
|
public override bool CanSeek { get { return basestream.CanSeek; } }
|
|
|
|
public override bool CanWrite { get { return basestream.CanWrite; } }
|
|
|
|
public bool IsDisposed { get { return isdisposed; } }
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
public ClippedStream(Stream basestream, int offset, int length)
|
|
|
|
{
|
|
|
|
// Can only create from a stream that can seek
|
|
|
|
if(!basestream.CanSeek) throw new ArgumentException("ClippedStream can only be created with a Stream that allows Seeking.");
|
|
|
|
|
|
|
|
// Initialize
|
|
|
|
this.basestream = basestream;
|
|
|
|
this.position = 0;
|
|
|
|
this.offset = offset;
|
|
|
|
this.length = length;
|
|
|
|
|
|
|
|
// We have no destructor
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Diposer
|
|
|
|
public new void Dispose()
|
|
|
|
{
|
|
|
|
// Not already disposed?
|
|
|
|
if(!isdisposed)
|
|
|
|
{
|
2007-06-16 19:53:51 +00:00
|
|
|
// Already set isdisposed to prevent recursion
|
|
|
|
isdisposed = true;
|
|
|
|
|
2007-06-13 19:39:38 +00:00
|
|
|
// Clean up
|
|
|
|
basestream = null;
|
|
|
|
|
|
|
|
// Dispose base
|
|
|
|
base.Dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Methods
|
|
|
|
|
|
|
|
// This flushes the written changes
|
|
|
|
public override void Flush()
|
|
|
|
{
|
|
|
|
// Flush base stream
|
|
|
|
basestream.Flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This reads from the stream
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-06-24 18:56:43 +00:00
|
|
|
if((this.position + count) > (this.length + 1))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to read outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek if needed
|
|
|
|
if(basestream.Position != (this.offset + this.position))
|
|
|
|
basestream.Seek(this.offset + this.position, SeekOrigin.Begin);
|
|
|
|
|
|
|
|
// Read from base stream
|
2007-06-24 18:56:43 +00:00
|
|
|
position += count;
|
2007-06-13 19:39:38 +00:00
|
|
|
return basestream.Read(buffer, offset, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This writes to the stream
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-06-24 18:56:43 +00:00
|
|
|
if((this.position + count) > (this.length + 1))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to write outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek if needed
|
|
|
|
if(basestream.Position != (this.offset + this.position))
|
|
|
|
basestream.Seek(this.offset + this.position, SeekOrigin.Begin);
|
|
|
|
|
|
|
|
// Read from base stream
|
2007-06-24 18:56:43 +00:00
|
|
|
position += count;
|
2007-06-13 19:39:38 +00:00
|
|
|
basestream.Write(buffer, offset, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Seek within clipped buffer
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
|
|
{
|
|
|
|
// Seeking from beginning
|
|
|
|
if(origin == SeekOrigin.Begin)
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-10-07 20:43:05 +00:00
|
|
|
if((offset > this.length) || (offset < 0))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to seek outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek
|
2007-06-24 18:56:43 +00:00
|
|
|
position = basestream.Seek(this.offset + offset, SeekOrigin.Begin) - this.offset;
|
2007-06-13 19:39:38 +00:00
|
|
|
}
|
|
|
|
// Seeking from current position
|
|
|
|
else if(origin == SeekOrigin.Current)
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-10-07 20:43:05 +00:00
|
|
|
if((this.position + offset > this.length) || (this.position + offset < 0))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to seek outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek
|
2007-06-24 18:56:43 +00:00
|
|
|
position = basestream.Seek(this.offset + this.position + offset, SeekOrigin.Begin) - this.offset;
|
2007-06-13 19:39:38 +00:00
|
|
|
}
|
|
|
|
// Seeking from end
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
|
|
|
if((offset > 0) || (this.length + offset < 0))
|
|
|
|
throw new ArgumentException("Attempted to seek outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek
|
2007-06-24 18:56:43 +00:00
|
|
|
position = basestream.Seek(this.offset + this.length + offset, SeekOrigin.Begin) - this.offset;
|
2007-06-13 19:39:38 +00:00
|
|
|
}
|
2007-06-24 18:56:43 +00:00
|
|
|
|
|
|
|
// Return new position
|
|
|
|
return position;
|
2007-06-13 19:39:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Change the length of the steam
|
|
|
|
public override void SetLength(long value)
|
|
|
|
{
|
|
|
|
// Not supported
|
|
|
|
throw new NotSupportedException("This operation is not supported.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Asynchronous read from stream
|
|
|
|
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-06-24 18:56:43 +00:00
|
|
|
if((this.position + count) > (this.length + 1))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to read outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek if needed
|
|
|
|
if(basestream.Position != (this.offset + this.position))
|
|
|
|
basestream.Seek(this.offset + this.position, SeekOrigin.Begin);
|
|
|
|
|
|
|
|
// Read
|
2007-06-24 18:56:43 +00:00
|
|
|
position += count;
|
2007-06-13 19:39:38 +00:00
|
|
|
return base.BeginRead(buffer, offset, count, callback, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Asynchronous write to stream
|
|
|
|
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-06-24 18:56:43 +00:00
|
|
|
if((this.position + count) > (this.length + 1))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to write outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek if needed
|
|
|
|
if(basestream.Position != (this.offset + this.position))
|
|
|
|
basestream.Seek(this.offset + this.position, SeekOrigin.Begin);
|
|
|
|
|
|
|
|
// Write
|
2007-06-24 18:56:43 +00:00
|
|
|
position += count;
|
2007-06-13 19:39:38 +00:00
|
|
|
return base.BeginWrite(buffer, offset, count, callback, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This closes the stream
|
|
|
|
public override void Close()
|
|
|
|
{
|
2007-06-16 19:53:51 +00:00
|
|
|
basestream = null;
|
2007-06-13 19:39:38 +00:00
|
|
|
base.Close();
|
|
|
|
this.Dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This reads a single byte from the stream
|
|
|
|
public override int ReadByte()
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-06-24 18:56:43 +00:00
|
|
|
if((this.position + 1) > (this.length + 1))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to read outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek if needed
|
|
|
|
if(basestream.Position != (this.offset + this.position))
|
|
|
|
basestream.Seek(this.offset + this.position, SeekOrigin.Begin);
|
|
|
|
|
|
|
|
// Read from base stream
|
2007-06-24 18:56:43 +00:00
|
|
|
position++;
|
2007-06-13 19:39:38 +00:00
|
|
|
return basestream.ReadByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This writes a single byte to the stream
|
|
|
|
public override void WriteByte(byte value)
|
|
|
|
{
|
|
|
|
// Check if this exceeds limits
|
2007-06-24 18:56:43 +00:00
|
|
|
if((this.position + 1) > (this.length + 1))
|
2007-06-13 19:39:38 +00:00
|
|
|
throw new ArgumentException("Attempted to write outside the range of the stream.");
|
|
|
|
|
|
|
|
// Seek if needed
|
|
|
|
if(basestream.Position != (this.offset + this.position))
|
|
|
|
basestream.Seek(this.offset + this.position, SeekOrigin.Begin);
|
|
|
|
|
|
|
|
// Read from base stream
|
2007-06-24 18:56:43 +00:00
|
|
|
position++;
|
2007-06-13 19:39:38 +00:00
|
|
|
basestream.WriteByte(value);
|
|
|
|
}
|
|
|
|
|
2007-06-24 18:56:43 +00:00
|
|
|
// This returns all the bytes in the stream
|
|
|
|
public byte[] ReadAllBytes()
|
|
|
|
{
|
|
|
|
byte[] bytes = new byte[length];
|
|
|
|
Seek(0, SeekOrigin.Begin);
|
|
|
|
Read(bytes, 0, length);
|
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
2007-06-13 19:39:38 +00:00
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|