PendingBuffer.cs 6.1 KB

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