|
|
- using System;
- using System.IO;
- using System.Text;
- using MiscUtil.Conversion;
-
- namespace MiscUtil.IO
- {
- /// <summary>
- /// Equivalent of System.IO.BinaryWriter, but with either endianness, depending on
- /// the EndianBitConverter it is constructed with.
- /// </summary>
- public class EndianBinaryWriter : IDisposable
- {
- #region Fields not directly related to properties
- /// <summary>
- /// Whether or not this writer has been disposed yet.
- /// </summary>
- bool disposed=false;
- /// <summary>
- /// Buffer used for temporary storage during conversion from primitives
- /// </summary>
- byte[] buffer = new byte[16];
- /// <summary>
- /// Buffer used for Write(char)
- /// </summary>
- char[] charBuffer = new char[1];
- #endregion
-
- #region Constructors
- /// <summary>
- /// Constructs a new binary writer with the given bit converter, writing
- /// to the given stream, using UTF-8 encoding.
- /// </summary>
- /// <param name="bitConverter">Converter to use when writing data</param>
- /// <param name="stream">Stream to write data to</param>
- public EndianBinaryWriter (EndianBitConverter bitConverter,
- Stream stream) : this (bitConverter, stream, Encoding.UTF8)
- {
- }
-
- /// <summary>
- /// Constructs a new binary writer with the given bit converter, writing
- /// to the given stream, using the given encoding.
- /// </summary>
- /// <param name="bitConverter">Converter to use when writing data</param>
- /// <param name="stream">Stream to write data to</param>
- /// <param name="encoding">Encoding to use when writing character data</param>
- public EndianBinaryWriter (EndianBitConverter bitConverter, Stream stream, Encoding encoding)
- {
- if (bitConverter==null)
- {
- throw new ArgumentNullException("bitConverter");
- }
- if (stream==null)
- {
- throw new ArgumentNullException("stream");
- }
- if (encoding==null)
- {
- throw new ArgumentNullException("encoding");
- }
- if (!stream.CanWrite)
- {
- throw new ArgumentException("Stream isn't writable", "stream");
- }
- this.stream = stream;
- this.bitConverter = bitConverter;
- this.encoding = encoding;
- }
- #endregion
-
- #region Properties
- EndianBitConverter bitConverter;
- /// <summary>
- /// The bit converter used to write values to the stream
- /// </summary>
- public EndianBitConverter BitConverter
- {
- get { return bitConverter; }
- }
-
- Encoding encoding;
- /// <summary>
- /// The encoding used to write strings
- /// </summary>
- public Encoding Encoding
- {
- get { return encoding; }
- }
-
- Stream stream;
- /// <summary>
- /// Gets the underlying stream of the EndianBinaryWriter.
- /// </summary>
- public Stream BaseStream
- {
- get { return stream; }
- }
- #endregion
-
- #region Public methods
- /// <summary>
- /// Closes the writer, including the underlying stream.
- /// </summary>
- public void Close()
- {
- Dispose();
- }
-
- /// <summary>
- /// Flushes the underlying stream.
- /// </summary>
- public void Flush()
- {
- CheckDisposed();
- stream.Flush();
- }
-
- /// <summary>
- /// Seeks within the stream.
- /// </summary>
- /// <param name="offset">Offset to seek to.</param>
- /// <param name="origin">Origin of seek operation.</param>
- public void Seek (int offset, SeekOrigin origin)
- {
- CheckDisposed();
- stream.Seek (offset, origin);
- }
-
- /// <summary>
- /// Writes a boolean value to the stream. 1 byte is written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (bool value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 1);
- }
-
- /// <summary>
- /// Writes a 16-bit signed integer to the stream, using the bit converter
- /// for this writer. 2 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (short value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 2);
- }
-
- /// <summary>
- /// Writes a 32-bit signed integer to the stream, using the bit converter
- /// for this writer. 4 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (int value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 4);
- }
-
- /// <summary>
- /// Writes a 64-bit signed integer to the stream, using the bit converter
- /// for this writer. 8 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (long value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 8);
- }
-
- /// <summary>
- /// Writes a 16-bit unsigned integer to the stream, using the bit converter
- /// for this writer. 2 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (ushort value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 2);
- }
-
- /// <summary>
- /// Writes a 32-bit unsigned integer to the stream, using the bit converter
- /// for this writer. 4 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (uint value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 4);
- }
-
- /// <summary>
- /// Writes a 64-bit unsigned integer to the stream, using the bit converter
- /// for this writer. 8 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (ulong value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 8);
- }
-
- /// <summary>
- /// Writes a single-precision floating-point value to the stream, using the bit converter
- /// for this writer. 4 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (float value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 4);
- }
-
- /// <summary>
- /// Writes a double-precision floating-point value to the stream, using the bit converter
- /// for this writer. 8 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (double value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 8);
- }
-
- /// <summary>
- /// Writes a decimal value to the stream, using the bit converter for this writer.
- /// 16 bytes are written.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (decimal value)
- {
- bitConverter.CopyBytes(value, buffer, 0);
- WriteInternal(buffer, 16);
- }
-
- /// <summary>
- /// Writes a signed byte to the stream.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (byte value)
- {
- buffer[0] = value;
- WriteInternal(buffer, 1);
- }
-
- /// <summary>
- /// Writes an unsigned byte to the stream.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write (sbyte value)
- {
- buffer[0] = unchecked((byte)value);
- WriteInternal(buffer, 1);
- }
-
- /// <summary>
- /// Writes an array of bytes to the stream.
- /// </summary>
- /// <param name="value">The values to write</param>
- public void Write (byte[] value)
- {
- if (value == null)
- {
- throw (new System.ArgumentNullException("value"));
- }
- WriteInternal(value, value.Length);
- }
-
- /// <summary>
- /// Writes a portion of an array of bytes to the stream.
- /// </summary>
- /// <param name="value">An array containing the bytes to write</param>
- /// <param name="offset">The index of the first byte to write within the array</param>
- /// <param name="count">The number of bytes to write</param>
- public void Write (byte[] value, int offset, int count)
- {
- CheckDisposed();
- stream.Write(value, offset, count);
- }
-
- /// <summary>
- /// Writes a single character to the stream, using the encoding for this writer.
- /// </summary>
- /// <param name="value">The value to write</param>
- public void Write(char value)
- {
- charBuffer[0] = value;
- Write(charBuffer);
- }
-
- /// <summary>
- /// Writes an array of characters to the stream, using the encoding for this writer.
- /// </summary>
- /// <param name="value">An array containing the characters to write</param>
- public void Write(char[] value)
- {
- if (value==null)
- {
- throw new ArgumentNullException("value");
- }
- CheckDisposed();
- byte[] data = Encoding.GetBytes(value, 0, value.Length);
- WriteInternal(data, data.Length);
- }
-
- /// <summary>
- /// Writes a string to the stream, using the encoding for this writer.
- /// </summary>
- /// <param name="value">The value to write. Must not be null.</param>
- /// <exception cref="ArgumentNullException">value is null</exception>
- public void Write(string value)
- {
- if (value==null)
- {
- throw new ArgumentNullException("value");
- }
- CheckDisposed();
- byte[] data = Encoding.GetBytes(value);
- Write7BitEncodedInt(data.Length);
- WriteInternal(data, data.Length);
- }
-
- /// <summary>
- /// Writes a 7-bit encoded integer from the stream. This is stored with the least significant
- /// information first, with 7 bits of information per byte of value, and the top
- /// bit as a continuation flag.
- /// </summary>
- /// <param name="value">The 7-bit encoded integer to write to the stream</param>
- public void Write7BitEncodedInt(int value)
- {
- CheckDisposed();
- if (value < 0)
- {
- throw new ArgumentOutOfRangeException("value", "Value must be greater than or equal to 0.");
- }
- int index=0;
- while (value >= 128)
- {
- buffer[index++]= (byte)((value&0x7f) | 0x80);
- value = value >> 7;
- index++;
- }
- buffer[index++]=(byte)value;
- stream.Write(buffer, 0, index);
- }
-
- #endregion
-
- #region Private methods
- /// <summary>
- /// Checks whether or not the writer has been disposed, throwing an exception if so.
- /// </summary>
- void CheckDisposed()
- {
- if (disposed)
- {
- throw new ObjectDisposedException("EndianBinaryWriter");
- }
- }
-
- /// <summary>
- /// Writes the specified number of bytes from the start of the given byte array,
- /// after checking whether or not the writer has been disposed.
- /// </summary>
- /// <param name="bytes">The array of bytes to write from</param>
- /// <param name="length">The number of bytes to write</param>
- void WriteInternal (byte[] bytes, int length)
- {
- CheckDisposed();
- stream.Write(bytes, 0, length);
- }
- #endregion
-
- #region IDisposable Members
- /// <summary>
- /// Disposes of the underlying stream.
- /// </summary>
- public void Dispose()
- {
- if (!disposed)
- {
- Flush();
- disposed = true;
- ((IDisposable)stream).Dispose();
- }
- }
- #endregion
- }
- }
|