ByteQueue.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls
  6. {
  7. /// <remarks>
  8. /// A queue for bytes.
  9. /// <p>
  10. /// This file could be more optimized.
  11. /// </p>
  12. /// </remarks>
  13. public class ByteQueue
  14. {
  15. /// <returns>The smallest number which can be written as 2^x which is bigger than i.</returns>
  16. public static int NextTwoPow(
  17. int i)
  18. {
  19. /*
  20. * This code is based of a lot of code I found on the Internet
  21. * which mostly referenced a book called "Hacking delight".
  22. *
  23. */
  24. i |= (i >> 1);
  25. i |= (i >> 2);
  26. i |= (i >> 4);
  27. i |= (i >> 8);
  28. i |= (i >> 16);
  29. return i + 1;
  30. }
  31. /**
  32. * The initial size for our buffer.
  33. */
  34. private const int DefaultCapacity = 1024;
  35. /**
  36. * The buffer where we store our data.
  37. */
  38. private byte[] databuf;
  39. /**
  40. * How many bytes at the beginning of the buffer are skipped.
  41. */
  42. private int skipped = 0;
  43. /**
  44. * How many bytes in the buffer are valid data.
  45. */
  46. private int available = 0;
  47. private bool readOnlyBuf = false;
  48. public ByteQueue()
  49. : this(DefaultCapacity)
  50. {
  51. }
  52. public ByteQueue(int capacity)
  53. {
  54. this.databuf = capacity == 0 ? TlsUtilities.EmptyBytes : new byte[capacity];
  55. }
  56. public ByteQueue(byte[] buf, int off, int len)
  57. {
  58. this.databuf = buf;
  59. this.skipped = off;
  60. this.available = len;
  61. this.readOnlyBuf = true;
  62. }
  63. /// <summary>Add some data to our buffer.</summary>
  64. /// <param name="data">A byte-array to read data from.</param>
  65. /// <param name="offset">How many bytes to skip at the beginning of the array.</param>
  66. /// <param name="len">How many bytes to read from the array.</param>
  67. public void AddData(
  68. byte[] data,
  69. int offset,
  70. int len)
  71. {
  72. if (readOnlyBuf)
  73. throw new InvalidOperationException("Cannot add data to read-only buffer");
  74. if ((skipped + available + len) > databuf.Length)
  75. {
  76. int desiredSize = ByteQueue.NextTwoPow(available + len);
  77. if (desiredSize > databuf.Length)
  78. {
  79. byte[] tmp = new byte[desiredSize];
  80. Array.Copy(databuf, skipped, tmp, 0, available);
  81. databuf = tmp;
  82. }
  83. else
  84. {
  85. Array.Copy(databuf, skipped, databuf, 0, available);
  86. }
  87. skipped = 0;
  88. }
  89. Array.Copy(data, offset, databuf, skipped + available, len);
  90. available += len;
  91. }
  92. /// <summary>The number of bytes which are available in this buffer.</summary>
  93. public int Available
  94. {
  95. get { return available; }
  96. }
  97. /// <summary>Copy some bytes from the beginning of the data to the provided <c cref="Stream">Stream</c>.</summary>
  98. /// <param name="output">The <c cref="Stream">Stream</c> to copy the bytes to.</param>
  99. /// <param name="length">How many bytes to copy.</param>
  100. /// <exception cref="InvalidOperationException">If insufficient data is available.</exception>
  101. /// <exception cref="IOException">If there is a problem copying the data.</exception>
  102. public void CopyTo(Stream output, int length)
  103. {
  104. if (length > available)
  105. throw new InvalidOperationException("Cannot copy " + length + " bytes, only got " + available);
  106. output.Write(databuf, skipped, length);
  107. }
  108. /// <summary>Read data from the buffer.</summary>
  109. /// <param name="buf">The buffer where the read data will be copied to.</param>
  110. /// <param name="offset">How many bytes to skip at the beginning of buf.</param>
  111. /// <param name="len">How many bytes to read at all.</param>
  112. /// <param name="skip">How many bytes from our data to skip.</param>
  113. public void Read(
  114. byte[] buf,
  115. int offset,
  116. int len,
  117. int skip)
  118. {
  119. if ((buf.Length - offset) < len)
  120. {
  121. throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
  122. }
  123. if ((available - skip) < len)
  124. {
  125. throw new InvalidOperationException("Not enough data to read");
  126. }
  127. Array.Copy(databuf, skipped + skip, buf, offset, len);
  128. }
  129. /// <summary>Return a <c cref="MemoryStream">MemoryStream</c> over some bytes at the beginning of the data.</summary>
  130. /// <param name="length">How many bytes will be readable.</param>
  131. /// <returns>A <c cref="MemoryStream">MemoryStream</c> over the data.</returns>
  132. /// <exception cref="InvalidOperationException">If insufficient data is available.</exception>
  133. public MemoryStream ReadFrom(int length)
  134. {
  135. if (length > available)
  136. throw new InvalidOperationException("Cannot read " + length + " bytes, only got " + available);
  137. int position = skipped;
  138. available -= length;
  139. skipped += length;
  140. return new MemoryStream(databuf, position, length, false);
  141. }
  142. /// <summary>Remove some bytes from our data from the beginning.</summary>
  143. /// <param name="i">How many bytes to remove.</param>
  144. public void RemoveData(
  145. int i)
  146. {
  147. if (i > available)
  148. {
  149. throw new InvalidOperationException("Cannot remove " + i + " bytes, only got " + available);
  150. }
  151. /*
  152. * Skip the data.
  153. */
  154. available -= i;
  155. skipped += i;
  156. }
  157. public void RemoveData(byte[] buf, int off, int len, int skip)
  158. {
  159. Read(buf, off, len, skip);
  160. RemoveData(skip + len);
  161. }
  162. public byte[] RemoveData(int len, int skip)
  163. {
  164. byte[] buf = new byte[len];
  165. RemoveData(buf, 0, len, skip);
  166. return buf;
  167. }
  168. public void Shrink()
  169. {
  170. if (available == 0)
  171. {
  172. databuf = TlsUtilities.EmptyBytes;
  173. skipped = 0;
  174. }
  175. else
  176. {
  177. int desiredSize = ByteQueue.NextTwoPow(available);
  178. if (desiredSize < databuf.Length)
  179. {
  180. byte[] tmp = new byte[desiredSize];
  181. Array.Copy(databuf, skipped, tmp, 0, available);
  182. databuf = tmp;
  183. skipped = 0;
  184. }
  185. }
  186. }
  187. }
  188. }
  189. #pragma warning restore
  190. #endif