Click here to Skip to main content
15,892,005 members
Articles / Programming Languages / C#

Project Tool

Rate me:
Please Sign up or sign in to vote.
4.69/5 (10 votes)
23 Sep 2007CPOL3 min read 54.6K   1.7K   73  
Backup your C# solution and projects for archive or source code sharing. Temporary or unused files are excluded.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace QiHe.CodeLib.Compress
{
    public class BitStream
    {
        BufferedStream stream;

        public BitStream(Stream stream)
        {
            //this.stream = stream;
            this.stream = new BufferedStream(stream);
        }

        public long Length
        {
            get { return stream.Length; }
        }

        public long Position
        {
            get { return stream.Position; }
            set { stream.Position = value; }
        }

        public bool IsEndReached
        {
            get { return Position == Length; }
        }

        BitArray bitBuffer;
        public int bitsRead = 0;
        int bitsRemained = 0;

        /// <summary>
        /// Read num bits from stream, return as a machine integer stored with the most-significant bit first
        /// return -1 if not enough bits remained.
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public int ReadBitsBigEndian(int num)
        {
            if (num < 1 || num > 16)
            {
                throw new ArgumentOutOfRangeException("number of bits");
            }
            if (num <= bitsRemained)
            {
                int result = GetBinaryInteger(bitBuffer, bitsRead, num);
                bitsRead += num;
                bitsRemained -= num;
                return result;
            }
            else
            {
                int count = num - bitsRemained;
                int bytesToRead = count <= 8 ? 1 : 2;
                byte[] data = ReadBytes(bytesToRead);
                if (data.Length == bytesToRead)
                {
                    int result = GetBinaryInteger(bitBuffer, bitsRead, bitsRemained);
                    bitBuffer = new BitArray(data);
                    result = GetBinaryInteger(result, bitBuffer, 0, count);
                    bitsRead = count;
                    bitsRemained = bytesToRead * 8 - count;
                    return result;
                }
                else
                {
                    return -1;
                }
            }
        }

        private static int GetBinaryInteger(BitArray array, int start, int count)
        {
            return GetBinaryInteger(0, array, start, count);
        }

        private static int GetBinaryInteger(int initial, BitArray array, int start, int count)
        {
            int result = initial;
            for (int n = start; n < start + count; n++)
            {
                int bit = array[n] ? 1 : 0;
                result = result * 2 + bit;
            }
            return result;
        }

        /// <summary>
        /// Read Bits Little Endian
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public int ReadBits(int num)
        {
            int result = ReadBitsBigEndian(num);
            BitArray bits = new BitArray(BitConverter.GetBytes(result));
            return GetBinaryInteger(0, bits, 0, num);
        }

        /// <summary>
        /// Read one bit.
        /// </summary>
        /// <returns></returns>
        public int ReadBit()
        {
            return ReadBitsBigEndian(1);
        }

        /// <summary>
        /// go to the next byte boundary, former unread bits are ignored.
        /// </summary>
        public void GotoNextByte()
        {
            bitsRead = 0;
            bitsRemained = 0;
        }

        public byte ReadByte()
        {
            return (byte)stream.ReadByte();
        }

        public int ReadByte(long offset)
        {
            stream.Position = offset;
            return stream.ReadByte();
        }

        public byte[] ReadBytes(int count)
        {
            byte[] data = new byte[count];
            int bytesRead = stream.Read(data, 0, count);
            if (bytesRead == count)
            {
                return data;
            }
            else
            {
                byte[] bytes = new byte[bytesRead];
                if (bytesRead > 0)
                {
                    Array.Copy(data, bytes, bytesRead);
                }
                return bytes;
            }
        }

        public byte[] ReadToEnd()
        {
            int bytesRemained = (int)(Length - Position);
            return ReadBytes(bytesRemained);
        }

        public byte[] PeekBytes(int count)
        {
            return PeekBytes(this.Position, count);
        }

        public byte[] PeekBytes(long offset, int length)
        {
            long pos = this.Position;
            this.Position = offset;
            byte[] data = ReadBytes(length);
            this.Position = pos;
            return data;
        }

        public ushort ReadUInt16()
        {
            byte[] data = ReadBytes(2);
            return BitConverter.ToUInt16(data, 0);
        }

        uint writebuffer = 0;
        public int bitsWritten = 0;
        public void WriteBits(int value, int num)
        {
            if (num == 0) return;
            BitArray bits = new BitArray(BitConverter.GetBytes(value));
            for (int i = 0; i < num; i++)
            {
                uint bit = bits[i] ? 0x80000000 : 0;
                writebuffer = (writebuffer >> 1) | bit;

                bitsWritten++;
                if (bitsWritten == 32)
                {
                    WriteBytes(BitConverter.GetBytes(writebuffer));
                    ClearWriteBuffer();
                }
            }
        }

        public void WriteBitsBigEndian(int value, int num)
        {
            BitArray bits = new BitArray(BitConverter.GetBytes(value));
            int result = GetBinaryInteger(0, bits, 0, num);
            WriteBits(result, num);
        }

        public void WriteBit(bool bit)
        {
            WriteBit(bit ? 1 : 0);
        }

        public void WriteBit(int bit)
        {
            WriteBits(bit, 1);
        }

        private void ClearWriteBuffer()
        {
            writebuffer = 0;
            bitsWritten = 0;
        }

        /// <summary>
        /// Flush bits in buffer, zero bits are apended to form a byte border.
        /// Or flush read when reading.
        /// </summary>
        public void Flush()
        {
            if (bitsWritten > 0)
            {
                writebuffer = writebuffer >> (32 - bitsWritten);
                byte[] bytes = BitConverter.GetBytes(writebuffer);
                int count = bitsWritten / 8;
                if (bitsWritten % 8 != 0)
                {
                    count++;
                }
                stream.Write(bytes, 0, count);
                ClearWriteBuffer();
            }
            stream.Flush();
        }

        public void WriteByte(byte value)
        {
            stream.WriteByte(value);
        }

        public void WriteBytes(byte[] data)
        {
            stream.Write(data, 0, data.Length);
        }

        public void WriteBytes(byte[] data, int offset, int count)
        {
            stream.Write(data, offset, count);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect YunCheDa Hangzhou
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions