Created
November 14, 2011 18:40
-
-
Save LordJZ/1364708 to your computer and use it in GitHub Desktop.
StreamHandler + StructHelper + Time classes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
using Microsoft.Xna.Framework; | |
namespace Kamilla | |
{ | |
/// <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 bool m_closeStream; | |
/// <summary> | |
/// When reading, this value indicates how many bits of m_buffer[0] is used. | |
/// When writing, this value indicates how many bits are free in m_buffer[0]. | |
/// </summary> | |
private int m_unalignedBits = 8; | |
private byte[] m_buffer = new byte[16]; | |
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="Kamilla.StreamHandler"/>. | |
/// </summary> | |
public Stream BaseStream | |
{ | |
get | |
{ | |
this.Flush(); | |
return 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 length of the stream in bytes. | |
/// </summary> | |
/// <returns> | |
/// The length of the stream in bytes.</returns> | |
/// <exception cref="T:System.ObjectDisposedException"> | |
/// The stream is closed. | |
/// </exception> | |
public long Length | |
{ | |
get | |
{ | |
this.Flush(); | |
return m_stream.Length; | |
} | |
} | |
/// <summary> | |
/// Gets or sets the current position within the stream. | |
/// </summary> | |
/// <returns> | |
/// The current position within the stream. | |
/// </returns> | |
/// <exception cref="T:System.ArgumentOutOfRangeException"> | |
/// The position is set to a negative value or a value greater than <see cref="F:System.Int32.MaxValue" />. | |
/// </exception> | |
/// <exception cref="T:System.ObjectDisposedException"> | |
/// The stream is closed. | |
/// </exception> | |
public long Position | |
{ | |
get | |
{ | |
this.Flush(); | |
return m_stream.Position; | |
} | |
set | |
{ | |
this.Flush(); | |
m_stream.Position = value; | |
} | |
} | |
/// <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 this.RemainingLength == 0; | |
} | |
} | |
#endregion | |
#region Constructors | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Kamilla.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) | |
: this(output, encoding, true) | |
{ | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Kamilla.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> | |
/// <param name="closeStream"> | |
/// true, if the output stream should be closed when | |
/// the <see cref="Kamilla.StreamHandler"/> is disposed; otherwise, false. | |
/// </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, bool closeStream) | |
{ | |
if (output == null) | |
throw new ArgumentNullException("output"); | |
if (encoding == null) | |
throw new ArgumentNullException("encoding"); | |
m_stream = output; | |
m_closeStream = closeStream; | |
m_encoding = encoding; | |
m_encoder = m_encoding.GetEncoder(); | |
m_decoder = m_encoding.GetDecoder(); | |
m_2BytesPerChar = encoding is UnicodeEncoding; | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Kamilla.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="Kamilla.StreamHandler"/> class | |
/// based on the supplied stream and using UTF-8 as the encoding for strings. | |
/// </summary> | |
/// <param name="output">The output stream.</param> | |
/// <param name="closeStream"> | |
/// true, if the output stream should be closed when | |
/// the <see cref="Kamilla.StreamHandler"/> is disposed; otherwise, false. | |
/// </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, bool closeStream) | |
: this(output, new UTF8Encoding(false, true), closeStream) | |
{ | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Kamilla.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="Kamilla.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="Kamilla.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="Kamilla.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="Kamilla.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="Kamilla.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="Kamilla.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) | |
{ | |
m_stream = new MemoryStream(buffer); | |
m_closeStream = true; | |
m_encoding = new UTF8Encoding(false, true); | |
m_encoder = m_encoding.GetEncoder(); | |
m_decoder = m_encoding.GetDecoder(); | |
m_2BytesPerChar = false; | |
} | |
#endregion | |
#region Misc Methods | |
/// <summary> | |
/// Closes the current <see cref="Kamilla.StreamHandler"/> and the underlying stream. | |
/// </summary> | |
public virtual void Close() | |
{ | |
this.Dispose(true); | |
} | |
/// <summary> | |
/// Releases the unmanaged resources used by the <see cref="Kamilla.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) | |
{ | |
if (m_closeStream) | |
m_stream.Close(); | |
} | |
} | |
/// <summary> | |
/// Releases all resources used by the current instance of the <see cref="Kamilla.StreamHandler"/> class. | |
/// </summary> | |
public void 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() | |
{ | |
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.Flush(); | |
m_stream.Position += bytes; | |
} | |
#endregion | |
#region Write Methods | |
#region Unaligned Writing | |
/// <summary> | |
/// Flushes the unaligned bit buffer of the current stream. | |
/// </summary> | |
/// <returns>The current instance of <see cref="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler FlushUnalignedBits() | |
{ | |
if (m_unalignedBits != 8) | |
InternalFlushUnalignedBits(); | |
return this; | |
} | |
void InternalFlushUnalignedBits() | |
{ | |
m_stream.Write(m_buffer, 0, 1); | |
m_unalignedBits = 8; | |
m_buffer[0] = 0; | |
} | |
void InternalUnalignedWrite(ulong value, int bits) | |
{ | |
while (bits > 0) | |
{ | |
if (m_unalignedBits == 0) | |
InternalFlushUnalignedBits(); | |
int bitsWriteNow = Math.Min(bits, m_unalignedBits); | |
int bitsWriteNowMask = (1 << bitsWriteNow) - 1; | |
m_buffer[0] |= (byte)(((int)(value >> (bits - bitsWriteNow)) & bitsWriteNowMask) // Grab the bits from the value | |
<< (m_unalignedBits - bitsWriteNow)); // Store them in the buffer | |
m_unalignedBits -= bitsWriteNow; | |
bits -= bitsWriteNow; | |
} | |
if (m_unalignedBits == 0) | |
InternalFlushUnalignedBits(); | |
} | |
/// <summary> | |
/// Writes a single bit of data to the current stream. | |
/// </summary> | |
/// <param name="value"> | |
/// The bit value to write. | |
/// </param> | |
/// <returns>The current instance of <see cref="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler UnalignedWriteBit(bool value) | |
{ | |
InternalUnalignedWrite(value ? 1UL : 0UL, 1); | |
return this; | |
} | |
/// <summary> | |
/// Writes an integer value of the specified number of bits of 64 maximum to the current stream. | |
/// </summary> | |
/// <param name="value"> | |
/// The integer value to write. | |
/// </param> | |
/// <param name="bits"> | |
/// Number of bits to write. | |
/// </param> | |
/// <returns>The current instance of <see cref="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler UnalignedWriteInt(ulong value, int bits) | |
{ | |
CheckBits(bits, 64); | |
InternalUnalignedWrite((ulong)value, bits); | |
return this; | |
} | |
/// <summary> | |
/// Writes an integer value of the specified number of bits of 32 maximum to the current stream. | |
/// </summary> | |
/// <param name="value"> | |
/// The integer value to write. | |
/// </param> | |
/// <param name="bits"> | |
/// Number of bits to write. | |
/// </param> | |
/// <returns>The current instance of <see cref="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler UnalignedWriteInt(uint value, int bits) | |
{ | |
CheckBits(bits, 32); | |
InternalUnalignedWrite((ulong)value, bits); | |
return this; | |
} | |
/// <summary> | |
/// Writes an integer value of the specified number of bits of 16 maximum to the current stream. | |
/// </summary> | |
/// <param name="value"> | |
/// The integer value to write. | |
/// </param> | |
/// <param name="bits"> | |
/// Number of bits to write. | |
/// </param> | |
/// <returns>The current instance of <see cref="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler UnalignedWriteInt(ushort value, int bits) | |
{ | |
CheckBits(bits, 16); | |
InternalUnalignedWrite((ulong)value, bits); | |
return this; | |
} | |
/// <summary> | |
/// Writes an integer value of the specified number of bits of 8 maximum to the current stream. | |
/// </summary> | |
/// <param name="value"> | |
/// The integer value to write. | |
/// </param> | |
/// <param name="bits"> | |
/// Number of bits to write. | |
/// </param> | |
/// <returns>The current instance of <see cref="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler UnalignedWriteInt(byte value, int bits) | |
{ | |
CheckBits(bits, 8); | |
InternalUnalignedWrite((ulong)value, bits); | |
return this; | |
} | |
#endregion | |
/// <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="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler WriteBoolean(bool value) | |
{ | |
m_buffer[0] = value ? ((byte)1) : ((byte)0); | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler WriteByte(byte value) | |
{ | |
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="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler WriteBytes(byte[] buffer) | |
{ | |
if (buffer == null) | |
throw new ArgumentNullException("buffer"); | |
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="Kamilla.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 = m_buffer) | |
{ | |
count = m_encoder.GetBytes(&ch, 1, numRef, 16, true); | |
} | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler WriteChars(char[] chars) | |
{ | |
if (chars == null) | |
throw new ArgumentNullException("chars"); | |
byte[] buffer = m_encoding.GetBytes(chars, 0, chars.Length); | |
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="Kamilla.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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteDouble(double value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(double*)buf = value; | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteSingle(float value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(float*)buf = value; | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteInt32(int value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(int*)buf = value; | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteInt64(long value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(long*)buf = value; | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler WriteSByte(sbyte value) | |
{ | |
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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteInt16(short value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(short*)buf = value; | |
m_stream.Write(m_buffer, 0, 2); | |
return this; | |
} | |
/// <summary> | |
/// Writes a null-terminated string to the current stream in the current encoding of | |
/// the <see cref="Kamilla.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="Kamilla.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 = m_encoding.GetBytes(chars, 0, chars.Length); | |
m_stream.Write(buffer, 0, buffer.Length); | |
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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteUInt32(uint value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(uint*)buf = value; | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteUInt64(ulong value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(ulong*)buf = value; | |
m_stream.Write(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="Kamilla.StreamHandler"/>.</returns> | |
public unsafe StreamHandler WriteUInt16(ushort value) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(ushort*)buf = value; | |
m_stream.Write(m_buffer, 0, 2); | |
return this; | |
} | |
/// <summary> | |
/// Writes a two-component vector to the current stream | |
/// and advances the stream position by eight bytes. | |
/// </summary> | |
/// <param name="vector"> | |
/// The <see cref="Microsoft.Xna.Framework.Vector2"/> to write. | |
/// </param> | |
/// <returns> | |
/// The current instance of <see cref="Kamilla.StreamHandler"/>. | |
/// </returns> | |
/// <exception cref="System.IO.IOException"> | |
/// An I/O error occurs. | |
/// </exception> | |
/// <exception cref="System.ObjectDisposedException"> | |
/// The stream is closed. | |
/// </exception> | |
public unsafe StreamHandler WriteVector2(ref Vector2 vector) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(Vector2*)buf = vector; | |
m_stream.Write(m_buffer, 0, 4 * 2); | |
return this; | |
} | |
/// <summary> | |
/// Writes a three-component vector to the current stream | |
/// and advances the stream position by twelve bytes. | |
/// </summary> | |
/// <param name="vector"> | |
/// The <see cref="Microsoft.Xna.Framework.Vector3"/> to write. | |
/// </param> | |
/// <returns> | |
/// The current instance of <see cref="Kamilla.StreamHandler"/>. | |
/// </returns> | |
/// <exception cref="System.IO.IOException"> | |
/// An I/O error occurs. | |
/// </exception> | |
/// <exception cref="System.ObjectDisposedException"> | |
/// The stream is closed. | |
/// </exception> | |
public unsafe StreamHandler WriteVector3(ref Vector3 vector) | |
{ | |
fixed (byte* buf = m_buffer) | |
*(Vector3*)buf = vector; | |
m_stream.Write(m_buffer, 0, 4 * 3); | |
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="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler WriteBytes(byte[] buffer, int index, int count) | |
{ | |
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="Kamilla.StreamHandler"/>.</returns> | |
public StreamHandler WriteChars(char[] chars, int index, int count) | |
{ | |
byte[] buffer = m_encoding.GetBytes(chars, index, count); | |
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="Kamilla.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 (m_stream.CanSeek) | |
position = m_stream.Position; | |
if (m_charBytes == null) | |
m_charBytes = new byte[0x80]; | |
if (m_singleChar == null) | |
m_singleChar = new char[1]; | |
while (num == 0) | |
{ | |
byteCount = m_2BytesPerChar ? 2 : 1; | |
int num4 = m_stream.ReadByte(); | |
m_charBytes[0] = (byte)num4; | |
if (num4 == -1) | |
byteCount = 0; | |
if (byteCount == 2) | |
{ | |
num4 = m_stream.ReadByte(); | |
m_charBytes[1] = (byte)num4; | |
if (num4 == -1) | |
byteCount = 1; | |
} | |
if (byteCount == 0) | |
return -1; | |
try | |
{ | |
num = m_decoder.GetChars(m_charBytes, 0, byteCount, m_singleChar, 0); | |
continue; | |
} | |
catch | |
{ | |
if (m_stream.CanSeek) | |
m_stream.Seek(position - m_stream.Position, SeekOrigin.Current); | |
throw; | |
} | |
} | |
if (num == 0) | |
return -1; | |
return m_singleChar[0]; | |
} | |
private void FillBuffer(int numBytes) | |
{ | |
m_unalignedBits = 8; | |
int offset = 0; | |
int num2 = 0; | |
if (m_stream == null) | |
throw new ObjectDisposedException("stream"); | |
if (numBytes == 1) | |
{ | |
num2 = m_stream.ReadByte(); | |
if (num2 == -1) | |
throw new EndOfStreamException(); | |
m_buffer[0] = (byte)num2; | |
} | |
else | |
{ | |
do | |
{ | |
num2 = m_stream.Read(m_buffer, offset, numBytes - offset); | |
if (num2 == 0) | |
throw new EndOfStreamException(); | |
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 (m_stream == null) | |
throw new ObjectDisposedException("stream"); | |
if (!m_stream.CanSeek) | |
return -1; | |
long position = m_stream.Position; | |
int num2 = this.Read(); | |
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 (m_stream == null) | |
throw new ObjectDisposedException("stream"); | |
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 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 (m_stream == null) | |
throw new ObjectDisposedException("stream"); | |
char[] buf = this.ReadChars(count); | |
Array.Copy(buf, 0, buffer, index, buf.Length); | |
return buf.Length; | |
} | |
#region Unaligned Reading | |
void CheckBits(int bits, int max) | |
{ | |
if (bits > max || bits < 0) | |
throw new ArgumentOutOfRangeException("bits", "bits must be from 0 to " + max + "."); | |
} | |
ulong InternalReadBits(int count) | |
{ | |
ulong ret = 0; | |
while (count > 0) | |
{ | |
if (m_unalignedBits == 8) | |
{ | |
this.FillBuffer(1); | |
m_unalignedBits = 0; | |
} | |
int readNow = Math.Min(8 - m_unalignedBits, count); | |
m_unalignedBits += readNow; | |
count -= readNow; | |
ret |= (ulong)(m_buffer[0] >> (8 - readNow)) << count; | |
m_buffer[0] <<= readNow; | |
} | |
return ret; | |
} | |
/// <summary> | |
/// Reads a single unaligned bit from the underlying stream. | |
/// </summary> | |
/// <returns> | |
/// Value of the read bit. | |
/// </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 UnalignedReadBit() | |
{ | |
return InternalReadBits(1) != 0; | |
} | |
/// <summary> | |
/// Reads an unaligned unsigned integer of maximum 64 bits at max from the underlying stream. | |
/// </summary> | |
/// <param name="bits"> | |
/// Number of bits to read. | |
/// </param> | |
/// <returns> | |
/// The read integer. | |
/// </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 ulong UnalignedReadBigInt(int bits) | |
{ | |
CheckBits(bits, 64); | |
return InternalReadBits(bits); | |
} | |
/// <summary> | |
/// Reads an unaligned unsigned integer of 32 bits at max from the underlying stream. | |
/// </summary> | |
/// <param name="bits"> | |
/// Number of bits to read. | |
/// </param> | |
/// <returns> | |
/// The read integer. | |
/// </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 UnalignedReadInt(int bits) | |
{ | |
CheckBits(bits, 32); | |
return (uint)InternalReadBits(bits); | |
} | |
/// <summary> | |
/// Reads an unaligned unsigned integer of 16 bits at max from the underlying stream. | |
/// </summary> | |
/// <param name="bits"> | |
/// Number of bits to read. | |
/// </param> | |
/// <returns> | |
/// The read integer. | |
/// </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 UnalignedReadSmallInt(int bits) | |
{ | |
CheckBits(bits, 16); | |
return (ushort)InternalReadBits(bits); | |
} | |
/// <summary> | |
/// Reads an unsigned integer of 8 bits at max from the underlying stream. | |
/// </summary> | |
/// <param name="bits"> | |
/// Number of bits to read. | |
/// </param> | |
/// <returns> | |
/// The read integer. | |
/// </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 UnalignedReadTinyInt(int bits) | |
{ | |
CheckBits(bits, 8); | |
return (byte)InternalReadBits(bits); | |
} | |
#endregion | |
/// <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 (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 (m_stream == null) | |
throw new ObjectDisposedException("m_stream"); | |
int num = 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.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 (m_stream == null) | |
throw new ObjectDisposedException("m_stream"); | |
byte[] buffer = new byte[count]; | |
int read = m_stream.Read(buffer, 0, count); | |
if (read != count) | |
throw new EndOfStreamException("Expected " + count + ", read " + read); | |
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 (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); | |
fixed (byte* buf = m_buffer) | |
return *(double*)buf; | |
} | |
/// <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 unsafe short ReadInt16() | |
{ | |
this.FillBuffer(2); | |
fixed (byte* buf = m_buffer) | |
return *(short*)buf; | |
} | |
/// <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 unsafe int ReadInt32() | |
{ | |
this.FillBuffer(4); | |
fixed (byte* buf = m_buffer) | |
return *(int*)buf; | |
} | |
/// <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 unsafe long ReadInt64() | |
{ | |
this.FillBuffer(8); | |
fixed (byte* buf = m_buffer) | |
return *(long*)buf; | |
} | |
/// <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)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); | |
fixed (byte* buf = m_buffer) | |
return *(float*)buf; | |
} | |
/// <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 unsafe ushort ReadUInt16() | |
{ | |
this.FillBuffer(2); | |
fixed (byte* buf = m_buffer) | |
return *(ushort*)buf; | |
} | |
/// <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 unsafe uint ReadUInt32() | |
{ | |
this.FillBuffer(4); | |
fixed (byte* buf = m_buffer) | |
return *(uint*)buf; | |
} | |
/// <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 unsafe ulong ReadUInt64() | |
{ | |
this.FillBuffer(8); | |
fixed (byte* buf = m_buffer) | |
return *(ulong*)buf; | |
} | |
/// <summary> | |
/// Reads a three-component vector from the current stream | |
/// and advences the position of the stream by twelve bytes. | |
/// </summary> | |
/// <returns> | |
/// A <see cref="Microsoft.Xna.Framework.Vector3"/> read from the 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 unsafe Vector3 ReadVector3() | |
{ | |
this.FillBuffer(4 * 3); | |
fixed (byte* buf = m_buffer) | |
return *(Vector3*)buf; | |
} | |
/// <summary> | |
/// Reads a two-component vector from the current stream | |
/// and advences the position of the stream by eight bytes. | |
/// </summary> | |
/// <returns> | |
/// A <see cref="Microsoft.Xna.Framework.Vector2"/> read from the 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 unsafe Vector2 ReadVector2() | |
{ | |
this.FillBuffer(4 * 2); | |
fixed (byte* buf = m_buffer) | |
return *(Vector2*)buf; | |
} | |
/// <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[] ToByteArray() | |
{ | |
this.Flush(); | |
long pos = m_stream.Position; | |
m_stream.Position = 0; | |
byte[] buffer = new byte[m_stream.Length]; | |
m_stream.Read(buffer, 0, (int)m_stream.Length); | |
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, StructHelper<T>.Type); | |
} | |
} | |
#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.Position; | |
this.Position = position; | |
TResult result = func(arg); | |
this.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.Position; | |
this.Position = position; | |
TResult result = func(); | |
this.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.Position; | |
this.Position = position; | |
func(arg); | |
this.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.Position; | |
this.Position = position; | |
func(); | |
this.Position = old_position; | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Text; | |
namespace Kamilla | |
{ | |
public static class StreamHandlerExtensions | |
{ | |
public static string ReadPascalString32(this StreamHandler sh) | |
{ | |
return PascalStringReader(sh, sh.ReadInt32()); | |
} | |
public static string ReadPascalString16(this StreamHandler sh) | |
{ | |
return PascalStringReader(sh, sh.ReadUInt16()); | |
} | |
public static string ReadPascalString8(this StreamHandler sh) | |
{ | |
return PascalStringReader(sh, sh.ReadByte()); | |
} | |
private static string PascalStringReader(StreamHandler sh, int length) | |
{ | |
if (length > 0) | |
{ | |
byte[] bytes = sh.ReadBytes(length + 1); | |
int len = length + 1; | |
if (bytes[bytes.Length - 1] == 0x00) | |
--len; | |
return Encoding.UTF8.GetString(bytes, 0, len); | |
} | |
else | |
return string.Empty; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.InteropServices; | |
namespace Kamilla | |
{ | |
public static class StructHelper<T> where T : struct | |
{ | |
public static readonly int Size; | |
public static readonly IntPtr UnmanagedDataBank; | |
public static readonly byte[] ManagedDataBank; | |
public static readonly object SyncRoot; | |
public static readonly Type Type; | |
static StructHelper() | |
{ | |
SyncRoot = new object(); | |
Type = typeof(T); | |
Size = Marshal.SizeOf(Type); | |
ManagedDataBank = new byte[Size]; | |
UnmanagedDataBank = Marshal.AllocHGlobal(Size); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
namespace Kamilla | |
{ | |
/// <summary> | |
/// Contains methods to work with time-representing variables. | |
/// </summary> | |
public static class Time | |
{ | |
/// <summary> | |
/// Represents a year in seconds. This field is constant. | |
/// </summary> | |
public const long Year = 12 * Month; | |
/// <summary> | |
/// Represents a month (28 days) in seconds. This field is constant. | |
/// </summary> | |
public const long Month = 28 * Day; | |
/// <summary> | |
/// Represents a week in seconds. This field is constant. | |
/// </summary> | |
public const long Week = 7 * Day; | |
/// <summary> | |
/// Represents a day in seconds. This field is constant. | |
/// </summary> | |
public const long Day = 24 * Hour; | |
/// <summary> | |
/// Represents an hour in seconds. This field is constant. | |
/// </summary> | |
public const long Hour = 60 * Minute; | |
/// <summary> | |
/// Represents a minute in seconds. This field is constant. | |
/// </summary> | |
public const long Minute = 60 * Second; | |
/// <summary> | |
/// Represents a single second. This field is constant. | |
/// </summary> | |
public const long Second = 1; | |
/// <summary> | |
/// Represents a second in milliseconds. This field is constant. | |
/// </summary> | |
public const long InMilliseconds = 1000; | |
private static readonly long[] Timeequence = new long[] { Year, Month, Week, Day, Hour, Minute, Second }; | |
// month, day, day,hour, min, second, none | |
private static readonly int[] TimeUnitNextUnit = new int[] { 1, 3, 3, 4, 5, 6, -1 }; | |
private static readonly string[] NamesNormal = { "year", "month", "week", "day", "hour", "minute", "second" }; | |
private static readonly string[] NamesPlural = { "years", "months", "weeks", "days", "hours", "minutes", "seconds" }; | |
private static readonly string[] NamesAbbrev = { "yr", "mo", "wk", string.Empty, "hr", "min", "sec" }; | |
static readonly DateTime s_unixEpochReference = new DateTime(1970, 1, 1, 0, 0, 0, 0); | |
/// <summary> | |
/// Represents the beginning of the Unix Epoch in local time. | |
/// </summary> | |
public static readonly DateTime UnixEpoch = (0L).AsUnixTime(); | |
/// <summary> | |
/// Converts the number of seconds passed since UTC Unix Epoch to local time. | |
/// </summary> | |
/// <param name="unixTimeUtc"> | |
/// Number of seconds passed since UTC Unix Epoch. | |
/// </param> | |
/// <returns> | |
/// <see cref="System.DateTime"/> converted from UTC Unix Epoch. | |
/// </returns> | |
/// <exception cref="System.ArgumentOutOfRangeException"> | |
/// The resulting <see cref="System.DateTime"/> is less than <see href="System.DateTime.MinValue"/> or greater than <see href="System.DateTime.MaxValue"/>. | |
/// </exception> | |
public static DateTime AsUnixTime(this uint unixTimeUtc) | |
{ | |
return AsUnixTime((long)unixTimeUtc); | |
} | |
/// <summary> | |
/// Converts the number of seconds passed since UTC Unix Epoch to local time. | |
/// </summary> | |
/// <param name="unixTimeUtc"> | |
/// Number of seconds passed since UTC Unix Epoch. | |
/// </param> | |
/// <returns> | |
/// <see cref="System.DateTime"/> converted from UTC Unix Epoch. | |
/// </returns> | |
/// <exception cref="System.ArgumentException"> | |
/// unixTimeUtc is negative. | |
/// </exception> | |
/// <exception cref="System.ArgumentOutOfRangeException"> | |
/// The resulting <see cref="System.DateTime"/> is less than <see href="System.DateTime.MinValue"/> or greater than <see href="System.DateTime.MaxValue"/>. | |
/// </exception> | |
public static DateTime AsUnixTime(this long unixTimeUtc) | |
{ | |
if (unixTimeUtc < 0) | |
throw new ArgumentException(); | |
return TimeZone.CurrentTimeZone.ToLocalTime(s_unixEpochReference.AddSeconds(unixTimeUtc)); | |
} | |
/// <summary> | |
/// Converts the <see cref="System.DateTime"/> to UTC Unix Timestamp. | |
/// </summary> | |
/// <param name="dateTime"> | |
/// <see cref="System.DateTime"/> to convert to UTC Unix Timestamp. | |
/// </param> | |
/// <returns> | |
/// Number of seconds passed since UTC Unix Epoch. | |
/// </returns> | |
/// <exception cref="System.ArgumentException"> | |
/// The provided <see cref="System.DateTime"/> cannot be converted to UTC Unix Timestamp. | |
/// </exception> | |
/// <exception cref="System.ArgumentNullException"> | |
/// dateTime is null. | |
/// </exception> | |
public static uint ToUnixTime(this DateTime dateTime) | |
{ | |
var ret = ToUnixTimeLong(dateTime); | |
if (ret >= int.MaxValue) // year >= 2038 | |
throw new ArgumentException(); | |
return (uint)ret; | |
} | |
/// <summary> | |
/// Converts the <see cref="System.DateTime"/> to UTC Unix Timestamp. | |
/// </summary> | |
/// <param name="dateTime"> | |
/// <see cref="System.DateTime"/> to convert to UTC Unix Timestamp. | |
/// </param> | |
/// <returns> | |
/// Number of seconds passed since UTC Unix Epoch. | |
/// </returns> | |
/// <exception cref="System.ArgumentNullException"> | |
/// dateTime is null. | |
/// </exception> | |
public static uint ToUnixTimeOrZero(this DateTime dateTime) | |
{ | |
var ret = ToUnixTimeOrZeroLong(dateTime); | |
if (ret >= int.MaxValue) // year >= 2038 | |
return 0U; | |
return (uint)ret; | |
} | |
/// <summary> | |
/// Converts the <see cref="System.DateTime"/> to UTC Unix Timestamp. | |
/// </summary> | |
/// <param name="dateTime"> | |
/// <see cref="System.DateTime"/> to convert to UTC Unix Timestamp. | |
/// </param> | |
/// <returns> | |
/// Number of seconds passed since UTC Unix Epoch. | |
/// </returns> | |
/// <exception cref="System.ArgumentException"> | |
/// The provided <see cref="System.DateTime"/> cannot be converted to UTC Unix Timestamp. | |
/// </exception> | |
/// <exception cref="System.ArgumentNullException"> | |
/// dateTime is null. | |
/// </exception> | |
public static long ToUnixTimeLong(this DateTime dateTime) | |
{ | |
if (dateTime == null) | |
throw new ArgumentNullException(); | |
dateTime = dateTime.ToUniversalTime(); | |
if (dateTime < s_unixEpochReference) | |
throw new ArgumentException(); | |
return (long)(dateTime - s_unixEpochReference).TotalSeconds; | |
} | |
/// <summary> | |
/// Converts the <see cref="System.DateTime"/> to UTC Unix Timestamp. | |
/// </summary> | |
/// <param name="dateTime"> | |
/// <see cref="System.DateTime"/> to convert to UTC Unix Timestamp. | |
/// </param> | |
/// <returns> | |
/// Number of seconds passed since UTC Unix Epoch. | |
/// </returns> | |
/// <exception cref="System.ArgumentNullException"> | |
/// dateTime is null. | |
/// </exception> | |
public static long ToUnixTimeOrZeroLong(this DateTime dateTime) | |
{ | |
if (dateTime == null) | |
throw new ArgumentNullException(); | |
dateTime = dateTime.ToUniversalTime(); | |
if (dateTime < s_unixEpochReference) | |
return 0; | |
return (long)(dateTime - s_unixEpochReference).TotalSeconds; | |
} | |
static string createText(long value, int id, bool small) | |
{ | |
if (small && NamesAbbrev[id] == string.Empty) | |
small = false; | |
if (small) | |
return value + " " + NamesAbbrev[id]; | |
return value + " " + (value == 1 ? NamesNormal[id] : NamesPlural[id]); | |
} | |
/// <summary> | |
/// Represents a number of seconds in a human-readable line, | |
/// which contains one or two words. | |
/// </summary> | |
/// <param name="input"> | |
/// Number of seconds in a 64-bit signed integer. | |
/// </param> | |
/// <returns> | |
/// The output string. | |
/// </returns> | |
public static string AsSimpleTimeString(this uint input) | |
{ | |
return AsSimpleTimeString((long)input); | |
} | |
/// <summary> | |
/// Represents a number of seconds in a human-readable line, | |
/// which contains one or two words. | |
/// </summary> | |
/// <param name="input"> | |
/// Number of seconds in a 64-bit signed integer. | |
/// </param> | |
/// <returns> | |
/// The output string. | |
/// </returns> | |
/// <exception cref="System.ArgumentOutOfRangeException"> | |
/// input must be a non-negative value. | |
/// </exception> | |
public static string AsSimpleTimeString(this long input) | |
{ | |
if (input < 0) | |
throw new ArgumentOutOfRangeException(); | |
if (input == 0) | |
return "Now"; | |
for (var id = 0; id < Timeequence.Length; ++id) | |
{ | |
if (input >= Timeequence[id]) | |
{ | |
long TimeUnit = input / Timeequence[id]; | |
if (TimeUnitNextUnit[id] != -1) | |
{ | |
input %= Timeequence[id]; | |
int secondId = TimeUnitNextUnit[id]; | |
long SecondTimeUnit = input / Timeequence[secondId]; | |
if (SecondTimeUnit > 0) | |
return createText(TimeUnit, id, true) + " " + createText(SecondTimeUnit, secondId, true); | |
} | |
return createText(TimeUnit, id, false); | |
} | |
} | |
return "(n/a)"; | |
} | |
/// <summary> | |
/// Represents a number of seconds in a human-readable line, which contains exact time span. | |
/// </summary> | |
/// <param name="input"> | |
/// Number of seconds in a 64-bit signed integer. | |
/// </param> | |
/// <returns> | |
/// The output string. | |
/// </returns> | |
public static string AsTimeString(this uint input) | |
{ | |
return AsTimeString((long)input); | |
} | |
/// <summary> | |
/// Represents a number of seconds in a human-readable line, which contains exact time span. | |
/// </summary> | |
/// <param name="input"> | |
/// Number of seconds in a 64-bit signed integer. | |
/// </param> | |
/// <returns> | |
/// The output string. | |
/// </returns> | |
/// <exception cref="System.ArgumentOutOfRangeException"> | |
/// input must be a non-negative value. | |
/// </exception> | |
public static string AsTimeString(this long input) | |
{ | |
if (input < 0) | |
throw new ArgumentOutOfRangeException(); | |
if (input == 0) | |
return "Now"; | |
List<string> result = new List<string>(); | |
for (var id = 0; id < Timeequence.Length; ) | |
{ | |
if (input >= Timeequence[id]) | |
{ | |
long TimeUnit = input / Timeequence[id]; | |
result.Add(TimeUnit + " " + (TimeUnit == 1 ? NamesNormal[id] : NamesPlural[id])); | |
if (TimeUnitNextUnit[id] != -1) | |
{ | |
input %= Timeequence[id]; | |
id = TimeUnitNextUnit[id]; | |
continue; | |
} | |
else | |
break; | |
} | |
++id; | |
} | |
return result.ToStringJoin(" "); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment