blob: e645a9f22712d1d743aee069358da62c4cedaea8 [file] [log] [blame]
csharptest71f662c2011-05-20 15:15:34 -05001#region Copyright notice and license
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc. All rights reserved.
5// http://github.com/jskeet/dotnet-protobufs/
6// Original C++/Java/Python code:
7// http://code.google.com/p/protobuf/
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// * Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15// * Redistributions in binary form must reproduce the above
16// copyright notice, this list of conditions and the following disclaimer
17// in the documentation and/or other materials provided with the
18// distribution.
19// * Neither the name of Google Inc. nor the names of its
20// contributors may be used to endorse or promote products derived from
21// this software without specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35#endregion
36
37using System;
38using System.Collections;
39using System.Collections.Generic;
40using System.Text;
41
42namespace Google.ProtocolBuffers
43{
44 /// <summary>
45 /// Immutable array of bytes.
46 /// TODO(jonskeet): Implement the common collection interfaces?
47 /// </summary>
48 public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>
49 {
50 private static readonly ByteString empty = new ByteString(new byte[0]);
51
52 private readonly byte[] bytes;
53
54 /// <summary>
csharptest45a93fa2011-06-02 10:52:37 -050055 /// Internal use only. Ensure that the provided array is not mutated and belongs to this instance.
56 /// </summary>
57 internal static ByteString AttachBytes(byte[] bytes)
58 {
59 return new ByteString(bytes);
60 }
61
62 /// <summary>
csharptest71f662c2011-05-20 15:15:34 -050063 /// Constructs a new ByteString from the given byte array. The array is
64 /// *not* copied, and must not be modified after this constructor is called.
65 /// </summary>
66 private ByteString(byte[] bytes)
67 {
68 this.bytes = bytes;
69 }
70
71 /// <summary>
72 /// Returns an empty ByteString.
73 /// </summary>
74 public static ByteString Empty
75 {
76 get { return empty; }
77 }
78
79 /// <summary>
80 /// Returns the length of this ByteString in bytes.
81 /// </summary>
82 public int Length
83 {
84 get { return bytes.Length; }
85 }
86
87 public bool IsEmpty
88 {
89 get { return Length == 0; }
90 }
91
92 public byte[] ToByteArray()
93 {
csharptest27bfcc52011-06-02 12:04:06 -050094 return (byte[])bytes.Clone();
95 }
96
97 public string ToBase64()
98 {
99 return Convert.ToBase64String(bytes);
csharptest71f662c2011-05-20 15:15:34 -0500100 }
101
102 /// <summary>
103 /// Constructs a ByteString from the Base64 Encoded String.
104 /// </summary>
105 public static ByteString FromBase64(string bytes)
106 {
107 return new ByteString(System.Convert.FromBase64String(bytes));
108 }
109
110 /// <summary>
111 /// Constructs a ByteString from the given array. The contents
112 /// are copied, so further modifications to the array will not
113 /// be reflected in the returned ByteString.
114 /// </summary>
115 public static ByteString CopyFrom(byte[] bytes)
116 {
117 return new ByteString((byte[]) bytes.Clone());
118 }
119
120 /// <summary>
121 /// Constructs a ByteString from a portion of a byte array.
122 /// </summary>
123 public static ByteString CopyFrom(byte[] bytes, int offset, int count)
124 {
125 byte[] portion = new byte[count];
126 Array.Copy(bytes, offset, portion, 0, count);
127 return new ByteString(portion);
128 }
129
130 /// <summary>
131 /// Creates a new ByteString by encoding the specified text with
132 /// the given encoding.
133 /// </summary>
134 public static ByteString CopyFrom(string text, Encoding encoding)
135 {
136 return new ByteString(encoding.GetBytes(text));
137 }
138
139 /// <summary>
140 /// Creates a new ByteString by encoding the specified text in UTF-8.
141 /// </summary>
142 public static ByteString CopyFromUtf8(string text)
143 {
144 return CopyFrom(text, Encoding.UTF8);
145 }
146
147 /// <summary>
148 /// Retuns the byte at the given index.
149 /// </summary>
150 public byte this[int index]
151 {
152 get { return bytes[index]; }
153 }
154
155 public string ToString(Encoding encoding)
156 {
157 return encoding.GetString(bytes, 0, bytes.Length);
158 }
159
160 public string ToStringUtf8()
161 {
162 return ToString(Encoding.UTF8);
163 }
164
165 public IEnumerator<byte> GetEnumerator()
166 {
167 return ((IEnumerable<byte>) bytes).GetEnumerator();
168 }
169
170 IEnumerator IEnumerable.GetEnumerator()
171 {
172 return GetEnumerator();
173 }
174
175 /// <summary>
176 /// Creates a CodedInputStream from this ByteString's data.
177 /// </summary>
178 public CodedInputStream CreateCodedInput()
179 {
180 // We trust CodedInputStream not to reveal the provided byte array or modify it
181 return CodedInputStream.CreateInstance(bytes);
182 }
183
184 // TODO(jonskeet): CopyTo if it turns out to be required
185
186 public override bool Equals(object obj)
187 {
188 ByteString other = obj as ByteString;
189 if (obj == null)
190 {
191 return false;
192 }
193 return Equals(other);
194 }
195
196 public override int GetHashCode()
197 {
198 int ret = 23;
199 foreach (byte b in bytes)
200 {
201 ret = (ret << 8) | b;
202 }
203 return ret;
204 }
205
206 public bool Equals(ByteString other)
207 {
208 if (other.bytes.Length != bytes.Length)
209 {
210 return false;
211 }
212 for (int i = 0; i < bytes.Length; i++)
213 {
214 if (other.bytes[i] != bytes[i])
215 {
216 return false;
217 }
218 }
219 return true;
220 }
221
222 /// <summary>
223 /// Builder for ByteStrings which allows them to be created without extra
224 /// copying being involved. This has to be a nested type in order to have access
225 /// to the private ByteString constructor.
226 /// </summary>
227 internal sealed class CodedBuilder
228 {
229 private readonly CodedOutputStream output;
230 private readonly byte[] buffer;
231
232 internal CodedBuilder(int size)
233 {
234 buffer = new byte[size];
235 output = CodedOutputStream.CreateInstance(buffer);
236 }
237
238 internal ByteString Build()
239 {
240 output.CheckNoSpaceLeft();
241
242 // We can be confident that the CodedOutputStream will not modify the
243 // underlying bytes anymore because it already wrote all of them. So,
244 // no need to make a copy.
245 return new ByteString(buffer);
246 }
247
248 internal CodedOutputStream CodedOutput
249 {
250 get { return output; }
251 }
252 }
csharptest45a93fa2011-06-02 10:52:37 -0500253
254 internal void WriteTo(CodedOutputStream outputStream)
255 {
256 outputStream.WriteRawBytes(bytes, 0, bytes.Length);
257 }
258
259 /// <summary>
260 /// Copies the entire byte array to the destination array provided at the offset specified.
261 /// </summary>
262 public void CopyTo(Array array, int position)
263 {
264 Array.Copy(bytes, 0, array, position, bytes.Length);
265 }
266
267 /// <summary>
268 /// Writes the entire byte array to the provided stream
269 /// </summary>
270 public void WriteTo(System.IO.Stream outputStream)
271 {
272 outputStream.Write(bytes, 0, bytes.Length);
273 }
csharptest71f662c2011-05-20 15:15:34 -0500274 }
275}