The Labs \ Source Viewer \ SSCLI \ System.IO.Compression \ InputBuffer

  1. //------------------------------------------------------------------------------
  2. // <copyright file="InputBuffer.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.IO.Compression
  16. {
  17.     using System;
  18.     using System.Diagnostics;
  19.    
  20.     // This class can be used to read bits from an byte array quickly.
  21.     // Normally we get bits from 'bitBuffer' field and bitsInBuffer stores
  22.     // the number of bits available in 'BitBuffer'.
  23.     // When we used up the bits in bitBuffer, we will try to get byte from
  24.     // the byte array and copy the byte to appropiate position in bitBuffer.
  25.     //
  26.     // The byte array is not reused. We will go from 'start' to 'end'.
  27.     // When we reach the end, most read operations will return -1,
  28.     // which means we are running out of input.
  29.    
  30.     internal class InputBuffer
  31.     {
  32.        
  33.         private byte[] buffer;
  34.         // byte array to store input
  35.         private int start;
  36.         // start poisition of the buffer
  37.         private int end;
  38.         // end position of the buffer
  39.         private uint bitBuffer = 0;
  40.         // store the bits here, we can quickly shift in this buffer
  41.         private int bitsInBuffer = 0;
  42.         // number of bits available in bitBuffer
  43.         // Total bits available in the input buffer
  44.         public int AvailableBits {
  45.             get { return bitsInBuffer; }
  46.         }
  47.        
  48.         // Total bytes available in the input buffer
  49.         public int AvailableBytes {
  50.             get { return (end - start) + (bitsInBuffer / 8); }
  51.         }
  52.        
  53.         // Ensure that count bits are in the bit buffer.
  54.         // Returns false if input is not sufficient to make this true.
  55.         // Count can be up to 16.
  56.         public bool EnsureBitsAvailable(int count)
  57.         {
  58.             Debug.Assert(0 < count && count <= 16, "count is invalid.");
  59.            
  60.             // manual inlining to improve perf
  61.             if (bitsInBuffer < count) {
  62.                 if (NeedsInput()) {
  63.                     return false;
  64.                 }
  65.                 // insert a byte to bitbuffer
  66.                 bitBuffer |= (uint)buffer[start++] << bitsInBuffer;
  67.                 bitsInBuffer += 8;
  68.                
  69.                 if (bitsInBuffer < count) {
  70.                     if (NeedsInput()) {
  71.                         return false;
  72.                     }
  73.                     // insert a byte to bitbuffer
  74.                     bitBuffer |= (uint)buffer[start++] << bitsInBuffer;
  75.                     bitsInBuffer += 8;
  76.                 }
  77.             }
  78.            
  79.             return true;
  80.         }
  81.        
  82.         // This function will try to load 16 or more bits into bitBuffer.
  83.         // It returns whatever is contained in bitBuffer after loading.
  84.         // The main difference between this and GetBits is that this will
  85.         // never return -1. So the caller needs to check AvailableBits to
  86.         // see how many bits are available.
  87.         public uint TryLoad16Bits()
  88.         {
  89.             if (bitsInBuffer < 8) {
  90.                 if (start < end) {
  91.                     bitBuffer |= (uint)buffer[start++] << bitsInBuffer;
  92.                     bitsInBuffer += 8;
  93.                 }
  94.                
  95.                 if (start < end) {
  96.                     bitBuffer |= (uint)buffer[start++] << bitsInBuffer;
  97.                     bitsInBuffer += 8;
  98.                 }
  99.             }
  100.             else if (bitsInBuffer < 16) {
  101.                 if (start < end) {
  102.                     bitBuffer |= (uint)buffer[start++] << bitsInBuffer;
  103.                     bitsInBuffer += 8;
  104.                 }
  105.             }
  106.            
  107.             return bitBuffer;
  108.         }
  109.        
  110.         private uint GetBitMask(int count)
  111.         {
  112.             return ((uint)1 << count) - 1;
  113.         }
  114.        
  115.         // Gets count bits from the input buffer. Returns -1 if not enough bits available.
  116.         public int GetBits(int count)
  117.         {
  118.             Debug.Assert(0 < count && count <= 16, "count is invalid.");
  119.            
  120.             if (!EnsureBitsAvailable(count)) {
  121.                 return -1;
  122.             }
  123.            
  124.             int result = (int)(bitBuffer & GetBitMask(count));
  125.             bitBuffer >>= count;
  126.             bitsInBuffer -= count;
  127.             return result;
  128.         }
  129.        
  130.         /// Copies length bytes from input buffer to output buffer starting
  131.         /// at output[offset]. You have to make sure, that the buffer is
  132.         /// byte aligned. If not enough bytes are available, copies fewer
  133.         /// bytes.
  134.         /// Returns the number of bytes copied, 0 if no byte is available.
  135.         public int CopyTo(byte[] output, int offset, int length)
  136.         {
  137.             Debug.Assert(output != null, "");
  138.             Debug.Assert(offset >= 0, "");
  139.             Debug.Assert(length >= 0, "");
  140.             Debug.Assert(offset <= output.Length - length, "");
  141.             Debug.Assert((bitsInBuffer % 8) == 0, "");
  142.            
  143.             // Copy the bytes in bitBuffer first.
  144.             int bytesFromBitBuffer = 0;
  145.             while (bitsInBuffer > 0 && length > 0) {
  146.                 output[offset++] = (byte)bitBuffer;
  147.                 bitBuffer >>= 8;
  148.                 bitsInBuffer -= 8;
  149.                 length--;
  150.                 bytesFromBitBuffer++;
  151.             }
  152.            
  153.             if (length == 0) {
  154.                 return bytesFromBitBuffer;
  155.             }
  156.            
  157.             int avail = end - start;
  158.             if (length > avail) {
  159.                 length = avail;
  160.             }
  161.            
  162.             Array.Copy(buffer, start, output, offset, length);
  163.             start += length;
  164.             return bytesFromBitBuffer + length;
  165.         }
  166.        
  167.         // Return true is all input bytes are used.
  168.         // This means the caller can call SetInput to add more input.
  169.         public bool NeedsInput()
  170.         {
  171.             return start == end;
  172.         }
  173.        
  174.         // Set the byte array to be processed.
  175.         // All the bits remained in bitBuffer will be processed before the new bytes.
  176.         // We don't clone the byte array here since it is expensive.
  177.         // The caller should make sure after a buffer is passed in.
  178.         // It will not be changed before calling this function again.
  179.        
  180.         public void SetInput(byte[] buffer, int offset, int length)
  181.         {
  182.             Debug.Assert(buffer != null, "");
  183.             Debug.Assert(offset >= 0, "");
  184.             Debug.Assert(length >= 0, "");
  185.             Debug.Assert(offset <= buffer.Length - length, "");
  186.             Debug.Assert(start == end, "");
  187.            
  188.             this.buffer = buffer;
  189.             start = offset;
  190.             end = offset + length;
  191.         }
  192.        
  193.         // Skip n bits in the buffer
  194.         public void SkipBits(int n)
  195.         {
  196.             Debug.Assert(bitsInBuffer >= n, "No enough bits in the buffer, Did you call EnsureBitsAvailable?");
  197.             bitBuffer >>= n;
  198.             bitsInBuffer -= n;
  199.         }
  200.        
  201.         // Skips to the next byte boundary.
  202.         public void SkipToByteBoundary()
  203.         {
  204.             bitBuffer >>= (bitsInBuffer % 8);
  205.             bitsInBuffer = bitsInBuffer - (bitsInBuffer % 8);
  206.         }
  207.     }
  208. }

Developer Fusion