⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bitstream.cs

📁 自适应huffman编码工具
💻 CS
字号:
// Stephen Toub
// stoub@microsoft.com
//
// BitStream.cs
// Stream for reading and writing individual bits from and to another stream.
//
// v1.0.0
// July 17th, 2002

#region Namespaces
using System;
using System.IO;
#endregion

namespace Toub.IO
{
	/// <summary>Stream for reading and writing individual bits from and to another stream.</summary>
	public class BitStream : Stream, IDisposable
	{
		#region Member Variables
		/// <summary>The number of bits that have been processed in the stream.</summary>
		private long _bitsProcessed;
		/// <summary>The direction in which this stream is processing bits.</summary>
		private StreamDirection _direction;
		/// <summary>The underlying stream for the bit stream (i.e. a FileStream).</summary>
		private Stream _baseStream;
		/// <summary>The bit buffer for buffering read or written bits.</summary>
		private byte _bitBuffer;
		/// <summary>The current position in the bit buffer.</summary>
		private int _curPos;
		/// <summary>Whether the stream is open.  Used primarily when closing the stream.</summary>
		private bool _open;
		/// <summary>Whether to close the base stream when this stream is closed.</summary>
		private bool _closeBaseStream;
		#endregion

		#region Construction
		/// <summary>Initialize the BitStream.</summary>
		/// <param name="baseStream">The underlying stream for the bit stream.</param>
		/// <param name="direction">The direction of the stream.</param>
		public BitStream(Stream baseStream, StreamDirection direction)
		{
			// Store the data
			_direction = direction;
			_baseStream = baseStream;

			// Make sure we can process the underlying stream in the requested direction
			if (direction == StreamDirection.Read && !baseStream.CanRead) 
			{
				throw new ArgumentException("Can't read from the underlying stream.");
			} 
			else if (direction == StreamDirection.Write && !baseStream.CanWrite) 
			{
				throw new ArgumentException("Can't write to the underlying stream.");
			}

			// Setup stream
			_bitBuffer = 0;
			_curPos = 0;
			_bitsProcessed = 0;
			_open = true;
			_closeBaseStream = true;
		}
		#endregion

		#region Properties
		/// <summary>Gets whether we can read bits from this stream.</summary>
		public override bool CanRead { get { return _open && _direction == StreamDirection.Read; } }
        
		/// <summary>Gets whether we can seek on this stream.  Always returns false.</summary>
		public override bool CanSeek { get { return false; } }
        
		/// <summary>Gets whether we can write bits to this stream.</summary>
		public override bool CanWrite { get { return _open && _direction == StreamDirection.Write; } }

		/// <summary>Not Supported.</summary>
		public override long Length { get { throw new NotSupportedException("Can't seek on a bit stream."); } }
        
		/// <summary>Gets the number of bits processed by the stream (either read or written).</summary>
		public override long Position
		{
			get { return _bitsProcessed; }
			set { throw new NotSupportedException("Can't seek on a bit stream."); }
		}

		/// <summary>
		/// Gets or sets whether to close the base stream when this stream is closed.
		/// Default is true.
		/// </summary>
		public bool CloseBaseStream { get { return _closeBaseStream; } set { _closeBaseStream = value; } }
		#endregion
        
		#region Writing
		/// <summary>Writes a bit to the output stream.</summary>
		/// <param name="bit">The bit to be written.</param>
		public void WriteBit(int bit)
		{
			// Make sure we can write and that we have valid input.
			if (!CanWrite) throw new NotSupportedException("Can't write on this stream.");
			if (bit != 0 && bit != 1) throw new ArgumentException("The bit must be 0 or 1.", "bit");

			// Write the bit into the buffer
			_bitBuffer = (byte)(_bitBuffer | (bit << (7-_curPos)));

			// Move the internal pointer along.  If we've reached the end
			// of the buffer, dump it into the real stream.
			if (++_curPos == 8)
			{
				_baseStream.WriteByte(_bitBuffer);
				_bitBuffer = 0;
				_curPos = 0;
			}

			// Update our count of how many bits we've processed
			_bitsProcessed++;
		}

		/// <summary>Writes a byte worth of bits to the output stream.</summary>
		/// <param name='value'>The byte to be written.</param>
		public override void WriteByte(byte value)
		{
			// Write out each bit in the number
			for(int i=0; i<8; i++) 
			{
				// Get the bit from the value buffer and write it
				int bit = ((1 << (7 - i)) & value) > 0 ? 1 : 0;
				WriteBit(bit);
			}
		}
        
		/// <summary>Writes an array of bits (integers with 0 or 1 values) to the stream.</summary>
		/// <param name="bits">The array of bits to write.</param>
		/// <param name="offset">The offset into the array at which to begin writing.</param>
		/// <param name="count">The number of bits to write.</param>
		public void Write(int [] bits, int offset, int count)
		{
			// Write each bit in the array.
			for(int i=offset; i<offset+count; i++) WriteBit(bits[i]);
		}

		/// <summary>Writes a buffer's worth of bytes to the output stream.</summary>
		/// <param name='buffer'>The bytes to be written.</param>
		/// <param name='offset'>The position in the array of bytes at which to begin writing.</param>
		/// <param name='count'>The number of bytes to write.</param>
		public override void Write(byte [] buffer, int offset, int count)
		{
			// Write each byte to the output stream.
			for(int i=offset; i<offset+count; i++) WriteByte(buffer[i]);
		}
		#endregion
        
