BitStream.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Shared / MS / Internal / Ink / BitStream.cs / 1305600 / BitStream.cs

                            using MS.Utility; 
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic; 
using System.Windows;
using System.Diagnostics; 
 
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 

namespace MS.Internal.Ink
{
    ///  
    /// A stream-style reader for retrieving packed bits from a byte array
    ///  
    /// This bits should packed into the leftmost position in each byte. 
    /// For compatibility purposes with the v1 ISF encoder and decoder, the order of the
    /// packing must not be changed. This code is a from-scratch rewrite of the BitStream 
    /// natice C++ class in the v1 Ink code, but still maintaining the same packing
    /// behavior.
    internal class BitStreamReader
    { 
        /// 
        /// Create a new BitStreamReader to unpack the bits in a buffer of bytes 
        ///  
        /// Buffer of bytes
        internal BitStreamReader(byte[] buffer) 
        {
            Debug.Assert(buffer != null);

            _byteArray = buffer; 
            _bufferLengthInBits = (uint)buffer.Length * (uint)Native.BitsPerByte;
        } 
 
        /// 
        /// Create a new BitStreamReader to unpack the bits in a buffer of bytes 
        /// 
        /// Buffer of bytes
        /// The index to start reading at
        internal BitStreamReader(byte[] buffer, int startIndex) 
        {
            Debug.Assert(buffer != null); 
 
            if (startIndex < 0 || startIndex >= buffer.Length)
            { 
                throw new ArgumentOutOfRangeException("startIndex");
            }
            _byteArray = buffer;
            _byteArrayIndex = startIndex; 
            _bufferLengthInBits = (uint)(buffer.Length - startIndex) * (uint)Native.BitsPerByte;
        } 
 
        /// 
        /// Create a new BitStreamReader to unpack the bits in a buffer of bytes 
        /// and enforce a maximum buffer read length
        /// 
        /// Buffer of bytes
        /// Maximum number of bytes to read from the buffer 
        internal BitStreamReader(byte[] buffer, uint bufferLengthInBits)
            : this(buffer) 
        { 
            if (bufferLengthInBits > (buffer.Length * Native.BitsPerByte))
            { 
                throw new ArgumentOutOfRangeException("bufferLengthInBits", SR.Get(SRID.InvalidBufferLength));
            }

            _bufferLengthInBits = bufferLengthInBits; 
        }
 
        ///  
        /// Read a specified number of bits from the stream into a long
        ///  
        internal long ReadUInt64(int countOfBits)
        {
            // we only support 1-64 bits currently, not multiple bytes, and not 0 bits
            if (countOfBits > Native.BitsPerLong || countOfBits <= 0) 
            {
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange)); 
            } 
            long retVal = 0;
            while (countOfBits > 0) 
            {
                int countToRead = (int)Native.BitsPerByte;
                if (countOfBits < 8)
                { 
                    countToRead = countOfBits;
                } 
                //make room 
                retVal <<= countToRead;
                byte b = ReadByte(countToRead); 
                retVal |= (long)b;
                countOfBits -= countToRead;
            }
            return retVal; 
        }
 
        ///  
        /// Read a single UInt16 from the byte[]
        ///  
        /// 
        /// 
        internal ushort ReadUInt16(int countOfBits)
        { 
            // we only support 1-16 bits currently, not multiple bytes, and not 0 bits
            if (countOfBits > Native.BitsPerShort || countOfBits <= 0) 
            { 
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange));
            } 

            ushort retVal = 0;
            while (countOfBits > 0)
            { 
                int countToRead = (int)Native.BitsPerByte;
                if (countOfBits < 8) 
                { 
                    countToRead = countOfBits;
                } 
                //make room
                retVal <<= countToRead;
                byte b = ReadByte(countToRead);
                retVal |= (ushort)b; 
                countOfBits -= countToRead;
            } 
            return retVal; 
        }
 
        /// 
        /// Read a specified number of bits from the stream in reverse byte order
        /// 
        internal uint ReadUInt16Reverse(int countOfBits) 
        {
            // we only support 1-8 bits currently, not multiple bytes, and not 0 bits 
            if (countOfBits > Native.BitsPerShort|| countOfBits <= 0) 
            {
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange)); 
            }

            ushort retVal = 0;
            int fullBytesRead = 0; 
            while (countOfBits > 0)
            { 
                int countToRead = (int)Native.BitsPerByte; 
                if (countOfBits < 8)
                { 
                    countToRead = countOfBits;
                }
                //make room
                ushort b = (ushort)ReadByte(countToRead); 
                b <<= (fullBytesRead * Native.BitsPerByte);
                retVal |= b; 
                fullBytesRead++; 
                countOfBits -= countToRead;
            } 
            return retVal;
        }

        ///  
        /// Read a specified number of bits from the stream into a single byte
        ///  
        internal uint ReadUInt32(int countOfBits) 
        {
            // we only support 1-8 bits currently, not multiple bytes, and not 0 bits 
            if (countOfBits > Native.BitsPerInt || countOfBits <= 0)
            {
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange));
            } 

            uint retVal = 0; 
            while (countOfBits > 0) 
            {
                int countToRead = (int)Native.BitsPerByte; 
                if (countOfBits < 8)
                {
                    countToRead = countOfBits;
                } 
                //make room
                retVal <<= countToRead; 
                byte b = ReadByte(countToRead); 
                retVal |= (uint)b;
                countOfBits -= countToRead; 
            }
            return retVal;
        }
 
        /// 
        /// Read a specified number of bits from the stream in reverse byte order 
        ///  
        internal uint ReadUInt32Reverse(int countOfBits)
        { 
            // we only support 1-8 bits currently, not multiple bytes, and not 0 bits
            if (countOfBits > Native.BitsPerInt || countOfBits <= 0)
            {
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange)); 
            }
 
            uint retVal = 0; 
            int fullBytesRead = 0;
            while (countOfBits > 0) 
            {
                int countToRead = (int)Native.BitsPerByte;
                if (countOfBits < 8)
                { 
                    countToRead = countOfBits;
                } 
                //make room 
                uint b = (uint)ReadByte(countToRead);
                b <<= (fullBytesRead * Native.BitsPerByte); 
                retVal |= b;
                fullBytesRead++;
                countOfBits -= countToRead;
            } 
            return retVal;
        } 
 
        /// 
        /// Reads a single bit from the buffer 
        /// 
        /// 
        internal bool ReadBit()
        { 
            byte b = ReadByte(1);
            return ((b & 1) == 1); 
        } 

        ///  
        /// Read a specified number of bits from the stream into a single byte
        /// 
        /// The number of bits to unpack
        /// A single byte that contains up to 8 packed bits 
        /// For example, if 2 bits are read from the stream, then a full byte
        /// will be created with the least significant bits set to the 2 unpacked bits 
        /// from the stream 
        internal byte ReadByte(int countOfBits)
        { 
            // if the end of the stream has been reached, then throw an exception
            if (EndOfStream)
            {
                throw new System.IO.EndOfStreamException(SR.Get(SRID.EndOfStreamReached)); 
            }
 
            // we only support 1-8 bits currently, not multiple bytes, and not 0 bits 
            if (countOfBits > Native.BitsPerByte || countOfBits <= 0)
            { 
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange));
            }

            if (countOfBits > _bufferLengthInBits) 
            {
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsGreatThanRemainingBits)); 
            } 

            _bufferLengthInBits -= (uint)countOfBits; 

            // initialize return byte to 0 before reading from the cache
            byte returnByte = 0;
 
            // if the partial bit cache contains more bits than requested, then read the
            //      cache only 
            if (_cbitsInPartialByte >= countOfBits) 
            {
                // retrieve the requested count of most significant bits from the cache 
                //      and store them in the least significant positions in the return byte
                int rightShiftPartialByteBy = Native.BitsPerByte - countOfBits;
                returnByte = (byte)(_partialByte >> rightShiftPartialByteBy);
 
                // reposition any unused portion of the cache in the most significant part of the bit cache
                unchecked // disable overflow checking since we are intentionally throwing away 
                            //  the significant bits 
                {
                    _partialByte <<= countOfBits; 
                }
                // update the bit count in the cache
                _cbitsInPartialByte -= countOfBits;
            } 
                // otherwise, we need to retrieve more full bytes from the stream
            else 
            { 
                // retrieve the next full byte from the stream
                byte nextByte = _byteArray[_byteArrayIndex]; 
                _byteArrayIndex++;

                //right shift partial byte to get it ready to or with the partial next byte
                int rightShiftPartialByteBy = Native.BitsPerByte - countOfBits; 
                returnByte = (byte)(_partialByte >> rightShiftPartialByteBy);
 
                // now copy the remaining chunk of the newly retrieved full byte 
                int rightShiftNextByteBy = Math.Abs((countOfBits - _cbitsInPartialByte) - Native.BitsPerByte);
                returnByte |= (byte)(nextByte >> rightShiftNextByteBy); 

                // update the partial bit cache with the remainder of the newly retrieved full byte
                unchecked // disable overflow checking since we are intentionally throwing away
                            //  the significant bits 
                {
                    _partialByte = (byte)(nextByte << (countOfBits - _cbitsInPartialByte)); 
                } 

                _cbitsInPartialByte = Native.BitsPerByte - (countOfBits - _cbitsInPartialByte); 
            }
            return returnByte;
        }
 
        /// 
        /// Since the return value of Read cannot distinguish between valid and invalid 
        /// data (e.g. 8 bits set), the EndOfStream property detects when there is no more 
        /// data to read.
        ///  
        /// True if stream end has been reached
        internal bool EndOfStream
        {
            get 
            {
                return 0 == _bufferLengthInBits; 
            } 
        }
 
        /// 
        /// The current read index in the array
        /// 
        internal int CurrentIndex 
        {
            get 
            { 
                //_byteArrayIndex is always advanced to the next index
                // so we always decrement before returning 
                return _byteArrayIndex - 1;
            }
        }
 

        // Privates 
        // reference to the source byte buffer to read from 
        private byte[] _byteArray = null;
 
        // maximum length of buffer to read in bits
        private uint _bufferLengthInBits = 0;

            // the index in the source buffer for the next byte to be read 
        private int _byteArrayIndex = 0;
 
            // since the bits from multiple inputs can be packed into a single byte 
            //  (e.g. 2 bits per input fits 4 per byte), we use this field as a cache
            //  of the remaining partial bits. 
        private byte _partialByte = 0;

            // the number of bits (partial byte) left to read in the overlapped byte field
        private int _cbitsInPartialByte = 0; 
    }
 
    ///  
    /// A stream-like writer for packing bits into a byte buffer
    ///  
    /// This class is to be used with the BitStreamReader for reading
    /// and writing bytes. Note that the bytes should be read in the same order
    /// and lengths as they were written to retrieve the same values.
    /// See remarks in BitStreamReader regarding compatibility with the native C++ 
    /// BitStream class.
    internal class BitStreamWriter 
    { 
        /// 
        /// Create a new bit writer that writes to the target buffer 
        /// 
        /// 
        internal BitStreamWriter(List bufferToWriteTo)
        { 
            if (bufferToWriteTo == null)
            { 
                throw new ArgumentNullException("bufferToWriteTo"); 
            }
            _targetBuffer = bufferToWriteTo; 
        }

        /// 
        /// Writes the count of bits from the int to the left packed buffer 
        /// 
        ///  
        ///  
        internal void Write(uint bits, int countOfBits)
        { 
            // validate that a subset of the bits in a single byte are being written
            if (countOfBits <= 0 || countOfBits > Native.BitsPerInt)
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange));
 

            // calculate the number of full bytes 
            //   Example: 10 bits would require 1 full byte 
            int fullBytes = countOfBits / Native.BitsPerByte;
 
            // calculate the number of bits that spill beyond the full byte boundary
            //   Example: 10 buttons would require 2 extra bits (8 fit in a full byte)
            int bitsToWrite = countOfBits % Native.BitsPerByte;
 
            for (; fullBytes >= 0; fullBytes--)
            { 
                byte byteOfData = (byte)(bits >> (fullBytes * Native.BitsPerByte)); 
                //
                // write 8 or less bytes to the bitwriter 
                // checking for 0 handles the case where we're writing 8, 16 or 24 bytes
                // and bitsToWrite is initialize to zero
                //
                if (bitsToWrite > 0) 
                {
                    Write(byteOfData, bitsToWrite); 
                } 
                if (fullBytes > 0)
                { 
                    bitsToWrite = Native.BitsPerByte;
                }
            }
        } 

        ///  
        /// Writes the count of bits from the int to the buffer in reverse order 
        /// 
        ///  
        /// 
        internal void WriteReverse(uint bits, int countOfBits)
        {
            // validate that a subset of the bits in a single byte are being written 
            if (countOfBits <= 0 || countOfBits > Native.BitsPerInt)
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange)); 
 
            // calculate the number of full bytes
            //   Example: 10 bits would require 1 full byte 
            int fullBytes = countOfBits / Native.BitsPerByte;

            // calculate the number of bits that spill beyond the full byte boundary
            //   Example: 10 buttons would require 2 extra bits (8 fit in a full byte) 
            int bitsToWrite = countOfBits % Native.BitsPerByte;
            if (bitsToWrite > 0) 
            { 
                fullBytes++;
            } 
            for (int x = 0; x < fullBytes; x++)
            {
                byte byteOfData = (byte)(bits >> (x * Native.BitsPerByte));
                Write(byteOfData, Native.BitsPerByte); 
            }
        } 
 
        /// 
        /// Write a specific number of bits from byte input into the stream 
        /// 
        /// The byte to read the bits from
        /// The number of bits to read
        internal void Write(byte bits, int countOfBits) 
        {
            // validate that a subset of the bits in a single byte are being written 
            if (countOfBits <= 0 || countOfBits > Native.BitsPerByte) 
                throw new ArgumentOutOfRangeException("countOfBits", countOfBits, SR.Get(SRID.CountOfBitsOutOfRange));
 
            byte buffer;
                // if there is remaining bits in the last byte in the stream
                //      then use those first
            if (_remaining > 0) 
            {
                // retrieve the last byte from the stream, update it, and then replace it 
                buffer = _targetBuffer[_targetBuffer.Count - 1]; 
                    // if the remaining bits aren't enough then just copy the significant bits
                    //      of the input into the remainder 
                if (countOfBits > _remaining)
                {
                    buffer |= (byte)((bits & (0xFF >> (Native.BitsPerByte - countOfBits))) >> (countOfBits - _remaining));
                } 
                    // otherwise, copy the entire set of input bits into the remainder
                else 
                { 
                    buffer |= (byte)((bits & (0xFF >> (Native.BitsPerByte - countOfBits))) << (_remaining - countOfBits));
                } 
                _targetBuffer[_targetBuffer.Count - 1] = buffer;
            }

            // if the remainder wasn't large enough to hold the entire input set 
            if (countOfBits > _remaining)
            { 
                  // then copy the uncontained portion of the input set into a temporary byte 
                _remaining = Native.BitsPerByte - (countOfBits - _remaining);
                unchecked // disable overflow checking since we are intentionally throwing away 
                            //  the significant bits
                {
                    buffer = (byte)(bits << _remaining);
                } 
                    // and add it to the target buffer
                _targetBuffer.Add(buffer); 
            } 
            else
            { 
                // otherwise, simply update the amount of remaining bits we have to spare
                _remaining -= countOfBits;
            }
        } 

 
        // the buffer that the bits are written into 
        private List _targetBuffer = null;
 
        // number of free bits remaining in the last byte added to the target buffer
        private int _remaining = 0;
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK