Skip to content

Instantly share code, notes, and snippets.

@LordJZ
Created May 28, 2011 19:20
Show Gist options
  • Save LordJZ/997133 to your computer and use it in GitHub Desktop.
Save LordJZ/997133 to your computer and use it in GitHub Desktop.
StreamHandler
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace WhatIf
{
/// <summary>
/// A class to manipulate data inside a stream.
/// </summary>
public class StreamHandler : IDisposable
{
private static IEnumerable<byte> m_newLineBytes = Environment.NewLine.ToCharArray().Select(c => (byte)c);
#region Properties
private Encoding m_encoding;
private Encoder m_encoder;
private Decoder m_decoder;
private bool m_2BytesPerChar;
private byte[] m_buffer;
private byte[] m_charBytes;
private char[] m_singleChar;
/// <summary>
/// Holds the underlying stream.
/// </summary>
protected Stream m_stream;
/// <summary>
/// Gets the underlying stream of the <see cref="WhatIf.StreamHandler"/>.
/// </summary>
public Stream BaseStream
{
get
{
this.Flush();
return this.m_stream;
}
}
/// <summary>
/// Gets the number of bytes from the current position of the stream to the end of the stream.
/// </summary>
/// <exception cref="System.ObjectDisposedException">
/// Methods were called after the stream was closed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public long RemainingLength
{
get
{
this.Flush();
return m_stream.Length - m_stream.Position;
}
}
/// <summary>
/// Gets the value indicating whether the current stream was fully read and no bytes can be read currently.
/// </summary>
/// <exception cref="System.ObjectDisposedException">
/// Methods were called after the stream was closed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public bool IsRead
{
get
{
return RemainingLength == 0;
}
}
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WhatIf.StreamHandler"/> class
/// based on the supplied stream and a specific character encoding.
/// </summary>
/// <param name="output">The output stream.</param>
/// <param name="encoding">The character encoding.</param>
/// <exception cref="System.ArgumentException">
/// The stream does not support writing, or the stream is already closed.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// output or encoding is null.
/// </exception>
public StreamHandler(Stream output, Encoding encoding)
{
if (output == null)
throw new ArgumentNullException("output");
if (encoding == null)
throw new ArgumentNullException("encoding");
this.m_stream = output;
this.m_buffer = new byte[0x10];
this.m_encoding = encoding;
this.m_encoder = this.m_encoding.GetEncoder();
this.m_decoder = this.m_encoding.GetDecoder();
this.m_2BytesPerChar = encoding is UnicodeEncoding;
}
/// <summary>
/// Initializes a new instance of the <see cref="WhatIf.StreamHandler"/> class
/// based on the supplied stream and using UTF-8 as the encoding for strings.
/// </summary>
/// <param name="output">The output stream.</param>
/// <exception cref="System.ArgumentException">
/// The stream does not support writing, or the stream is already closed.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// output is null.
/// </exception>
public StreamHandler(Stream output)
: this(output, new UTF8Encoding(false, true))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WhatIf.StreamHandler"/> class
/// using a new resizeable <see cref="System.IO.MemoryStream"/> and using UTF-8 as the encoding for strings.
/// </summary>
public StreamHandler()
: this(new MemoryStream(), new UTF8Encoding(false, true))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WhatIf.StreamHandler"/> class
/// using a new <see cref="System.IO.FileStream"/> in reading or writing mode
/// and using UTF-8 as the encoding for strings.
/// </summary>
/// <param name="path">
/// Name of the file to open.
/// </param>
public StreamHandler(string path)
: this(new FileStream(path, FileMode.OpenOrCreate), new UTF8Encoding(false, true))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WhatIf.StreamHandler"/> class
/// using a new <see cref="System.IO.FileStream"/> in the specified mode
/// and using UTF-8 as the encoding for strings.
/// </summary>
/// <param name="path">
/// A relative or absolute path for the file that the current
/// <see cref="WhatIf.StreamHandler"/> object will encapsulate.
/// </param>
/// <param name="mode">
/// A <see cref="System.IO.FileMode"/> constant that determines how to open or create the file.
/// </param>
public StreamHandler(string path, FileMode mode)
: this(new FileStream(path, mode), new UTF8Encoding(false, true))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WhatIf.StreamHandler"/> class
/// using a new <see cref="System.IO.FileStream"/> in the specified mode
/// and using the specified encoding for strings.
/// </summary>
/// <param name="path">
/// A relative or absolute path for the file that the current
/// <see cref="WhatIf.StreamHandler"/> object will encapsulate.
/// </param>
/// <param name="mode">
/// A <see cref="System.IO.FileMode"/> constant that determines how to open or create the file.
/// </param>
/// <param name="encoding">
/// The character encoding.
/// </param>
public StreamHandler(string path, FileMode mode, Encoding encoding)
: this(new FileStream(path, mode), encoding)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WhatIf.StreamHandler"/> class
/// based on the supplied byte array.
/// </summary>
/// <param name="buffer">The byte array containing data to be read or to be written into.</param>
/// <exception cref="System.ArgumentNullException">
/// buffer is null.
/// </exception>
public StreamHandler(byte[] buffer)
{
this.m_stream = new MemoryStream(buffer);
this.m_buffer = new byte[16];
this.m_encoding = new UTF8Encoding(false, true);
this.m_encoder = this.m_encoding.GetEncoder();
this.m_decoder = this.m_encoding.GetDecoder();
this.m_2BytesPerChar = false;
}
#endregion
#region Misc Methods
/// <summary>
/// Closes the current <see cref="WhatIf.StreamHandler"/> and the underlying stream.
/// </summary>
public virtual void Close()
{
this.Dispose(true);
}
/// <summary>
/// Releases the unmanaged resources used by the <see cref="WhatIf.StreamHandler"/>
/// and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// true to release both managed and unmanaged resources;
/// false to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
this.m_stream.Close();
}
/// <summary>
/// Releases all resources used by the current instance of the <see cref="WhatIf.StreamHandler"/> class.
/// </summary>
void IDisposable.Dispose()
{
this.Dispose(true);
}
/// <summary>
/// Clears all buffers for the current writer and causes any buffered
/// data to be written to the underlying device.
/// </summary>
public void Flush()
{
this.m_stream.Flush();
}
/// <summary>
/// Gets the value indicating whether you can read the provided number of bytes.
/// </summary>
/// <param name="bytes">Number of bytes to read.</param>
/// <returns>true if the provided number of bytes can be read; otherwise, false.</returns>
/// <exception cref="System.ObjectDisposedException">
/// Methods were called after the stream was closed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ArgumentException">
/// bytes is negative.
/// </exception>
public bool CanRead(long bytes)
{
if (bytes < 0)
throw new ArgumentException("A non-negative number is required.", "bytes");
return RemainingLength >= bytes;
}
/// <summary>
/// Skips a number of bytes from the current stream.
/// </summary>
/// <param name="bytes">The number of bytes to skip.</param>
/// <returns>true if the provided number of bytes can be read; otherwise, false.</returns>
/// <exception cref="System.ObjectDisposedException">
/// Methods were called after the stream was closed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ArgumentException">
/// bytes is negative.
/// </exception>
/// <exception cref="System.IO.EndOfStreamException">
/// End of stream is reached.
/// </exception>
public void Skip(long bytes)
{
if (!CanRead(bytes))
throw new EndOfStreamException();
this.m_stream.Position += bytes;
}
#endregion
#region Write Methods
/// <summary>
/// Writes a one-byte Boolean value to the current stream, with 0 representing
/// false and 1 representing true.
/// </summary>
/// <param name="value">
/// The Boolean value to write (0 or 1).
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteBool(bool value)
{
this.m_buffer[0] = value ? ((byte)1) : ((byte)0);
this.m_stream.Write(this.m_buffer, 0, 1);
return this;
}
/// <summary>
/// Writes an unsigned byte to the current stream and advances the stream position
/// by one byte.
/// </summary>
/// <param name="value">
/// The unsigned byte to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteByte(byte value)
{
this.m_stream.WriteByte(value);
return this;
}
/// <summary>
/// Writes a byte array to the underlying stream.
/// </summary>
/// <param name="buffer">
/// A byte array containing the data to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// buffer is null.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteBytes(byte[] buffer)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
this.m_stream.Write(buffer, 0, buffer.Length);
return this;
}
/// <summary>
/// Writes a Unicode character to the current stream and advances the current
/// position of the stream in accordance with the Encoding used and the specific
/// characters being written to the stream.
/// </summary>
/// <param name="ch">
/// The non-surrogate, Unicode character to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.ArgumentException">
/// ch is a single surrogate character.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public unsafe StreamHandler WriteChar(char ch)
{
if (char.IsSurrogate(ch))
throw new ArgumentException("Single surrogate characters are not allowed.");
int count = 0;
fixed (byte* numRef = this.m_buffer)
{
count = this.m_encoder.GetBytes(&ch, 1, numRef, 16, true);
}
this.m_stream.Write(this.m_buffer, 0, count);
return this;
}
/// <summary>
/// Writes a character array to the current stream and advances the current position
/// of the stream in accordance with the Encoding used and the specific characters
/// being written to the stream.
/// </summary>
/// <param name="chars">
/// A character array containing the data to write.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// chars is null.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteChars(char[] chars)
{
if (chars == null)
throw new ArgumentNullException("chars");
byte[] buffer = this.m_encoding.GetBytes(chars, 0, chars.Length);
this.m_stream.Write(buffer, 0, buffer.Length);
return this;
}
/// <summary>
/// Writes a decimal value to the current stream and advances the stream position
/// by sixteen bytes.
/// </summary>
/// <param name="value">
/// The decimal value to write.
/// </param>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteDecimal(decimal value)
{
int[] bits = decimal.GetBits(value);
this.WriteInt32(bits[0]);
this.WriteInt32(bits[1]);
this.WriteInt32(bits[2]);
this.WriteInt32(bits[3]);
return this;
}
/// <summary>
/// Writes an eight-byte floating-point value to the current stream and advances
/// the stream position by eight bytes.
/// </summary>
/// <param name="value">
/// The eight-byte floating-point value to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public unsafe StreamHandler WriteDouble(double value)
{
ulong num = *(ulong*)&value;
this.m_buffer[0] = (byte)num;
this.m_buffer[1] = (byte)(num >> 8);
this.m_buffer[2] = (byte)(num >> 16);
this.m_buffer[3] = (byte)(num >> 24);
this.m_buffer[4] = (byte)(num >> 32);
this.m_buffer[5] = (byte)(num >> 40);
this.m_buffer[6] = (byte)(num >> 48);
this.m_buffer[7] = (byte)(num >> 56);
this.m_stream.Write(this.m_buffer, 0, 8);
return this;
}
/// <summary>
/// Writes a four-byte floating-point value to the current stream and advances
/// the stream position by four bytes.
/// </summary>
/// <param name="value">
/// The four-byte floating-point value to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public unsafe StreamHandler WriteFloat(float value)
{
uint num = *((uint*)&value);
this.m_buffer[0] = (byte)num;
this.m_buffer[1] = (byte)(num >> 8);
this.m_buffer[2] = (byte)(num >> 16);
this.m_buffer[3] = (byte)(num >> 24);
this.m_stream.Write(this.m_buffer, 0, 4);
return this;
}
/// <summary>
/// Writes a four-byte signed integer to the current stream and advances the
/// stream position by four bytes.
/// </summary>
/// <param name="value">
/// The four-byte signed integer to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteInt32(int value)
{
this.m_buffer[0] = (byte)value;
this.m_buffer[1] = (byte)(value >> 8);
this.m_buffer[2] = (byte)(value >> 16);
this.m_buffer[3] = (byte)(value >> 24);
this.m_stream.Write(this.m_buffer, 0, 4);
return this;
}
/// <summary>
/// Writes an eight-byte signed integer to the current stream and advances the
/// stream position by eight bytes.
/// </summary>
/// <param name="value">
/// The eight-byte signed integer to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteInt64(long value)
{
this.m_buffer[0] = (byte)value;
this.m_buffer[1] = (byte)(value >> 8);
this.m_buffer[2] = (byte)(value >> 0x10);
this.m_buffer[3] = (byte)(value >> 0x18);
this.m_buffer[4] = (byte)(value >> 0x20);
this.m_buffer[5] = (byte)(value >> 40);
this.m_buffer[6] = (byte)(value >> 0x30);
this.m_buffer[7] = (byte)(value >> 0x38);
this.m_stream.Write(this.m_buffer, 0, 8);
return this;
}
/// <summary>
/// Writes a signed byte to the current stream and advances the stream position
/// by one byte.
/// </summary>
/// <param name="value">
/// The signed byte to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteSByte(sbyte value)
{
this.m_stream.WriteByte((byte)value);
return this;
}
/// <summary>
/// Writes a two-byte signed integer to the current stream and advances the stream
/// position by two bytes.
/// </summary>
/// <param name="value">
/// The two-byte signed integer to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteInt16(short value)
{
this.m_buffer[0] = (byte)value;
this.m_buffer[1] = (byte)(value >> 8);
this.m_stream.Write(this.m_buffer, 0, 2);
return this;
}
/// <summary>
/// Writes a null-terminated string to the current stream in the current encoding of
/// the <see cref="WhatIf.StreamHandler"/>, and advances the current position of the stream
/// by the length of the string plus one.
/// </summary>
/// <param name="value">
/// The string to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// value is null.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.ArgumentException">
/// value contains a null character before a not-null character.
/// </exception>
/// <returns>
/// The current instance of <see cref="WhatIf.StreamHandler"/>.
/// </returns>
public StreamHandler WriteCString(string value)
{
if (value == null)
throw new ArgumentNullException("value");
value = value.TrimEnd((char)0);
if (value.IndexOf((char)0) != -1)
throw new ArgumentException("value");
char[] chars = value.ToCharArray();
byte[] buffer = this.m_encoding.GetBytes(chars, 0, chars.Length);
this.m_stream.Write(buffer, 0, buffer.Length);
this.m_stream.WriteByte(0);
return this;
}
/// <summary>
/// Writes a four-byte unsigned integer to the current stream and advances the
/// stream position by four bytes.
/// </summary>
/// <param name="value">
/// The four-byte unsigned integer to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteUInt32(uint value)
{
this.m_buffer[0] = (byte)value;
this.m_buffer[1] = (byte)(value >> 8);
this.m_buffer[2] = (byte)(value >> 0x10);
this.m_buffer[3] = (byte)(value >> 0x18);
this.m_stream.Write(this.m_buffer, 0, 4);
return this;
}
/// <summary>
/// Writes an eight-byte unsigned integer to the current stream and advances
/// the stream position by eight bytes.
/// </summary>
/// <param name="value">
/// The eight-byte unsigned integer to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteUInt64(ulong value)
{
this.m_buffer[0] = (byte)value;
this.m_buffer[1] = (byte)(value >> 8);
this.m_buffer[2] = (byte)(value >> 0x10);
this.m_buffer[3] = (byte)(value >> 0x18);
this.m_buffer[4] = (byte)(value >> 0x20);
this.m_buffer[5] = (byte)(value >> 40);
this.m_buffer[6] = (byte)(value >> 0x30);
this.m_buffer[7] = (byte)(value >> 0x38);
this.m_stream.Write(this.m_buffer, 0, 8);
return this;
}
/// <summary>
/// Writes a two-byte unsigned integer to the current stream and advances the
/// stream position by two bytes.
/// </summary>
/// <param name="value">
/// The two-byte unsigned integer to write.
/// </param>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteUInt16(ushort value)
{
this.m_buffer[0] = (byte)value;
this.m_buffer[1] = (byte)(value >> 8);
this.m_stream.Write(this.m_buffer, 0, 2);
return this;
}
/// <summary>
/// Writes a region of a byte array to the current stream.
/// </summary>
/// <param name="buffer">
/// A byte array containing the data to write.
/// </param>
/// <param name="index">
/// The starting point in buffer at which to begin writing.
/// </param>
/// <param name="count">
/// The number of bytes to write.
/// </param>
/// <exception cref="System.ArgumentException">
/// The buffer length minus index is less than count.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// buffer is null.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// index or count is negative.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteBytes(byte[] buffer, int index, int count)
{
this.m_stream.Write(buffer, index, count);
return this;
}
/// <summary>
/// Writes a section of a character array to the current stream, and advances
/// the current position of the stream in accordance with the Encoding used and
/// perhaps the specific characters being written to the stream.
/// </summary>
/// <param name="chars">
/// A character array containing the data to write.
/// </param>
/// <param name="index">
/// The starting point in buffer from which to begin writing.
/// </param>
/// <param name="count">
/// The number of characters to write.
/// </param>
/// <exception cref="System.ArgumentException">
/// The buffer length minus index is less than count.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// chars is null.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// index or count is negative.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteChars(char[] chars, int index, int count)
{
byte[] buffer = this.m_encoding.GetBytes(chars, index, count);
this.m_stream.Write(buffer, 0, buffer.Length);
return this;
}
/// <summary>
/// Writes a byte representation of a structure to the current stream.
/// </summary>
/// <typeparam name="T">
/// Type of a structure.
/// </typeparam>
/// <param name="structure">
/// A structure to write into the current stream.
/// </param>
/// <returns>The current instance of <see cref="WhatIf.StreamHandler"/>.</returns>
public StreamHandler WriteStruct<T>(T structure) where T : struct
{
lock (StructHelper<T>.SyncRoot)
{
Marshal.StructureToPtr(structure, StructHelper<T>.UnmanagedDataBank, false);
Marshal.Copy(StructHelper<T>.UnmanagedDataBank, StructHelper<T>.ManagedDataBank, 0, StructHelper<T>.Size);
WriteBytes(StructHelper<T>.ManagedDataBank);
}
return this;
}
#endregion
#region Read Methods
private int InternalReadOneChar()
{
long position = 0L;
int num = 0;
int byteCount = 0;
if (this.m_stream.CanSeek)
position = this.m_stream.Position;
if (this.m_charBytes == null)
this.m_charBytes = new byte[0x80];
if (this.m_singleChar == null)
this.m_singleChar = new char[1];
while (num == 0)
{
byteCount = this.m_2BytesPerChar ? 2 : 1;
int num4 = this.m_stream.ReadByte();
this.m_charBytes[0] = (byte)num4;
if (num4 == -1)
byteCount = 0;
if (byteCount == 2)
{
num4 = this.m_stream.ReadByte();
this.m_charBytes[1] = (byte)num4;
if (num4 == -1)
byteCount = 1;
}
if (byteCount == 0)
return -1;
try
{
num = this.m_decoder.GetChars(this.m_charBytes, 0, byteCount, this.m_singleChar, 0);
continue;
}
catch
{
if (this.m_stream.CanSeek)
this.m_stream.Seek(position - this.m_stream.Position, SeekOrigin.Current);
throw;
}
}
if (num == 0)
return -1;
return this.m_singleChar[0];
}
private void FillBuffer(int numBytes)
{
int offset = 0;
int num2 = 0;
if (this.m_stream == null)
throw new IOException();
if (numBytes == 1)
{
num2 = this.m_stream.ReadByte();
if (num2 == -1)
throw new IOException();
this.m_buffer[0] = (byte)num2;
}
else
{
do
{
num2 = this.m_stream.Read(this.m_buffer, offset, numBytes - offset);
if (num2 == 0)
throw new IOException();
offset += num2;
}
while (offset < numBytes);
}
}
/// <summary>
/// Returns the next available character and does not advance the byte or character
/// position.
/// </summary>
/// <returns>
/// The next available character, or -1 if no more characters are available or
/// the stream does not support seeking.
/// </returns>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public int PeekChar()
{
if (this.m_stream == null)
throw new IOException();
if (!this.m_stream.CanSeek)
return -1;
long position = this.m_stream.Position;
int num2 = this.Read();
this.m_stream.Position = position;
return num2;
}
/// <summary>
/// Reads characters from the underlying stream and advances the current position
/// of the stream in accordance with the Encoding used and the specific character
/// being read from the stream.
/// </summary>
/// <returns>
/// The next character from the input stream, or -1 if no characters are currently
/// available.
/// </returns>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
public int Read()
{
if (this.m_stream == null)
throw new IOException();
return this.InternalReadOneChar();
}
/// <summary>
/// Reads the specified number of bytes from the stream, starting from a specified
/// point in the byte array.
/// </summary>
/// <param name="buffer">
/// The buffer to read data into.
/// </param>
/// <param name="offset">
/// The starting point in the buffer at which to begin reading into the buffer.
/// </param>
/// <param name="count">
/// The number of bytes to read.
/// </param>
/// <returns>
/// The number of bytes read into buffer. This might be less than the number
/// of bytes requested if that many bytes are not available, or it might be zero
/// if the end of the stream is reached.
/// </returns>
/// <exception cref="System.ArgumentException">
/// The sum of offset and count is larger than the buffer length.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// buffer is null.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// offset or count is negative.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support reading.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// Methods were called after the stream was closed.
/// </exception>
public int Read(byte[] buffer, int offset, int count)
{
return this.m_stream.Read(buffer, offset, count);
}
/// <summary>
/// Reads the specified number of characters from the stream, starting from a
/// specified point in the character array.
/// </summary>
/// <param name="buffer">
/// The buffer to read data into.
/// </param>
/// <param name="index">
/// The starting point in the buffer at which to begin reading into the buffer.
/// </param>
/// <param name="count">
/// The number of characters to read.
/// </param>
/// <returns>
/// The total number of characters read into the buffer. This might be less than
/// the number of characters requested if that many characters are not currently
/// available, or it might be zero if the end of the stream is reached.
/// </returns>
/// <exception cref="System.ArgumentException">
/// The buffer length minus index is less than count. -or-The number of decoded
/// characters to read is greater than count. This can happen if a Unicode decoder
/// returns fallback characters or a surrogate pair.
/// </exception>
/// <exception cref="System.ArgumentNullException">
/// buffer is null.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// index or count is negative.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public int Read(char[] buffer, int index, int count)
{
if (buffer == null)
throw new ArgumentNullException("buffer");
if (index < 0)
throw new ArgumentOutOfRangeException("index", "A non-negative number is required.");
if (count < 0)
throw new ArgumentOutOfRangeException("count", "A non-negative number is required.");
if ((buffer.Length - index) < count)
throw new ArgumentException("Invalid index and count arguments.");
if (this.m_stream == null)
throw new IOException();
char[] buf = this.ReadChars(count);
Array.Copy(buf, 0, buffer, index, buf.Length);
return buf.Length;
}
/// <summary>
/// Reads a Boolean value from the current stream and advances the current position
/// of the stream by one byte.
/// </summary>
/// <returns>
/// true if the byte is nonzero; otherwise, false.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public bool ReadBoolean()
{
this.FillBuffer(1);
return (this.m_buffer[0] != 0);
}
/// <summary>
/// Reads the next byte from the current stream and advances the current position
/// of the stream by one byte.
/// </summary>
/// <returns>
/// The next byte read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public byte ReadByte()
{
if (this.m_stream == null)
throw new ObjectDisposedException("m_stream");
int num = this.m_stream.ReadByte();
if (num == -1)
throw new EndOfStreamException();
return (byte)num;
}
/// <summary>
/// Reads the specified number of bytes from the current stream into a byte array
/// and advances the current position by that number of bytes.
/// </summary>
/// <param name="count">
/// The number of bytes to read.
/// </param>
/// <returns>
/// A byte array containing data read from the underlying stream. This might
/// be less than the number of bytes requested if the end of the stream is reached.
/// </returns>
/// <exception cref="System.ArgumentException">
/// The number of decoded characters to read is greater than count. This can
/// happen if a Unicode decoder returns fallback characters or a surrogate pair.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// count is negative.
/// </exception>
public byte[] ReadBytes(int count)
{
if (count < 0)
throw new ArgumentOutOfRangeException("count", "A non-negative number is required.");
if (this.m_stream == null)
throw new ObjectDisposedException("m_stream");
byte[] buffer = new byte[count];
this.m_stream.Read(buffer, 0, count);
return buffer;
}
/// <summary>
/// Reads the next character from the current stream and advances the current
/// position of the stream in accordance with the Encoding used and the specific
/// character being read from the stream.
/// </summary>
/// <returns>
/// A character read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ArgumentException">
/// A surrogate character was read.
/// </exception>
public char ReadChar()
{
int num = this.Read();
if (num == -1)
throw new EndOfStreamException();
return (char)num;
}
/// <summary>
/// Reads the specified number of characters from the current stream, returns
/// the data in a character array, and advances the current position in accordance
/// with the Encoding used and the specific character being read from the stream.
/// </summary>
/// <param name="count">
/// The number of characters to read.
/// </param>
/// <returns>
/// A character array containing data read from the underlying stream. This might
/// be less than the number of characters requested if the end of the stream
/// is reached.
/// </returns>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// count is negative.
/// </exception>
public char[] ReadChars(int count)
{
if (count < 0)
throw new ArgumentOutOfRangeException("count", "A non-negative number is required.");
if (this.m_stream == null)
throw new ObjectDisposedException("m_stream");
List<char> buffer = new List<char>(count);
for (int i = 0; i < count; ++i)
buffer.Add(this.ReadChar());
return buffer.ToArray();
}
/// <summary>
/// Reads a decimal value from the current stream and advances the current position
/// of the stream by sixteen bytes.
/// </summary>
/// <returns>
/// A decimal value read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public decimal ReadDecimal()
{
this.FillBuffer(16);
int lo = ((m_buffer[0] | (m_buffer[1] << 8)) | (m_buffer[2] << 16)) | (m_buffer[3] << 24);
int mid = ((m_buffer[4] | (m_buffer[5] << 8)) | (m_buffer[6] << 16)) | (m_buffer[7] << 24);
int hi = ((m_buffer[8] | (m_buffer[9] << 8)) | (m_buffer[10] << 16)) | (m_buffer[11] << 24);
return new decimal(new int[] { lo, mid, hi,
((m_buffer[12] | (m_buffer[13] << 8)) | (m_buffer[14] << 16)) | (m_buffer[15] << 24) });
}
/// <summary>
/// Reads an 8-byte floating point value from the current stream and advances
/// the current position of the stream by eight bytes.
/// </summary>
/// <returns>
/// An 8-byte floating point value read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public unsafe double ReadDouble()
{
this.FillBuffer(8);
uint num = (uint)(m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
uint num2 = (uint)(m_buffer[4] | (m_buffer[5] << 8) | (m_buffer[6] << 16) | (m_buffer[7] << 24));
ulong num3 = (num2 << 0x20) | num;
return *(((double*)&num3));
}
/// <summary>
/// Reads a 2-byte signed integer from the current stream and advances the current
/// position of the stream by two bytes.
/// </summary>
/// <returns>
/// A 2-byte signed integer read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public short ReadInt16()
{
this.FillBuffer(2);
return (short)(this.m_buffer[0] | (this.m_buffer[1] << 8));
}
/// <summary>
/// Reads a 4-byte signed integer from the current stream and advances the current
/// position of the stream by four bytes.
/// </summary>
/// <returns>
/// A 4-byte signed integer read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public int ReadInt32()
{
this.FillBuffer(4);
return (m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
}
/// <summary>
/// Reads an 8-byte signed integer from the current stream and advances the current
/// position of the stream by eight bytes.
/// </summary>
/// <returns>
/// An 8-byte signed integer read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public long ReadInt64()
{
this.FillBuffer(8);
uint num = (uint)(m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
uint num2 = (uint)(m_buffer[4] | (m_buffer[5] << 8) | (m_buffer[6] << 16) | (m_buffer[7] << 24));
return (long)((num2 << 0x20) | num);
}
/// <summary>
/// Reads a signed byte from this stream and advances the current position of
/// the stream by one byte.
/// </summary>
/// <returns>
/// A signed byte read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public sbyte ReadSByte()
{
this.FillBuffer(1);
return (sbyte)this.m_buffer[0];
}
/// <summary>
/// Reads a 4-byte floating point value from the current stream and advances
/// the current position of the stream by four bytes.
/// </summary>
/// <returns>
/// A 4-byte floating point value read from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public unsafe float ReadSingle()
{
this.FillBuffer(4);
uint num = (uint)(m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
return *(((float*)&num));
}
/// <summary>
/// Reads a null-terminated string from the current stream.
/// </summary>
/// <returns>
/// The string being read.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public string ReadCString()
{
const int allocationCount = 100;
long left = RemainingLength;
if (left == 0)
throw new EndOfStreamException();
var list = new List<byte>((int)Math.Min(left, allocationCount));
byte b;
bool caretReturn = false;
bool terminatorFound = false;
do
{
b = ReadByte();
switch (b)
{
case 0:
terminatorFound = true;
break;
case (byte)'\r':
caretReturn = true;
break;
case (byte)'\n':
if (list.Count == list.Capacity)
list.Capacity += allocationCount;
list.AddRange(m_newLineBytes);
caretReturn = false;
break;
default:
if (list.Count == list.Capacity)
list.Capacity += allocationCount;
if (caretReturn)
{
list.AddRange(m_newLineBytes);
caretReturn = false;
}
list.Add(b);
break;
}
} while (!terminatorFound && !IsRead);
return m_encoding.GetString(list.ToArray());
}
/// <summary>
/// Reads a 2-byte unsigned integer from the current stream using little-endian
/// encoding and advances the position of the stream by two bytes.
/// </summary>
/// <returns>
/// A 2-byte unsigned integer read from this stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public ushort ReadUInt16()
{
this.FillBuffer(2);
return (ushort)(this.m_buffer[0] | (this.m_buffer[1] << 8));
}
/// <summary>
/// Reads a 4-byte unsigned integer from the current stream and advances the
/// position of the stream by four bytes.
/// </summary>
/// <returns>
/// A 4-byte unsigned integer read from this stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
public uint ReadUInt32()
{
this.FillBuffer(4);
return (uint)(m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
}
/// <summary>
/// Reads an 8-byte unsigned integer from the current stream and advances the
/// position of the stream by eight bytes.
/// </summary>
/// <returns>
/// An 8-byte unsigned integer read from this stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
public ulong ReadUInt64()
{
this.FillBuffer(8);
uint num = (uint)(m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
uint num2 = (uint)(m_buffer[4] | (m_buffer[5] << 8) | (m_buffer[6] << 16) | (m_buffer[7] << 24));
return ((num2 << 0x20) | num);
}
/// <summary>
/// Reads all bytes from the current stream, not advancing the current position.
/// </summary>
/// <returns>
/// The byte array that contains all bytes from the current stream.
/// </returns>
/// <exception cref="System.IO.EndOfStreamException">
/// The end of the stream is reached.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurs.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream is closed.
/// </exception>
public byte[] ReadAllBytes()
{
long pos = this.m_stream.Position;
this.m_stream.Position = 0;
byte[] buffer = new byte[this.m_stream.Length];
this.m_stream.Read(buffer, 0, (int)this.m_stream.Length);
this.m_stream.Position = pos;
return buffer;
}
/// <summary>
/// Reads a structure from the current stream, advancing
/// the current position by the number of bytes in the structure.
/// </summary>
/// <typeparam name="T">
/// Type of the structure.
/// </typeparam>
/// <returns>
/// A structure read from the stream.
/// </returns>
public T ReadStruct<T>() where T : struct
{
lock (StructHelper<T>.SyncRoot)
{
m_stream.Read(StructHelper<T>.ManagedDataBank, 0, StructHelper<T>.Size);
Marshal.Copy(StructHelper<T>.ManagedDataBank, 0, StructHelper<T>.UnmanagedDataBank, StructHelper<T>.Size);
return (T)Marshal.PtrToStructure(StructHelper<T>.UnmanagedDataBank, typeof(T));
}
}
#endregion
#region DoAt Methods
/// <summary>
/// Runs the given function temporary setting the current stream's position to the specified value.
/// </summary>
/// <typeparam name="TArg">Type of the function argument.</typeparam>
/// <typeparam name="TResult">The return type of the function.</typeparam>
/// <param name="position">The position to run the function at.</param>
/// <param name="func">The function to run at the given position.</param>
/// <param name="arg">The argument passed to the function.</param>
/// <returns>The result of the function.</returns>
public TResult DoAt<TArg, TResult>(long position, Func<TArg, TResult> func, TArg arg)
{
long old_position = this.BaseStream.Position;
this.BaseStream.Position = position;
TResult result = func(arg);
this.BaseStream.Position = old_position;
return result;
}
/// <summary>
/// Runs the given function temporary setting the current stream's position to the specified value.
/// </summary>
/// <typeparam name="TResult">The return type of the function.</typeparam>
/// <param name="position">The position to run the function at.</param>
/// <param name="func">The function to run at the given position.</param>
/// <returns>The result of the function.</returns>
public TResult DoAt<TResult>(long position, Func<TResult> func)
{
long old_position = this.BaseStream.Position;
this.BaseStream.Position = position;
TResult result = func();
this.BaseStream.Position = old_position;
return result;
}
/// <summary>
/// Runs the given function temporary setting the current stream's position to the specified value.
/// </summary>
/// <typeparam name="TArg">Type of the function argument.</typeparam>
/// <param name="position">The position to run the function at.</param>
/// <param name="func">The function to run at the given position.</param>
/// <param name="arg">The argument passed to the function.</param>
public void DoAt<TArg>(long position, Action<TArg> func, TArg arg)
{
long old_position = this.BaseStream.Position;
this.BaseStream.Position = position;
func(arg);
this.BaseStream.Position = old_position;
}
/// <summary>
/// Runs the given function temporary setting the current stream's position to the specified value.
/// </summary>
/// <param name="position">The position to run the function at.</param>
/// <param name="func">The function to run at the given position.</param>
public void DoAt(long position, Action func)
{
long old_position = this.BaseStream.Position;
this.BaseStream.Position = position;
func();
this.BaseStream.Position = old_position;
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment