blob: 26816d9cc27754bba89db3a19231596c672341e9 [file] [log] [blame]
Jon Skeet68036862008-10-22 13:30:34 +01001using System;
2using System.Collections;
3using System.Collections.Generic;
4// Protocol Buffers - Google's data interchange format
5// Copyright 2008 Google Inc.
6// http://code.google.com/p/protobuf/
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License at
11//
12// http://www.apache.org/licenses/LICENSE-2.0
13//
14// Unless required by applicable law or agreed to in writing, software
15// distributed under the License is distributed on an "AS IS" BASIS,
16// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17// See the License for the specific language governing permissions and
18// limitations under the License.
19using System.Text;
20
21namespace Google.ProtocolBuffers {
22 /// <summary>
23 /// Immutable array of bytes.
24 /// TODO(jonskeet): Implement the common collection interfaces?
25 /// </summary>
26 public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString> {
27
28 private static readonly ByteString empty = new ByteString(new byte[0]);
29
30 private readonly byte[] bytes;
31
32 /// <summary>
33 /// Constructs a new ByteString from the given byte array. The array is
34 /// *not* copied, and must not be modified after this constructor is called.
35 /// </summary>
36 private ByteString(byte[] bytes) {
37 this.bytes = bytes;
38 }
39
40 /// <summary>
41 /// Returns an empty ByteString.
42 /// </summary>
43 public static ByteString Empty {
44 get { return empty; }
45 }
46
47 /// <summary>
48 /// Returns the length of this ByteString in bytes.
49 /// </summary>
50 public int Length {
51 get { return bytes.Length; }
52 }
53
54 public bool IsEmpty {
55 get { return Length == 0; }
56 }
57
58 public byte[] ToByteArray() {
59 return (byte[])bytes.Clone();
60 }
61
62 /// <summary>
63 /// Constructs a ByteString from the given array. The contents
64 /// are copied, so further modifications to the array will not
65 /// be reflected in the returned ByteString.
66 /// </summary>
67 public static ByteString CopyFrom(byte[] bytes) {
68 return new ByteString((byte[]) bytes.Clone());
69 }
70
71 /// <summary>
72 /// Constructs a ByteString from a portion of a byte array.
73 /// </summary>
74 public static ByteString CopyFrom(byte[] bytes, int offset, int count) {
75 byte[] portion = new byte[count];
76 Array.Copy(bytes, offset, portion, 0, count);
77 return new ByteString(portion);
78 }
79
80 /// <summary>
81 /// Creates a new ByteString by encoding the specified text with
82 /// the given encoding.
83 /// </summary>
84 public static ByteString CopyFrom(string text, Encoding encoding) {
85 return new ByteString(encoding.GetBytes(text));
86 }
87
88 /// <summary>
89 /// Creates a new ByteString by encoding the specified text in UTF-8.
90 /// </summary>
91 public static ByteString CopyFromUtf8(string text) {
92 return CopyFrom(text, Encoding.UTF8);
93 }
94
95 /// <summary>
96 /// Retuns the byte at the given index.
97 /// </summary>
98 public byte this[int index] {
99 get { return bytes[index]; }
100 }
101
102 public string ToString(Encoding encoding) {
103 return encoding.GetString(bytes);
104 }
105
106 public string ToStringUtf8() {
107 return ToString(Encoding.UTF8);
108 }
109
110 public IEnumerator<byte> GetEnumerator() {
111 return ((IEnumerable<byte>) bytes).GetEnumerator();
112 }
113
114 IEnumerator IEnumerable.GetEnumerator() {
115 return GetEnumerator();
116 }
117
118 /// <summary>
119 /// Creates a CodedInputStream from this ByteString's data.
120 /// </summary>
121 public CodedInputStream CreateCodedInput() {
122
123 // We trust CodedInputStream not to reveal the provided byte array or modify it
124 return CodedInputStream.CreateInstance(bytes);
125 }
126
127 // TODO(jonskeet): CopyTo if it turns out to be required
128
129 public override bool Equals(object obj) {
130 ByteString other = obj as ByteString;
131 if (obj == null) {
132 return false;
133 }
134 return Equals(other);
135 }
136
137 public override int GetHashCode() {
138 int ret = 23;
139 foreach (byte b in bytes) {
140 ret = (ret << 8) | b;
141 }
142 return ret;
143 }
144
145 public bool Equals(ByteString other) {
146 if (other.bytes.Length != bytes.Length) {
147 return false;
148 }
149 for (int i = 0; i < bytes.Length; i++) {
150 if (other.bytes[i] != bytes[i]) {
151 return false;
152 }
153 }
154 return true;
155 }
156
157 /// <summary>
158 /// Builder for ByteStrings which allows them to be created without extra
159 /// copying being involved. This has to be a nested type in order to have access
160 /// to the private ByteString constructor.
161 /// </summary>
162 internal sealed class CodedBuilder {
163 private readonly CodedOutputStream output;
164 private readonly byte[] buffer;
165
166 internal CodedBuilder(int size) {
167 buffer = new byte[size];
168 output = CodedOutputStream.CreateInstance(buffer);
169 }
170
171 public ByteString Build() {
172 output.CheckNoSpaceLeft();
173
174 // We can be confident that the CodedOutputStream will not modify the
175 // underlying bytes anymore because it already wrote all of them. So,
176 // no need to make a copy.
177 return new ByteString(buffer);
178 }
179
180 public CodedOutputStream CodedOutput {
181 get {
182 return output;
183 }
184 }
185 }
186 }
187}