PendingBuffer.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. namespace ICSharpCode.SharpZipLib.Zip.Compression
  2. {
  3. /// <summary>
  4. /// This class is general purpose class for writing data to a buffer.
  5. ///
  6. /// It allows you to write bits as well as bytes
  7. /// Based on DeflaterPending.java
  8. ///
  9. /// author of the original java version : Jochen Hoenicke
  10. /// </summary>
  11. public class PendingBuffer
  12. {
  13. #region Instance Fields
  14. /// <summary>
  15. /// Internal work buffer
  16. /// </summary>
  17. private readonly byte[] buffer;
  18. private int start;
  19. private int end;
  20. private uint bits;
  21. private int bitCount;
  22. #endregion Instance Fields
  23. #region Constructors
  24. /// <summary>
  25. /// construct instance using default buffer size of 4096
  26. /// </summary>
  27. public PendingBuffer() : this(4096)
  28. {
  29. }
  30. /// <summary>
  31. /// construct instance using specified buffer size
  32. /// </summary>
  33. /// <param name="bufferSize">
  34. /// size to use for internal buffer
  35. /// </param>
  36. public PendingBuffer(int bufferSize)
  37. {
  38. buffer = new byte[bufferSize];
  39. }
  40. #endregion Constructors
  41. /// <summary>
  42. /// Clear internal state/buffers
  43. /// </summary>
  44. public void Reset()
  45. {
  46. start = end = bitCount = 0;
  47. }
  48. /// <summary>
  49. /// Write a byte to buffer
  50. /// </summary>
  51. /// <param name="value">
  52. /// The value to write
  53. /// </param>
  54. public void WriteByte(int value)
  55. {
  56. #if DebugDeflation
  57. if (DeflaterConstants.DEBUGGING && (start != 0) )
  58. {
  59. throw new SharpZipBaseException("Debug check: start != 0");
  60. }
  61. #endif
  62. buffer[end++] = unchecked((byte)value);
  63. }
  64. /// <summary>
  65. /// Write a short value to buffer LSB first
  66. /// </summary>
  67. /// <param name="value">
  68. /// The value to write.
  69. /// </param>
  70. public void WriteShort(int value)
  71. {
  72. #if DebugDeflation
  73. if (DeflaterConstants.DEBUGGING && (start != 0) )
  74. {
  75. throw new SharpZipBaseException("Debug check: start != 0");
  76. }
  77. #endif
  78. buffer[end++] = unchecked((byte)value);
  79. buffer[end++] = unchecked((byte)(value >> 8));
  80. }
  81. /// <summary>
  82. /// write an integer LSB first
  83. /// </summary>
  84. /// <param name="value">The value to write.</param>
  85. public void WriteInt(int value)
  86. {
  87. #if DebugDeflation
  88. if (DeflaterConstants.DEBUGGING && (start != 0) )
  89. {
  90. throw new SharpZipBaseException("Debug check: start != 0");
  91. }
  92. #endif
  93. buffer[end++] = unchecked((byte)value);
  94. buffer[end++] = unchecked((byte)(value >> 8));
  95. buffer[end++] = unchecked((byte)(value >> 16));
  96. buffer[end++] = unchecked((byte)(value >> 24));
  97. }
  98. /// <summary>
  99. /// Write a block of data to buffer
  100. /// </summary>
  101. /// <param name="block">data to write</param>
  102. /// <param name="offset">offset of first byte to write</param>
  103. /// <param name="length">number of bytes to write</param>
  104. public void WriteBlock(byte[] block, int offset, int length)
  105. {
  106. #if DebugDeflation
  107. if (DeflaterConstants.DEBUGGING && (start != 0) )
  108. {
  109. throw new SharpZipBaseException("Debug check: start != 0");
  110. }
  111. #endif
  112. System.Array.Copy(block, offset, buffer, end, length);
  113. end += length;
  114. }
  115. /// <summary>
  116. /// The number of bits written to the buffer
  117. /// </summary>
  118. public int BitCount
  119. {
  120. get
  121. {
  122. return bitCount;
  123. }
  124. }
  125. /// <summary>
  126. /// Align internal buffer on a byte boundary
  127. /// </summary>
  128. public void AlignToByte()
  129. {
  130. #if DebugDeflation
  131. if (DeflaterConstants.DEBUGGING && (start != 0) )
  132. {
  133. throw new SharpZipBaseException("Debug check: start != 0");
  134. }
  135. #endif
  136. if (bitCount > 0)
  137. {
  138. buffer[end++] = unchecked((byte)bits);
  139. if (bitCount > 8)
  140. {
  141. buffer[end++] = unchecked((byte)(bits >> 8));
  142. }
  143. }
  144. bits = 0;
  145. bitCount = 0;
  146. }
  147. /// <summary>
  148. /// Write bits to internal buffer
  149. /// </summary>
  150. /// <param name="b">source of bits</param>
  151. /// <param name="count">number of bits to write</param>
  152. public void WriteBits(int b, int count)
  153. {
  154. #if DebugDeflation
  155. if (DeflaterConstants.DEBUGGING && (start != 0) )
  156. {
  157. throw new SharpZipBaseException("Debug check: start != 0");
  158. }
  159. // if (DeflaterConstants.DEBUGGING) {
  160. // //Console.WriteLine("writeBits("+b+","+count+")");
  161. // }
  162. #endif
  163. bits |= (uint)(b << bitCount);
  164. bitCount += count;
  165. if (bitCount >= 16)
  166. {
  167. buffer[end++] = unchecked((byte)bits);
  168. buffer[end++] = unchecked((byte)(bits >> 8));
  169. bits >>= 16;
  170. bitCount -= 16;
  171. }
  172. }
  173. /// <summary>
  174. /// Write a short value to internal buffer most significant byte first
  175. /// </summary>
  176. /// <param name="s">value to write</param>
  177. public void WriteShortMSB(int s)
  178. {
  179. #if DebugDeflation
  180. if (DeflaterConstants.DEBUGGING && (start != 0) )
  181. {
  182. throw new SharpZipBaseException("Debug check: start != 0");
  183. }
  184. #endif
  185. buffer[end++] = unchecked((byte)(s >> 8));
  186. buffer[end++] = unchecked((byte)s);
  187. }
  188. /// <summary>
  189. /// Indicates if buffer has been flushed
  190. /// </summary>
  191. public bool IsFlushed
  192. {
  193. get
  194. {
  195. return end == 0;
  196. }
  197. }
  198. /// <summary>
  199. /// Flushes the pending buffer into the given output array. If the
  200. /// output array is to small, only a partial flush is done.
  201. /// </summary>
  202. /// <param name="output">The output array.</param>
  203. /// <param name="offset">The offset into output array.</param>
  204. /// <param name="length">The maximum number of bytes to store.</param>
  205. /// <returns>The number of bytes flushed.</returns>
  206. public int Flush(byte[] output, int offset, int length)
  207. {
  208. if (bitCount >= 8)
  209. {
  210. buffer[end++] = unchecked((byte)bits);
  211. bits >>= 8;
  212. bitCount -= 8;
  213. }
  214. if (length > end - start)
  215. {
  216. length = end - start;
  217. System.Array.Copy(buffer, start, output, offset, length);
  218. start = 0;
  219. end = 0;
  220. }
  221. else
  222. {
  223. System.Array.Copy(buffer, start, output, offset, length);
  224. start += length;
  225. }
  226. return length;
  227. }
  228. /// <summary>
  229. /// Convert internal buffer to byte array.
  230. /// Buffer is empty on completion
  231. /// </summary>
  232. /// <returns>
  233. /// The internal buffer contents converted to a byte array.
  234. /// </returns>
  235. public byte[] ToByteArray()
  236. {
  237. AlignToByte();
  238. byte[] result = new byte[end - start];
  239. System.Array.Copy(buffer, start, result, 0, result.Length);
  240. start = 0;
  241. end = 0;
  242. return result;
  243. }
  244. }
  245. }