blob: 329f47f6c4bd2e1af84a456766e14c87e60be57d [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
csharptest71f662c2011-05-20 15:15:34 -05002// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc. All rights reserved.
Jon Skeetee835a32015-06-30 17:22:26 +01004// https://developers.google.com/protocol-buffers/
csharptest71f662c2011-05-20 15:15:34 -05005//
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.
csharptest71f662c2011-05-20 15:15:34 -050031#endregion
32
33using System;
34using System.Collections;
35using System.Collections.Generic;
csharptest74c5e0c2011-07-14 13:06:22 -050036using System.IO;
csharptest71f662c2011-05-20 15:15:34 -050037using System.Text;
38
Jon Skeete38294a2015-06-09 19:30:44 +010039namespace Google.Protobuf
csharptest71f662c2011-05-20 15:15:34 -050040{
41 /// <summary>
42 /// Immutable array of bytes.
43 /// TODO(jonskeet): Implement the common collection interfaces?
44 /// </summary>
45 public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>
46 {
47 private static readonly ByteString empty = new ByteString(new byte[0]);
48
49 private readonly byte[] bytes;
50
51 /// <summary>
csharptestfdb4cc72013-05-07 16:12:45 -050052 /// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.
53 /// </summary>
54 public static class Unsafe
55 {
56 /// <summary>
57 /// Constructs a new ByteString from the given byte array. The array is
58 /// *not* copied, and must not be modified after this constructor is called.
59 /// </summary>
60 public static ByteString FromBytes(byte[] bytes)
61 {
62 return new ByteString(bytes);
63 }
64
65 /// <summary>
66 /// Provides direct, unrestricted access to the bytes contained in this instance.
67 /// You must not modify or resize the byte array returned by this method.
68 /// </summary>
69 public static byte[] GetBuffer(ByteString bytes)
70 {
71 return bytes.bytes;
72 }
73 }
74
75 /// <summary>
csharptest45a93fa2011-06-02 10:52:37 -050076 /// Internal use only. Ensure that the provided array is not mutated and belongs to this instance.
77 /// </summary>
78 internal static ByteString AttachBytes(byte[] bytes)
79 {
80 return new ByteString(bytes);
81 }
82
83 /// <summary>
csharptest71f662c2011-05-20 15:15:34 -050084 /// Constructs a new ByteString from the given byte array. The array is
85 /// *not* copied, and must not be modified after this constructor is called.
86 /// </summary>
87 private ByteString(byte[] bytes)
88 {
89 this.bytes = bytes;
90 }
91
92 /// <summary>
93 /// Returns an empty ByteString.
94 /// </summary>
95 public static ByteString Empty
96 {
97 get { return empty; }
98 }
99
100 /// <summary>
101 /// Returns the length of this ByteString in bytes.
102 /// </summary>
103 public int Length
104 {
105 get { return bytes.Length; }
106 }
107
108 public bool IsEmpty
109 {
110 get { return Length == 0; }
111 }
112
113 public byte[] ToByteArray()
114 {
csharptest74c5e0c2011-07-14 13:06:22 -0500115 return (byte[]) bytes.Clone();
csharptest27bfcc52011-06-02 12:04:06 -0500116 }
117
118 public string ToBase64()
119 {
120 return Convert.ToBase64String(bytes);
csharptest71f662c2011-05-20 15:15:34 -0500121 }
122
123 /// <summary>
124 /// Constructs a ByteString from the Base64 Encoded String.
125 /// </summary>
126 public static ByteString FromBase64(string bytes)
127 {
Jon Skeetdc8149f2013-08-13 15:14:17 +0100128 // By handling the empty string explicitly, we not only optimize but we fix a
129 // problem on CF 2.0. See issue 61 for details.
130 return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes));
csharptest71f662c2011-05-20 15:15:34 -0500131 }
132
133 /// <summary>
134 /// Constructs a ByteString from the given array. The contents
135 /// are copied, so further modifications to the array will not
136 /// be reflected in the returned ByteString.
Jan Tattermuschb4a24aa2015-07-15 19:44:22 -0700137 /// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form
138 /// which is primarily useful for testing.
csharptest71f662c2011-05-20 15:15:34 -0500139 /// </summary>
Jon Skeet6c1fe6e2015-06-23 11:54:19 +0100140 public static ByteString CopyFrom(params byte[] bytes)
csharptest71f662c2011-05-20 15:15:34 -0500141 {
142 return new ByteString((byte[]) bytes.Clone());
143 }
144
145 /// <summary>
146 /// Constructs a ByteString from a portion of a byte array.
147 /// </summary>
148 public static ByteString CopyFrom(byte[] bytes, int offset, int count)
149 {
150 byte[] portion = new byte[count];
csharptestaef072a2011-06-08 18:00:43 -0500151 ByteArray.Copy(bytes, offset, portion, 0, count);
csharptest71f662c2011-05-20 15:15:34 -0500152 return new ByteString(portion);
153 }
154
155 /// <summary>
156 /// Creates a new ByteString by encoding the specified text with
157 /// the given encoding.
158 /// </summary>
159 public static ByteString CopyFrom(string text, Encoding encoding)
160 {
161 return new ByteString(encoding.GetBytes(text));
162 }
163
164 /// <summary>
165 /// Creates a new ByteString by encoding the specified text in UTF-8.
166 /// </summary>
167 public static ByteString CopyFromUtf8(string text)
168 {
169 return CopyFrom(text, Encoding.UTF8);
170 }
171
172 /// <summary>
173 /// Retuns the byte at the given index.
174 /// </summary>
175 public byte this[int index]
176 {
177 get { return bytes[index]; }
178 }
179
180 public string ToString(Encoding encoding)
181 {
182 return encoding.GetString(bytes, 0, bytes.Length);
183 }
184
185 public string ToStringUtf8()
186 {
187 return ToString(Encoding.UTF8);
188 }
189
190 public IEnumerator<byte> GetEnumerator()
191 {
192 return ((IEnumerable<byte>) bytes).GetEnumerator();
193 }
194
195 IEnumerator IEnumerable.GetEnumerator()
196 {
197 return GetEnumerator();
198 }
199
200 /// <summary>
201 /// Creates a CodedInputStream from this ByteString's data.
202 /// </summary>
203 public CodedInputStream CreateCodedInput()
204 {
205 // We trust CodedInputStream not to reveal the provided byte array or modify it
206 return CodedInputStream.CreateInstance(bytes);
207 }
208
Jon Skeete38294a2015-06-09 19:30:44 +0100209 public static bool operator ==(ByteString lhs, ByteString rhs)
210 {
211 if (ReferenceEquals(lhs, rhs))
212 {
213 return true;
214 }
Jon Skeet8d47ec42015-07-04 14:40:24 +0100215 if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
Jon Skeete38294a2015-06-09 19:30:44 +0100216 {
217 return false;
218 }
Jon Skeet8d47ec42015-07-04 14:40:24 +0100219 if (lhs.bytes.Length != rhs.bytes.Length)
220 {
221 return false;
222 }
223 for (int i = 0; i < lhs.Length; i++)
224 {
225 if (rhs.bytes[i] != lhs.bytes[i])
226 {
227 return false;
228 }
229 }
230 return true;
Jon Skeete38294a2015-06-09 19:30:44 +0100231 }
232
233 public static bool operator !=(ByteString lhs, ByteString rhs)
234 {
235 return !(lhs == rhs);
236 }
237
csharptest71f662c2011-05-20 15:15:34 -0500238 // TODO(jonskeet): CopyTo if it turns out to be required
239
240 public override bool Equals(object obj)
241 {
Jon Skeet8d47ec42015-07-04 14:40:24 +0100242 return this == (obj as ByteString);
csharptest71f662c2011-05-20 15:15:34 -0500243 }
244
245 public override int GetHashCode()
246 {
247 int ret = 23;
248 foreach (byte b in bytes)
249 {
250 ret = (ret << 8) | b;
251 }
252 return ret;
253 }
254
255 public bool Equals(ByteString other)
256 {
Jon Skeet8d47ec42015-07-04 14:40:24 +0100257 return this == other;
csharptest71f662c2011-05-20 15:15:34 -0500258 }
259
260 /// <summary>
csharptested701ad2011-07-14 13:20:11 -0500261 /// Used internally by CodedOutputStream to avoid creating a copy for the write
262 /// </summary>
263 internal void WriteRawBytesTo(CodedOutputStream outputStream)
csharptest45a93fa2011-06-02 10:52:37 -0500264 {
265 outputStream.WriteRawBytes(bytes, 0, bytes.Length);
266 }
267
268 /// <summary>
269 /// Copies the entire byte array to the destination array provided at the offset specified.
270 /// </summary>
csharptest2772dfe2011-06-08 15:50:58 -0500271 public void CopyTo(byte[] array, int position)
csharptest45a93fa2011-06-02 10:52:37 -0500272 {
csharptestaef072a2011-06-08 18:00:43 -0500273 ByteArray.Copy(bytes, 0, array, position, bytes.Length);
csharptest45a93fa2011-06-02 10:52:37 -0500274 }
275
276 /// <summary>
277 /// Writes the entire byte array to the provided stream
278 /// </summary>
csharptest74c5e0c2011-07-14 13:06:22 -0500279 public void WriteTo(Stream outputStream)
csharptest45a93fa2011-06-02 10:52:37 -0500280 {
281 outputStream.Write(bytes, 0, bytes.Length);
282 }
csharptest71f662c2011-05-20 15:15:34 -0500283 }
284}