		#region Reading
		/// <summary>Reads a bit from the input stream.</summary>
		/// <returns>0 or 1, or -1 if at the end of the stream.</returns>
		public int ReadBit()
		{
			int bit, tempBuffer;

			// Make sure we can read.
			if (!CanRead) throw new NotSupportedException("Can't read on this stream.");

			// Now read the bit.  If we need to get more data from the stream, do so.
			if (_curPos == 0)
			{
				// We need to read another byte from the stream.  If the
				// stream is empty, return -1.  Otherwise, fill the bitbuffer
				// with the read in byte.
				if ((tempBuffer = _baseStream.ReadByte()) == -1)
				{
					_bitBuffer = 0;
					return -1;
				} 
				else _bitBuffer = (byte)tempBuffer;
			}

			// Grab the appropriate bit from the buffer and move to the next bit.
			bit = ((1 << (7 - _curPos)) & _bitBuffer) > 0 ? 1 : 0;
			_curPos = (_curPos + 1) % 8;

			// Update our count of how many bits we've processed
			_bitsProcessed++;

			// Return the newly read bit
			return bit;
		}

		/// <summary>Read a byte from the input stream.</summary>
		/// <returns>The byte read from the input stream.</returns>
		public override int ReadByte()
		{
			byte tempBuffer = 0;

			// Get enough bits to fill a byte.
			for(int i=0; i<8; i++) 
			{
				// Read a bit and make sure we were able to get one.
				// Then store it into our byte.
				int bit = ReadBit();
				if (bit < 0) return bit;
				tempBuffer = (byte)(tempBuffer | (bit << (7-i)));
			}

			// Return the byte.
			return tempBuffer;
		}

		/// <summary>Read a series of bits from the input stream and store them in an array.</summary>
		/// <param name='bits'>The destination buffer for the read bits.</param>
		/// <param name='offset'>The position in the buffer at which to begin storing the read bits.</param>
		/// <param name='count'>The number of bytes to read.</param>
		/// <returns>The number of bits actually read.</returns>
		public int Read(int [] bits, int offset, int count)
		{
			// Read each bit.  If it is valid, store it to the buffer.
			// Otherwise return how many bytes we've already read.  If we read
			// all required bytes, return the requested number.
			for(int i=offset; i<offset+count; i++) 
			{
				int bit = ReadBit();
				if (bit >= 0) bits[i] = bit;
				else return i-offset;
			}
			return count;
		}
        
		/// <summary>Read an array of bytes from the input stream.</summary>
		/// <param name='buffer'>The destination buffer for the read bytes.</param>
		/// <param name='offset'>The position in the buffer at which to begin storing the read bytes.</param>
		/// <param name='count'>The number of bytes to read.</param>
		/// <returns>The number of bytes actually read.</returns>
		public override int Read(byte [] buffer, int offset, int count)
		{
			// Read each byte.  If it is valid, store it to the buffer.
			// Otherwise return how many bytes we've already read.  If we read
			// all required bytes, return the requested number.
			for(int i=offset; i<offset+count; i++) 
			{
				int readByte = ReadByte();
				if (readByte >= 0) buffer[i] = (byte)readByte;
				else return i-offset;
			}
			return count;
		}
		#endregion

		#region Other Stream Operations
		/// <summary>Flushes the stream underlying the BitStream.</summary>
		public override void Flush() 
		{ 
			// Just flush the base stream.  This may not flush up to 8 bits still stored in
			// our buffer, but flushing those could cause problems if there is more writing
			// to be done.
			_baseStream.Flush();
		}
        
		/// <summary>Flushes the last bits to the underlying stream and closes it.</summary>
		public override void Close() 
		{
			// Only do work if we're still open
			if (_open)
			{
				// If there are any bits remaining in the buffer, and if we're writing,
				// write the bits to the buffer.
				if (CanWrite && _curPos != 0) _baseStream.WriteByte(_bitBuffer);

				// Close the stream and reset the buffers for idealogical reasons.
				if (CloseBaseStream) _baseStream.Close(); 
				_baseStream = null;
				_bitBuffer = 0;
				_curPos = 0;

				// Mark as closed and cleaned up
				_open = false;
			}
		}
		#endregion

		#region IDisposable and Finalization
		/// <summary>Clean up after the Huffman stream.</summary>
		void IDisposable.Dispose()
		{
			// Close the stream and suppress finalization
			Close();
			GC.SuppressFinalize(this);
		}

		/// <summary>Clean up after the Huffman stream.</summary>
		~BitStream()
		{
			Close();
		}
		#endregion
        
		#region Not Supported Stream Operations
		/// <summary>Sets the length of the stream.  Unsupported.</summary>
		public override void SetLength(long value) 
		{ 
			throw new NotSupportedException("Can't set the length of a BitStream."); 
		}
        
		/// <summary>Not Supported.</summary>
		public override long Seek(long offset, System.IO.SeekOrigin origin)
		{
			throw new NotSupportedException("Can't seek on a bit stream.");
		}
        
		/// <summary>Not Supported.</summary>
		public override void EndWrite(System.IAsyncResult asyncResult)
		{
			throw new NotSupportedException("Can't asynchronously access a bit stream.");
		}
        
		/// <summary>Not Supported.</summary>
		public override System.IAsyncResult BeginWrite(System.Byte[] buffer, int offset, int count, System.AsyncCallback callback, object state)
		{
			throw new NotSupportedException("Can't asynchronously access a bit stream.");
		}
        
		/// <summary>Not Supported.</summary>
		public override int EndRead(System.IAsyncResult asyncResult)
		{
			throw new NotSupportedException("Can't asynchronously access a bit stream.");
		}
        
		/// <summary>Not Supported.</summary>
		public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback callback, object state)
		{
			throw new NotSupportedException("Can't asynchronously access a bit stream.");
		}
		#endregion
	}

	/// <summary>The direction in which a bit stream is processing bits.</summary>
	public enum StreamDirection 
	{
		/// <summary>Reading from the stream.</summary>
		Read,
		/// <summary>Writing to the stream.</summary>
		Write 
	}
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -