ByteString.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // https://developers.google.com/protocol-buffers/
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. #endregion
  32. using System;
  33. using System.Collections;
  34. using System.Collections.Generic;
  35. using System.IO;
  36. using System.Text;
  37. namespace Google.Protobuf
  38. {
  39. /// <summary>
  40. /// Immutable array of bytes.
  41. /// TODO(jonskeet): Implement the common collection interfaces?
  42. /// </summary>
  43. public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>
  44. {
  45. private static readonly ByteString empty = new ByteString(new byte[0]);
  46. private readonly byte[] bytes;
  47. /// <summary>
  48. /// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.
  49. /// </summary>
  50. public static class Unsafe
  51. {
  52. /// <summary>
  53. /// Constructs a new ByteString from the given byte array. The array is
  54. /// *not* copied, and must not be modified after this constructor is called.
  55. /// </summary>
  56. public static ByteString FromBytes(byte[] bytes)
  57. {
  58. return new ByteString(bytes);
  59. }
  60. /// <summary>
  61. /// Provides direct, unrestricted access to the bytes contained in this instance.
  62. /// You must not modify or resize the byte array returned by this method.
  63. /// </summary>
  64. public static byte[] GetBuffer(ByteString bytes)
  65. {
  66. return bytes.bytes;
  67. }
  68. }
  69. /// <summary>
  70. /// Internal use only. Ensure that the provided array is not mutated and belongs to this instance.
  71. /// </summary>
  72. internal static ByteString AttachBytes(byte[] bytes)
  73. {
  74. return new ByteString(bytes);
  75. }
  76. /// <summary>
  77. /// Constructs a new ByteString from the given byte array. The array is
  78. /// *not* copied, and must not be modified after this constructor is called.
  79. /// </summary>
  80. private ByteString(byte[] bytes)
  81. {
  82. this.bytes = bytes;
  83. }
  84. /// <summary>
  85. /// Returns an empty ByteString.
  86. /// </summary>
  87. public static ByteString Empty
  88. {
  89. get { return empty; }
  90. }
  91. /// <summary>
  92. /// Returns the length of this ByteString in bytes.
  93. /// </summary>
  94. public int Length
  95. {
  96. get { return bytes.Length; }
  97. }
  98. public bool IsEmpty
  99. {
  100. get { return Length == 0; }
  101. }
  102. public byte[] ToByteArray()
  103. {
  104. return (byte[]) bytes.Clone();
  105. }
  106. public string ToBase64()
  107. {
  108. return Convert.ToBase64String(bytes);
  109. }
  110. /// <summary>
  111. /// Constructs a ByteString from the Base64 Encoded String.
  112. /// </summary>
  113. public static ByteString FromBase64(string bytes)
  114. {
  115. // By handling the empty string explicitly, we not only optimize but we fix a
  116. // problem on CF 2.0. See issue 61 for details.
  117. return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes));
  118. }
  119. /// <summary>
  120. /// Constructs a ByteString from the given array. The contents
  121. /// are copied, so further modifications to the array will not
  122. /// be reflected in the returned ByteString.
  123. /// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form
  124. /// which is primarily useful for testing.
  125. /// </summary>
  126. public static ByteString CopyFrom(params byte[] bytes)
  127. {
  128. return new ByteString((byte[]) bytes.Clone());
  129. }
  130. /// <summary>
  131. /// Constructs a ByteString from a portion of a byte array.
  132. /// </summary>
  133. public static ByteString CopyFrom(byte[] bytes, int offset, int count)
  134. {
  135. byte[] portion = new byte[count];
  136. ByteArray.Copy(bytes, offset, portion, 0, count);
  137. return new ByteString(portion);
  138. }
  139. /// <summary>
  140. /// Creates a new ByteString by encoding the specified text with
  141. /// the given encoding.
  142. /// </summary>
  143. public static ByteString CopyFrom(string text, Encoding encoding)
  144. {
  145. return new ByteString(encoding.GetBytes(text));
  146. }
  147. /// <summary>
  148. /// Creates a new ByteString by encoding the specified text in UTF-8.
  149. /// </summary>
  150. public static ByteString CopyFromUtf8(string text)
  151. {
  152. return CopyFrom(text, Encoding.UTF8);
  153. }
  154. /// <summary>
  155. /// Retuns the byte at the given index.
  156. /// </summary>
  157. public byte this[int index]
  158. {
  159. get { return bytes[index]; }
  160. }
  161. public string ToString(Encoding encoding)
  162. {
  163. return encoding.GetString(bytes, 0, bytes.Length);
  164. }
  165. public string ToStringUtf8()
  166. {
  167. return ToString(Encoding.UTF8);
  168. }
  169. public IEnumerator<byte> GetEnumerator()
  170. {
  171. return ((IEnumerable<byte>) bytes).GetEnumerator();
  172. }
  173. IEnumerator IEnumerable.GetEnumerator()
  174. {
  175. return GetEnumerator();
  176. }
  177. /// <summary>
  178. /// Creates a CodedInputStream from this ByteString's data.
  179. /// </summary>
  180. public CodedInputStream CreateCodedInput()
  181. {
  182. // We trust CodedInputStream not to reveal the provided byte array or modify it
  183. return CodedInputStream.CreateInstance(bytes);
  184. }
  185. public static bool operator ==(ByteString lhs, ByteString rhs)
  186. {
  187. if (ReferenceEquals(lhs, rhs))
  188. {
  189. return true;
  190. }
  191. if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
  192. {
  193. return false;
  194. }
  195. if (lhs.bytes.Length != rhs.bytes.Length)
  196. {
  197. return false;
  198. }
  199. for (int i = 0; i < lhs.Length; i++)
  200. {
  201. if (rhs.bytes[i] != lhs.bytes[i])
  202. {
  203. return false;
  204. }
  205. }
  206. return true;
  207. }
  208. public static bool operator !=(ByteString lhs, ByteString rhs)
  209. {
  210. return !(lhs == rhs);
  211. }
  212. // TODO(jonskeet): CopyTo if it turns out to be required
  213. public override bool Equals(object obj)
  214. {
  215. return this == (obj as ByteString);
  216. }
  217. public override int GetHashCode()
  218. {
  219. int ret = 23;
  220. foreach (byte b in bytes)
  221. {
  222. ret = (ret << 8) | b;
  223. }
  224. return ret;
  225. }
  226. public bool Equals(ByteString other)
  227. {
  228. return this == other;
  229. }
  230. /// <summary>
  231. /// Used internally by CodedOutputStream to avoid creating a copy for the write
  232. /// </summary>
  233. internal void WriteRawBytesTo(CodedOutputStream outputStream)
  234. {
  235. outputStream.WriteRawBytes(bytes, 0, bytes.Length);
  236. }
  237. /// <summary>
  238. /// Copies the entire byte array to the destination array provided at the offset specified.
  239. /// </summary>
  240. public void CopyTo(byte[] array, int position)
  241. {
  242. ByteArray.Copy(bytes, 0, array, position, bytes.Length);
  243. }
  244. /// <summary>
  245. /// Writes the entire byte array to the provided stream
  246. /// </summary>
  247. public void WriteTo(Stream outputStream)
  248. {
  249. outputStream.Write(bytes, 0, bytes.Length);
  250. }
  251. }
  252. }