ByteQueue.cs 7.1 KB

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