InputBuffer.cs 7.2 KB

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