ByteQueue.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Tls
  7. {
  8. /// <summary>A queue for bytes. This file could be more optimized.</summary>
  9. public sealed class ByteQueue
  10. {
  11. /// <returns>The smallest number which can be written as 2^x which is bigger than i.</returns>
  12. private static int GetAllocationSize(int i)
  13. {
  14. return Integers.HighestOneBit((256 | i) << 1);
  15. }
  16. /// <summary>The buffer where we store our data.</summary>
  17. private byte[] m_databuf;
  18. /// <summary>How many bytes at the beginning of the buffer are skipped.</summary>
  19. private int m_skipped = 0;
  20. /// <summary>How many bytes in the buffer are valid data.</summary>
  21. private int m_available = 0;
  22. private bool m_readOnlyBuf = false;
  23. public ByteQueue()
  24. : this(0)
  25. {
  26. }
  27. public ByteQueue(int capacity)
  28. {
  29. this.m_databuf = capacity == 0 ? TlsUtilities.EmptyBytes : new byte[capacity];
  30. }
  31. public ByteQueue(byte[] buf, int off, int len)
  32. {
  33. this.m_databuf = buf;
  34. this.m_skipped = off;
  35. this.m_available = len;
  36. this.m_readOnlyBuf = true;
  37. }
  38. /// <summary>Add some data to our buffer.</summary>
  39. /// <param name="buf">A byte-array to read data from.</param>
  40. /// <param name="off">How many bytes to skip at the beginning of the array.</param>
  41. /// <param name="len">How many bytes to read from the array.</param>
  42. public void AddData(byte[] buf, int off, int len)
  43. {
  44. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  45. AddData(buf.AsSpan(off, len));
  46. #else
  47. if (m_readOnlyBuf)
  48. throw new InvalidOperationException("Cannot add data to read-only buffer");
  49. if (m_available == 0)
  50. {
  51. if (len > m_databuf.Length)
  52. {
  53. int desiredSize = GetAllocationSize(len);
  54. m_databuf = new byte[desiredSize];
  55. }
  56. m_skipped = 0;
  57. }
  58. else if ((m_skipped + m_available + len) > m_databuf.Length)
  59. {
  60. int desiredSize = GetAllocationSize(m_available + len);
  61. if (desiredSize > m_databuf.Length)
  62. {
  63. byte[] tmp = new byte[desiredSize];
  64. Array.Copy(m_databuf, m_skipped, tmp, 0, m_available);
  65. m_databuf = tmp;
  66. }
  67. else
  68. {
  69. Array.Copy(m_databuf, m_skipped, m_databuf, 0, m_available);
  70. }
  71. m_skipped = 0;
  72. }
  73. Array.Copy(buf, off, m_databuf, m_skipped + m_available, len);
  74. m_available += len;
  75. #endif
  76. }
  77. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  78. public void AddData(ReadOnlySpan<byte> buffer)
  79. {
  80. if (m_readOnlyBuf)
  81. throw new InvalidOperationException("Cannot add data to read-only buffer");
  82. int len = buffer.Length;
  83. if (m_available == 0)
  84. {
  85. if (len > m_databuf.Length)
  86. {
  87. int desiredSize = GetAllocationSize(len);
  88. m_databuf = new byte[desiredSize];
  89. }
  90. m_skipped = 0;
  91. }
  92. else if ((m_skipped + m_available + len) > m_databuf.Length)
  93. {
  94. int desiredSize = GetAllocationSize(m_available + len);
  95. if (desiredSize > m_databuf.Length)
  96. {
  97. byte[] tmp = new byte[desiredSize];
  98. Array.Copy(m_databuf, m_skipped, tmp, 0, m_available);
  99. m_databuf = tmp;
  100. }
  101. else
  102. {
  103. Array.Copy(m_databuf, m_skipped, m_databuf, 0, m_available);
  104. }
  105. m_skipped = 0;
  106. }
  107. buffer.CopyTo(m_databuf.AsSpan(m_skipped + m_available));
  108. m_available += len;
  109. }
  110. #endif
  111. /// <returns>The number of bytes which are available in this buffer.</returns>
  112. public int Available
  113. {
  114. get { return m_available; }
  115. }
  116. /// <summary>Copy some bytes from the beginning of the data to the provided <see cref="Stream"/>.</summary>
  117. /// <param name="output">The <see cref="Stream"/> to copy the bytes to.</param>
  118. /// <param name="length">How many bytes to copy.</param>
  119. public void CopyTo(Stream output, int length)
  120. {
  121. if (length > m_available)
  122. throw new InvalidOperationException("Cannot copy " + length + " bytes, only got " + m_available);
  123. output.Write(m_databuf, m_skipped, length);
  124. }
  125. /// <summary>Read data from the buffer.</summary>
  126. /// <param name="buf">The buffer where the read data will be copied to.</param>
  127. /// <param name="offset">How many bytes to skip at the beginning of buf.</param>
  128. /// <param name="len">How many bytes to read at all.</param>
  129. /// <param name="skip">How many bytes from our data to skip.</param>
  130. public void Read(byte[] buf, int offset, int len, int skip)
  131. {
  132. if ((buf.Length - offset) < len)
  133. {
  134. throw new ArgumentException("Buffer size of " + buf.Length
  135. + " is too small for a read of " + len + " bytes");
  136. }
  137. if ((m_available - skip) < len)
  138. {
  139. throw new InvalidOperationException("Not enough data to read");
  140. }
  141. Array.Copy(m_databuf, m_skipped + skip, buf, offset, len);
  142. }
  143. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  144. public void Read(Span<byte> buffer, int skip)
  145. {
  146. if ((m_available - skip) < buffer.Length)
  147. throw new InvalidOperationException("Not enough data to read");
  148. buffer.CopyFrom(m_databuf.AsSpan(m_skipped + skip));
  149. }
  150. #endif
  151. /// <summary>Return a <see cref="HandshakeMessageInput"/> over some bytes at the beginning of the data.
  152. /// </summary>
  153. /// <param name="length">How many bytes will be readable.</param>
  154. /// <returns>A <see cref="HandshakeMessageInput"/> over the data.</returns>
  155. internal HandshakeMessageInput ReadHandshakeMessage(int length)
  156. {
  157. if (length > m_available)
  158. throw new InvalidOperationException("Cannot read " + length + " bytes, only got " + m_available);
  159. int position = m_skipped;
  160. m_available -= length;
  161. m_skipped += length;
  162. return new HandshakeMessageInput(m_databuf, position, length);
  163. }
  164. public int ReadInt32()
  165. {
  166. if (m_available < 4)
  167. throw new InvalidOperationException("Not enough data to read");
  168. return TlsUtilities.ReadInt32(m_databuf, m_skipped);
  169. }
  170. public int ReadUint16(int skip)
  171. {
  172. if (m_available < skip + 2)
  173. throw new InvalidOperationException("Not enough data to read");
  174. return TlsUtilities.ReadUint16(m_databuf, m_skipped + skip);
  175. }
  176. /// <summary>Remove some bytes from our data from the beginning.</summary>
  177. /// <param name="i">How many bytes to remove.</param>
  178. public void RemoveData(int i)
  179. {
  180. if (i > m_available)
  181. throw new InvalidOperationException("Cannot remove " + i + " bytes, only got " + m_available);
  182. /*
  183. * Skip the data.
  184. */
  185. m_available -= i;
  186. m_skipped += i;
  187. }
  188. /// <summary>Remove data from the buffer.</summary>
  189. /// <param name="buf">The buffer where the removed data will be copied to.</param>
  190. /// <param name="off">How many bytes to skip at the beginning of buf.</param>
  191. /// <param name="len">How many bytes to read at all.</param>
  192. /// <param name="skip">How many bytes from our data to skip.</param>
  193. public void RemoveData(byte[] buf, int off, int len, int skip)
  194. {
  195. Read(buf, off, len, skip);
  196. RemoveData(skip + len);
  197. }
  198. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  199. public void RemoveData(Span<byte> buffer, int skip)
  200. {
  201. Read(buffer, skip);
  202. RemoveData(skip + buffer.Length);
  203. }
  204. #endif
  205. public byte[] RemoveData(int len, int skip)
  206. {
  207. byte[] buf = new byte[len];
  208. RemoveData(buf, 0, len, skip);
  209. return buf;
  210. }
  211. public void Shrink()
  212. {
  213. if (m_available == 0)
  214. {
  215. m_databuf = TlsUtilities.EmptyBytes;
  216. m_skipped = 0;
  217. }
  218. else
  219. {
  220. int desiredSize = GetAllocationSize(m_available);
  221. if (desiredSize < m_databuf.Length)
  222. {
  223. byte[] tmp = new byte[desiredSize];
  224. Array.Copy(m_databuf, m_skipped, tmp, 0, m_available);
  225. m_databuf = tmp;
  226. m_skipped = 0;
  227. }
  228. }
  229. }
  230. }
  231. }
  232. #pragma warning restore
  233. #endif