Summary

Class:ICSharpCode.SharpZipLib.Zip.Compression.Streams.StreamManipulator
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\StreamManipulator.cs
Covered lines:51
Uncovered lines:12
Coverable lines:63
Total lines:241
Line coverage:80.9%
Branch coverage:67.6%

Metrics

MethodCyclomatic ComplexitySequence CoverageBranch Coverage
PeekBits(...)3100100
DropBits(...)1100100
GetBits(...)200
SkipToByteBoundary()1100100
CopyBytes(...)886.3680
Reset()1100100
SetInput(...)872.2260

File(s)

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\Streams\StreamManipulator.cs

#LineLine coverage
 1using System;
 2
 3namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
 4{
 5  /// <summary>
 6  /// This class allows us to retrieve a specified number of bits from
 7  /// the input buffer, as well as copy big byte blocks.
 8  ///
 9  /// It uses an int buffer to store up to 31 bits for direct
 10  /// manipulation.  This guarantees that we can get at least 16 bits,
 11  /// but we only need at most 15, so this is all safe.
 12  ///
 13  /// There are some optimizations in this class, for example, you must
 14  /// never peek more than 8 bits more than needed, and you must first
 15  /// peek bits before you may drop them.  This is not a general purpose
 16  /// class but optimized for the behaviour of the Inflater.
 17  ///
 18  /// authors of the original java version : John Leuner, Jochen Hoenicke
 19  /// </summary>
 20  public class StreamManipulator
 21  {
 22    /// <summary>
 23    /// Get the next sequence of bits but don't increase input pointer.  bitCount must be
 24    /// less or equal 16 and if this call succeeds, you must drop
 25    /// at least n - 8 bits in the next call.
 26    /// </summary>
 27    /// <param name="bitCount">The number of bits to peek.</param>
 28    /// <returns>
 29    /// the value of the bits, or -1 if not enough bits available.  */
 30    /// </returns>
 31    public int PeekBits(int bitCount)
 32    {
 1162033       if (bitsInBuffer_ < bitCount) {
 628734         if (windowStart_ == windowEnd_) {
 39635          return -1; // ok
 36        }
 589137        buffer_ |= (uint)((window_[windowStart_++] & 0xff |
 589138                 (window_[windowStart_++] & 0xff) << 8) << bitsInBuffer_);
 589139        bitsInBuffer_ += 16;
 40      }
 1122441      return (int)(buffer_ & ((1 << bitCount) - 1));
 42    }
 43
 44    /// <summary>
 45    /// Drops the next n bits from the input.  You should have called PeekBits
 46    /// with a bigger or equal n before, to make sure that enough bits are in
 47    /// the bit buffer.
 48    /// </summary>
 49    /// <param name="bitCount">The number of bits to drop.</param>
 50    public void DropBits(int bitCount)
 51    {
 1122452      buffer_ >>= bitCount;
 1122453      bitsInBuffer_ -= bitCount;
 1122454    }
 55
 56    /// <summary>
 57    /// Gets the next n bits and increases input pointer.  This is equivalent
 58    /// to <see cref="PeekBits"/> followed by <see cref="DropBits"/>, except for correct error handling.
 59    /// </summary>
 60    /// <param name="bitCount">The number of bits to retrieve.</param>
 61    /// <returns>
 62    /// the value of the bits, or -1 if not enough bits available.
 63    /// </returns>
 64    public int GetBits(int bitCount)
 65    {
 066      int bits = PeekBits(bitCount);
 067       if (bits >= 0) {
 068        DropBits(bitCount);
 69      }
 070      return bits;
 71    }
 72
 73    /// <summary>
 74    /// Gets the number of bits available in the bit buffer.  This must be
 75    /// only called when a previous PeekBits() returned -1.
 76    /// </summary>
 77    /// <returns>
 78    /// the number of bits available.
 79    /// </returns>
 80    public int AvailableBits {
 81      get {
 2382        return bitsInBuffer_;
 83      }
 84    }
 85
 86    /// <summary>
 87    /// Gets the number of bytes available.
 88    /// </summary>
 89    /// <returns>
 90    /// The number of bytes available.
 91    /// </returns>
 92    public int AvailableBytes {
 93      get {
 232794        return windowEnd_ - windowStart_ + (bitsInBuffer_ >> 3);
 95      }
 96    }
 97
 98    /// <summary>
 99    /// Skips to the next byte boundary.
 100    /// </summary>
 101    public void SkipToByteBoundary()
 102    {
 303103      buffer_ >>= (bitsInBuffer_ & 7);
 303104      bitsInBuffer_ &= ~7;
 303105    }
 106
 107    /// <summary>
 108    /// Returns true when SetInput can be called
 109    /// </summary>
 110    public bool IsNeedingInput {
 111      get {
 3355112        return windowStart_ == windowEnd_;
 113      }
 114    }
 115
 116    /// <summary>
 117    /// Copies bytes from input buffer to output buffer starting
 118    /// at output[offset].  You have to make sure, that the buffer is
 119    /// byte aligned.  If not enough bytes are available, copies fewer
 120    /// bytes.
 121    /// </summary>
 122    /// <param name="output">
 123    /// The buffer to copy bytes to.
 124    /// </param>
 125    /// <param name="offset">
 126    /// The offset in the buffer at which copying starts
 127    /// </param>
 128    /// <param name="length">
 129    /// The length to copy, 0 is allowed.
 130    /// </param>
 131    /// <returns>
 132    /// The number of bytes copied, 0 if no bytes were available.
 133    /// </returns>
 134    /// <exception cref="ArgumentOutOfRangeException">
 135    /// Length is less than zero
 136    /// </exception>
 137    /// <exception cref="InvalidOperationException">
 138    /// Bit buffer isnt byte aligned
 139    /// </exception>
 140    public int CopyBytes(byte[] output, int offset, int length)
 141    {
 2376142       if (length < 0) {
 0143        throw new ArgumentOutOfRangeException(nameof(length));
 144      }
 145
 2376146       if ((bitsInBuffer_ & 7) != 0) {
 147        // bits_in_buffer may only be 0 or a multiple of 8
 0148        throw new InvalidOperationException("Bit buffer is not byte aligned!");
 149      }
 150
 2376151      int count = 0;
 2600152       while ((bitsInBuffer_ > 0) && (length > 0)) {
 224153        output[offset++] = (byte)buffer_;
 224154        buffer_ >>= 8;
 224155        bitsInBuffer_ -= 8;
 224156        length--;
 224157        count++;
 158      }
 159
 2376160       if (length == 0) {
 996161        return count;
 162      }
 163
 1380164      int avail = windowEnd_ - windowStart_;
 1380165       if (length > avail) {
 0166        length = avail;
 167      }
 1380168      System.Array.Copy(window_, windowStart_, output, offset, length);
 1380169      windowStart_ += length;
 170
 1380171       if (((windowStart_ - windowEnd_) & 1) != 0) {
 172        // We always want an even number of bytes in input, see peekBits
 210173        buffer_ = (uint)(window_[windowStart_++] & 0xff);
 210174        bitsInBuffer_ = 8;
 175      }
 1380176      return count + length;
 177    }
 178
 179    /// <summary>
 180    /// Resets state and empties internal buffers
 181    /// </summary>
 182    public void Reset()
 183    {
 41184      buffer_ = 0;
 41185      windowStart_ = windowEnd_ = bitsInBuffer_ = 0;
 41186    }
 187
 188    /// <summary>
 189    /// Add more input for consumption.
 190    /// Only call when IsNeedingInput returns true
 191    /// </summary>
 192    /// <param name="buffer">data to be input</param>
 193    /// <param name="offset">offset of first byte of input</param>
 194    /// <param name="count">number of bytes of input to add.</param>
 195    public void SetInput(byte[] buffer, int offset, int count)
 196    {
 1433197       if (buffer == null) {
 0198        throw new ArgumentNullException(nameof(buffer));
 199      }
 200
 1433201       if (offset < 0) {
 0202        throw new ArgumentOutOfRangeException(nameof(offset), "Cannot be negative");
 203      }
 204
 1433205       if (count < 0) {
 0206        throw new ArgumentOutOfRangeException(nameof(count), "Cannot be negative");
 207      }
 208
 1433209       if (windowStart_ < windowEnd_) {
 0210        throw new InvalidOperationException("Old input was not completely processed");
 211      }
 212
 1433213      int end = offset + count;
 214
 215      // We want to throw an ArrayIndexOutOfBoundsException early.
 216      // Note the check also handles integer wrap around.
 1433217       if ((offset > end) || (end > buffer.Length)) {
 0218        throw new ArgumentOutOfRangeException(nameof(count));
 219      }
 220
 1433221       if ((count & 1) != 0) {
 222        // We always want an even number of bytes in input, see PeekBits
 214223        buffer_ |= (uint)((buffer[offset++] & 0xff) << bitsInBuffer_);
 214224        bitsInBuffer_ += 8;
 225      }
 226
 1433227      window_ = buffer;
 1433228      windowStart_ = offset;
 1433229      windowEnd_ = end;
 1433230    }
 231
 232    #region Instance Fields
 233    private byte[] window_;
 234    private int windowStart_;
 235    private int windowEnd_;
 236
 237    private uint buffer_;
 238    private int bitsInBuffer_;
 239    #endregion
 240  }
 241}