1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license 2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format 3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2008 Google Inc. All rights reserved. 4*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/ 5*1b3f573fSAndroid Build Coastguard Worker // 6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without 7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are 8*1b3f573fSAndroid Build Coastguard Worker // met: 9*1b3f573fSAndroid Build Coastguard Worker // 10*1b3f573fSAndroid Build Coastguard Worker // * Redistributions of source code must retain the above copyright 11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer. 12*1b3f573fSAndroid Build Coastguard Worker // * Redistributions in binary form must reproduce the above 13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer 14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the 15*1b3f573fSAndroid Build Coastguard Worker // distribution. 16*1b3f573fSAndroid Build Coastguard Worker // * Neither the name of Google Inc. nor the names of its 17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from 18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission. 19*1b3f573fSAndroid Build Coastguard Worker // 20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*1b3f573fSAndroid Build Coastguard Worker #endregion 32*1b3f573fSAndroid Build Coastguard Worker 33*1b3f573fSAndroid Build Coastguard Worker using System; 34*1b3f573fSAndroid Build Coastguard Worker using System.Collections; 35*1b3f573fSAndroid Build Coastguard Worker using System.Collections.Generic; 36*1b3f573fSAndroid Build Coastguard Worker using System.IO; 37*1b3f573fSAndroid Build Coastguard Worker using System.Runtime.InteropServices; 38*1b3f573fSAndroid Build Coastguard Worker using System.Security; 39*1b3f573fSAndroid Build Coastguard Worker using System.Text; 40*1b3f573fSAndroid Build Coastguard Worker #if !NET35 41*1b3f573fSAndroid Build Coastguard Worker using System.Threading; 42*1b3f573fSAndroid Build Coastguard Worker using System.Threading.Tasks; 43*1b3f573fSAndroid Build Coastguard Worker #endif 44*1b3f573fSAndroid Build Coastguard Worker #if NET35 45*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.Compatibility; 46*1b3f573fSAndroid Build Coastguard Worker #endif 47*1b3f573fSAndroid Build Coastguard Worker 48*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf 49*1b3f573fSAndroid Build Coastguard Worker { 50*1b3f573fSAndroid Build Coastguard Worker /// <summary> 51*1b3f573fSAndroid Build Coastguard Worker /// Immutable array of bytes. 52*1b3f573fSAndroid Build Coastguard Worker /// </summary> 53*1b3f573fSAndroid Build Coastguard Worker [SecuritySafeCritical] 54*1b3f573fSAndroid Build Coastguard Worker public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString> 55*1b3f573fSAndroid Build Coastguard Worker { 56*1b3f573fSAndroid Build Coastguard Worker private static readonly ByteString empty = new ByteString(new byte[0]); 57*1b3f573fSAndroid Build Coastguard Worker 58*1b3f573fSAndroid Build Coastguard Worker private readonly ReadOnlyMemory<byte> bytes; 59*1b3f573fSAndroid Build Coastguard Worker 60*1b3f573fSAndroid Build Coastguard Worker /// <summary> 61*1b3f573fSAndroid Build Coastguard Worker /// Internal use only. Ensure that the provided memory is not mutated and belongs to this instance. 62*1b3f573fSAndroid Build Coastguard Worker /// </summary> AttachBytes(ReadOnlyMemory<byte> bytes)63*1b3f573fSAndroid Build Coastguard Worker internal static ByteString AttachBytes(ReadOnlyMemory<byte> bytes) 64*1b3f573fSAndroid Build Coastguard Worker { 65*1b3f573fSAndroid Build Coastguard Worker return new ByteString(bytes); 66*1b3f573fSAndroid Build Coastguard Worker } 67*1b3f573fSAndroid Build Coastguard Worker 68*1b3f573fSAndroid Build Coastguard Worker /// <summary> 69*1b3f573fSAndroid Build Coastguard Worker /// Internal use only. Ensure that the provided memory is not mutated and belongs to this instance. 70*1b3f573fSAndroid Build Coastguard Worker /// This method encapsulates converting array to memory. Reduces need for SecuritySafeCritical 71*1b3f573fSAndroid Build Coastguard Worker /// in .NET Framework. 72*1b3f573fSAndroid Build Coastguard Worker /// </summary> AttachBytes(byte[] bytes)73*1b3f573fSAndroid Build Coastguard Worker internal static ByteString AttachBytes(byte[] bytes) 74*1b3f573fSAndroid Build Coastguard Worker { 75*1b3f573fSAndroid Build Coastguard Worker return AttachBytes(bytes.AsMemory()); 76*1b3f573fSAndroid Build Coastguard Worker } 77*1b3f573fSAndroid Build Coastguard Worker 78*1b3f573fSAndroid Build Coastguard Worker /// <summary> 79*1b3f573fSAndroid Build Coastguard Worker /// Constructs a new ByteString from the given memory. The memory is 80*1b3f573fSAndroid Build Coastguard Worker /// *not* copied, and must not be modified after this constructor is called. 81*1b3f573fSAndroid Build Coastguard Worker /// </summary> ByteString(ReadOnlyMemory<byte> bytes)82*1b3f573fSAndroid Build Coastguard Worker private ByteString(ReadOnlyMemory<byte> bytes) 83*1b3f573fSAndroid Build Coastguard Worker { 84*1b3f573fSAndroid Build Coastguard Worker this.bytes = bytes; 85*1b3f573fSAndroid Build Coastguard Worker } 86*1b3f573fSAndroid Build Coastguard Worker 87*1b3f573fSAndroid Build Coastguard Worker /// <summary> 88*1b3f573fSAndroid Build Coastguard Worker /// Returns an empty ByteString. 89*1b3f573fSAndroid Build Coastguard Worker /// </summary> 90*1b3f573fSAndroid Build Coastguard Worker public static ByteString Empty 91*1b3f573fSAndroid Build Coastguard Worker { 92*1b3f573fSAndroid Build Coastguard Worker get { return empty; } 93*1b3f573fSAndroid Build Coastguard Worker } 94*1b3f573fSAndroid Build Coastguard Worker 95*1b3f573fSAndroid Build Coastguard Worker /// <summary> 96*1b3f573fSAndroid Build Coastguard Worker /// Returns the length of this ByteString in bytes. 97*1b3f573fSAndroid Build Coastguard Worker /// </summary> 98*1b3f573fSAndroid Build Coastguard Worker public int Length 99*1b3f573fSAndroid Build Coastguard Worker { 100*1b3f573fSAndroid Build Coastguard Worker get { return bytes.Length; } 101*1b3f573fSAndroid Build Coastguard Worker } 102*1b3f573fSAndroid Build Coastguard Worker 103*1b3f573fSAndroid Build Coastguard Worker /// <summary> 104*1b3f573fSAndroid Build Coastguard Worker /// Returns <c>true</c> if this byte string is empty, <c>false</c> otherwise. 105*1b3f573fSAndroid Build Coastguard Worker /// </summary> 106*1b3f573fSAndroid Build Coastguard Worker public bool IsEmpty 107*1b3f573fSAndroid Build Coastguard Worker { 108*1b3f573fSAndroid Build Coastguard Worker get { return Length == 0; } 109*1b3f573fSAndroid Build Coastguard Worker } 110*1b3f573fSAndroid Build Coastguard Worker 111*1b3f573fSAndroid Build Coastguard Worker /// <summary> 112*1b3f573fSAndroid Build Coastguard Worker /// Provides read-only access to the data of this <see cref="ByteString"/>. 113*1b3f573fSAndroid Build Coastguard Worker /// No data is copied so this is the most efficient way of accessing. 114*1b3f573fSAndroid Build Coastguard Worker /// </summary> 115*1b3f573fSAndroid Build Coastguard Worker public ReadOnlySpan<byte> Span 116*1b3f573fSAndroid Build Coastguard Worker { 117*1b3f573fSAndroid Build Coastguard Worker get { return bytes.Span; } 118*1b3f573fSAndroid Build Coastguard Worker } 119*1b3f573fSAndroid Build Coastguard Worker 120*1b3f573fSAndroid Build Coastguard Worker /// <summary> 121*1b3f573fSAndroid Build Coastguard Worker /// Provides read-only access to the data of this <see cref="ByteString"/>. 122*1b3f573fSAndroid Build Coastguard Worker /// No data is copied so this is the most efficient way of accessing. 123*1b3f573fSAndroid Build Coastguard Worker /// </summary> 124*1b3f573fSAndroid Build Coastguard Worker public ReadOnlyMemory<byte> Memory 125*1b3f573fSAndroid Build Coastguard Worker { 126*1b3f573fSAndroid Build Coastguard Worker get { return bytes; } 127*1b3f573fSAndroid Build Coastguard Worker } 128*1b3f573fSAndroid Build Coastguard Worker 129*1b3f573fSAndroid Build Coastguard Worker /// <summary> 130*1b3f573fSAndroid Build Coastguard Worker /// Converts this <see cref="ByteString"/> into a byte array. 131*1b3f573fSAndroid Build Coastguard Worker /// </summary> 132*1b3f573fSAndroid Build Coastguard Worker /// <remarks>The data is copied - changes to the returned array will not be reflected in this <c>ByteString</c>.</remarks> 133*1b3f573fSAndroid Build Coastguard Worker /// <returns>A byte array with the same data as this <c>ByteString</c>.</returns> ToByteArray()134*1b3f573fSAndroid Build Coastguard Worker public byte[] ToByteArray() 135*1b3f573fSAndroid Build Coastguard Worker { 136*1b3f573fSAndroid Build Coastguard Worker return bytes.ToArray(); 137*1b3f573fSAndroid Build Coastguard Worker } 138*1b3f573fSAndroid Build Coastguard Worker 139*1b3f573fSAndroid Build Coastguard Worker /// <summary> 140*1b3f573fSAndroid Build Coastguard Worker /// Converts this <see cref="ByteString"/> into a standard base64 representation. 141*1b3f573fSAndroid Build Coastguard Worker /// </summary> 142*1b3f573fSAndroid Build Coastguard Worker /// <returns>A base64 representation of this <c>ByteString</c>.</returns> ToBase64()143*1b3f573fSAndroid Build Coastguard Worker public string ToBase64() 144*1b3f573fSAndroid Build Coastguard Worker { 145*1b3f573fSAndroid Build Coastguard Worker if (MemoryMarshal.TryGetArray(bytes, out ArraySegment<byte> segment)) 146*1b3f573fSAndroid Build Coastguard Worker { 147*1b3f573fSAndroid Build Coastguard Worker // Fast path. ByteString was created with an array, so pass the underlying array. 148*1b3f573fSAndroid Build Coastguard Worker return Convert.ToBase64String(segment.Array, segment.Offset, segment.Count); 149*1b3f573fSAndroid Build Coastguard Worker } 150*1b3f573fSAndroid Build Coastguard Worker else 151*1b3f573fSAndroid Build Coastguard Worker { 152*1b3f573fSAndroid Build Coastguard Worker // Slow path. BytesString is not an array. Convert memory and pass result to ToBase64String. 153*1b3f573fSAndroid Build Coastguard Worker return Convert.ToBase64String(bytes.ToArray()); 154*1b3f573fSAndroid Build Coastguard Worker } 155*1b3f573fSAndroid Build Coastguard Worker } 156*1b3f573fSAndroid Build Coastguard Worker 157*1b3f573fSAndroid Build Coastguard Worker /// <summary> 158*1b3f573fSAndroid Build Coastguard Worker /// Constructs a <see cref="ByteString" /> from the Base64 Encoded String. 159*1b3f573fSAndroid Build Coastguard Worker /// </summary> FromBase64(string bytes)160*1b3f573fSAndroid Build Coastguard Worker public static ByteString FromBase64(string bytes) 161*1b3f573fSAndroid Build Coastguard Worker { 162*1b3f573fSAndroid Build Coastguard Worker // By handling the empty string explicitly, we not only optimize but we fix a 163*1b3f573fSAndroid Build Coastguard Worker // problem on CF 2.0. See issue 61 for details. 164*1b3f573fSAndroid Build Coastguard Worker return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes)); 165*1b3f573fSAndroid Build Coastguard Worker } 166*1b3f573fSAndroid Build Coastguard Worker 167*1b3f573fSAndroid Build Coastguard Worker /// <summary> 168*1b3f573fSAndroid Build Coastguard Worker /// Constructs a <see cref="ByteString"/> from data in the given stream, synchronously. 169*1b3f573fSAndroid Build Coastguard Worker /// </summary> 170*1b3f573fSAndroid Build Coastguard Worker /// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position 171*1b3f573fSAndroid Build Coastguard Worker /// at the start of the call.</remarks> 172*1b3f573fSAndroid Build Coastguard Worker /// <param name="stream">The stream to copy into a ByteString.</param> 173*1b3f573fSAndroid Build Coastguard Worker /// <returns>A ByteString with content read from the given stream.</returns> FromStream(Stream stream)174*1b3f573fSAndroid Build Coastguard Worker public static ByteString FromStream(Stream stream) 175*1b3f573fSAndroid Build Coastguard Worker { 176*1b3f573fSAndroid Build Coastguard Worker ProtoPreconditions.CheckNotNull(stream, nameof(stream)); 177*1b3f573fSAndroid Build Coastguard Worker int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0; 178*1b3f573fSAndroid Build Coastguard Worker var memoryStream = new MemoryStream(capacity); 179*1b3f573fSAndroid Build Coastguard Worker stream.CopyTo(memoryStream); 180*1b3f573fSAndroid Build Coastguard Worker #if NETSTANDARD1_1 || NETSTANDARD2_0 181*1b3f573fSAndroid Build Coastguard Worker byte[] bytes = memoryStream.ToArray(); 182*1b3f573fSAndroid Build Coastguard Worker #else 183*1b3f573fSAndroid Build Coastguard Worker // Avoid an extra copy if we can. 184*1b3f573fSAndroid Build Coastguard Worker byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray(); 185*1b3f573fSAndroid Build Coastguard Worker #endif 186*1b3f573fSAndroid Build Coastguard Worker return AttachBytes(bytes); 187*1b3f573fSAndroid Build Coastguard Worker } 188*1b3f573fSAndroid Build Coastguard Worker 189*1b3f573fSAndroid Build Coastguard Worker #if !NET35 190*1b3f573fSAndroid Build Coastguard Worker /// <summary> 191*1b3f573fSAndroid Build Coastguard Worker /// Constructs a <see cref="ByteString"/> from data in the given stream, asynchronously. 192*1b3f573fSAndroid Build Coastguard Worker /// </summary> 193*1b3f573fSAndroid Build Coastguard Worker /// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position 194*1b3f573fSAndroid Build Coastguard Worker /// at the start of the call.</remarks> 195*1b3f573fSAndroid Build Coastguard Worker /// <param name="stream">The stream to copy into a ByteString.</param> 196*1b3f573fSAndroid Build Coastguard Worker /// <param name="cancellationToken">The cancellation token to use when reading from the stream, if any.</param> 197*1b3f573fSAndroid Build Coastguard Worker /// <returns>A ByteString with content read from the given stream.</returns> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))198*1b3f573fSAndroid Build Coastguard Worker public static Task<ByteString> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) 199*1b3f573fSAndroid Build Coastguard Worker { 200*1b3f573fSAndroid Build Coastguard Worker ProtoPreconditions.CheckNotNull(stream, nameof(stream)); 201*1b3f573fSAndroid Build Coastguard Worker return ByteStringAsync.FromStreamAsyncCore(stream, cancellationToken); 202*1b3f573fSAndroid Build Coastguard Worker } 203*1b3f573fSAndroid Build Coastguard Worker #endif 204*1b3f573fSAndroid Build Coastguard Worker 205*1b3f573fSAndroid Build Coastguard Worker /// <summary> 206*1b3f573fSAndroid Build Coastguard Worker /// Constructs a <see cref="ByteString" /> from the given array. The contents 207*1b3f573fSAndroid Build Coastguard Worker /// are copied, so further modifications to the array will not 208*1b3f573fSAndroid Build Coastguard Worker /// be reflected in the returned ByteString. 209*1b3f573fSAndroid Build Coastguard Worker /// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form 210*1b3f573fSAndroid Build Coastguard Worker /// which is primarily useful for testing. 211*1b3f573fSAndroid Build Coastguard Worker /// </summary> CopyFrom(params byte[] bytes)212*1b3f573fSAndroid Build Coastguard Worker public static ByteString CopyFrom(params byte[] bytes) 213*1b3f573fSAndroid Build Coastguard Worker { 214*1b3f573fSAndroid Build Coastguard Worker return new ByteString((byte[]) bytes.Clone()); 215*1b3f573fSAndroid Build Coastguard Worker } 216*1b3f573fSAndroid Build Coastguard Worker 217*1b3f573fSAndroid Build Coastguard Worker /// <summary> 218*1b3f573fSAndroid Build Coastguard Worker /// Constructs a <see cref="ByteString" /> from a portion of a byte array. 219*1b3f573fSAndroid Build Coastguard Worker /// </summary> CopyFrom(byte[] bytes, int offset, int count)220*1b3f573fSAndroid Build Coastguard Worker public static ByteString CopyFrom(byte[] bytes, int offset, int count) 221*1b3f573fSAndroid Build Coastguard Worker { 222*1b3f573fSAndroid Build Coastguard Worker byte[] portion = new byte[count]; 223*1b3f573fSAndroid Build Coastguard Worker ByteArray.Copy(bytes, offset, portion, 0, count); 224*1b3f573fSAndroid Build Coastguard Worker return new ByteString(portion); 225*1b3f573fSAndroid Build Coastguard Worker } 226*1b3f573fSAndroid Build Coastguard Worker 227*1b3f573fSAndroid Build Coastguard Worker /// <summary> 228*1b3f573fSAndroid Build Coastguard Worker /// Constructs a <see cref="ByteString" /> from a read only span. The contents 229*1b3f573fSAndroid Build Coastguard Worker /// are copied, so further modifications to the span will not 230*1b3f573fSAndroid Build Coastguard Worker /// be reflected in the returned <see cref="ByteString" />. 231*1b3f573fSAndroid Build Coastguard Worker /// </summary> CopyFrom(ReadOnlySpan<byte> bytes)232*1b3f573fSAndroid Build Coastguard Worker public static ByteString CopyFrom(ReadOnlySpan<byte> bytes) 233*1b3f573fSAndroid Build Coastguard Worker { 234*1b3f573fSAndroid Build Coastguard Worker return new ByteString(bytes.ToArray()); 235*1b3f573fSAndroid Build Coastguard Worker } 236*1b3f573fSAndroid Build Coastguard Worker 237*1b3f573fSAndroid Build Coastguard Worker /// <summary> 238*1b3f573fSAndroid Build Coastguard Worker /// Creates a new <see cref="ByteString" /> by encoding the specified text with 239*1b3f573fSAndroid Build Coastguard Worker /// the given encoding. 240*1b3f573fSAndroid Build Coastguard Worker /// </summary> CopyFrom(string text, Encoding encoding)241*1b3f573fSAndroid Build Coastguard Worker public static ByteString CopyFrom(string text, Encoding encoding) 242*1b3f573fSAndroid Build Coastguard Worker { 243*1b3f573fSAndroid Build Coastguard Worker return new ByteString(encoding.GetBytes(text)); 244*1b3f573fSAndroid Build Coastguard Worker } 245*1b3f573fSAndroid Build Coastguard Worker 246*1b3f573fSAndroid Build Coastguard Worker /// <summary> 247*1b3f573fSAndroid Build Coastguard Worker /// Creates a new <see cref="ByteString" /> by encoding the specified text in UTF-8. 248*1b3f573fSAndroid Build Coastguard Worker /// </summary> CopyFromUtf8(string text)249*1b3f573fSAndroid Build Coastguard Worker public static ByteString CopyFromUtf8(string text) 250*1b3f573fSAndroid Build Coastguard Worker { 251*1b3f573fSAndroid Build Coastguard Worker return CopyFrom(text, Encoding.UTF8); 252*1b3f573fSAndroid Build Coastguard Worker } 253*1b3f573fSAndroid Build Coastguard Worker 254*1b3f573fSAndroid Build Coastguard Worker /// <summary> 255*1b3f573fSAndroid Build Coastguard Worker /// Returns the byte at the given index. 256*1b3f573fSAndroid Build Coastguard Worker /// </summary> 257*1b3f573fSAndroid Build Coastguard Worker public byte this[int index] 258*1b3f573fSAndroid Build Coastguard Worker { 259*1b3f573fSAndroid Build Coastguard Worker get { return bytes.Span[index]; } 260*1b3f573fSAndroid Build Coastguard Worker } 261*1b3f573fSAndroid Build Coastguard Worker 262*1b3f573fSAndroid Build Coastguard Worker /// <summary> 263*1b3f573fSAndroid Build Coastguard Worker /// Converts this <see cref="ByteString"/> into a string by applying the given encoding. 264*1b3f573fSAndroid Build Coastguard Worker /// </summary> 265*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 266*1b3f573fSAndroid Build Coastguard Worker /// This method should only be used to convert binary data which was the result of encoding 267*1b3f573fSAndroid Build Coastguard Worker /// text with the given encoding. 268*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 269*1b3f573fSAndroid Build Coastguard Worker /// <param name="encoding">The encoding to use to decode the binary data into text.</param> 270*1b3f573fSAndroid Build Coastguard Worker /// <returns>The result of decoding the binary data with the given decoding.</returns> ToString(Encoding encoding)271*1b3f573fSAndroid Build Coastguard Worker public string ToString(Encoding encoding) 272*1b3f573fSAndroid Build Coastguard Worker { 273*1b3f573fSAndroid Build Coastguard Worker if (MemoryMarshal.TryGetArray(bytes, out ArraySegment<byte> segment)) 274*1b3f573fSAndroid Build Coastguard Worker { 275*1b3f573fSAndroid Build Coastguard Worker // Fast path. ByteString was created with an array. 276*1b3f573fSAndroid Build Coastguard Worker return encoding.GetString(segment.Array, segment.Offset, segment.Count); 277*1b3f573fSAndroid Build Coastguard Worker } 278*1b3f573fSAndroid Build Coastguard Worker else 279*1b3f573fSAndroid Build Coastguard Worker { 280*1b3f573fSAndroid Build Coastguard Worker // Slow path. BytesString is not an array. Convert memory and pass result to GetString. 281*1b3f573fSAndroid Build Coastguard Worker // TODO: Consider using GetString overload that takes a pointer. 282*1b3f573fSAndroid Build Coastguard Worker byte[] array = bytes.ToArray(); 283*1b3f573fSAndroid Build Coastguard Worker return encoding.GetString(array, 0, array.Length); 284*1b3f573fSAndroid Build Coastguard Worker } 285*1b3f573fSAndroid Build Coastguard Worker } 286*1b3f573fSAndroid Build Coastguard Worker 287*1b3f573fSAndroid Build Coastguard Worker /// <summary> 288*1b3f573fSAndroid Build Coastguard Worker /// Converts this <see cref="ByteString"/> into a string by applying the UTF-8 encoding. 289*1b3f573fSAndroid Build Coastguard Worker /// </summary> 290*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 291*1b3f573fSAndroid Build Coastguard Worker /// This method should only be used to convert binary data which was the result of encoding 292*1b3f573fSAndroid Build Coastguard Worker /// text with UTF-8. 293*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 294*1b3f573fSAndroid Build Coastguard Worker /// <returns>The result of decoding the binary data with the given decoding.</returns> ToStringUtf8()295*1b3f573fSAndroid Build Coastguard Worker public string ToStringUtf8() 296*1b3f573fSAndroid Build Coastguard Worker { 297*1b3f573fSAndroid Build Coastguard Worker return ToString(Encoding.UTF8); 298*1b3f573fSAndroid Build Coastguard Worker } 299*1b3f573fSAndroid Build Coastguard Worker 300*1b3f573fSAndroid Build Coastguard Worker /// <summary> 301*1b3f573fSAndroid Build Coastguard Worker /// Returns an iterator over the bytes in this <see cref="ByteString"/>. 302*1b3f573fSAndroid Build Coastguard Worker /// </summary> 303*1b3f573fSAndroid Build Coastguard Worker /// <returns>An iterator over the bytes in this object.</returns> 304*1b3f573fSAndroid Build Coastguard Worker [SecuritySafeCritical] GetEnumerator()305*1b3f573fSAndroid Build Coastguard Worker public IEnumerator<byte> GetEnumerator() 306*1b3f573fSAndroid Build Coastguard Worker { 307*1b3f573fSAndroid Build Coastguard Worker return MemoryMarshal.ToEnumerable(bytes).GetEnumerator(); 308*1b3f573fSAndroid Build Coastguard Worker } 309*1b3f573fSAndroid Build Coastguard Worker 310*1b3f573fSAndroid Build Coastguard Worker /// <summary> 311*1b3f573fSAndroid Build Coastguard Worker /// Returns an iterator over the bytes in this <see cref="ByteString"/>. 312*1b3f573fSAndroid Build Coastguard Worker /// </summary> 313*1b3f573fSAndroid Build Coastguard Worker /// <returns>An iterator over the bytes in this object.</returns> IEnumerable.GetEnumerator()314*1b3f573fSAndroid Build Coastguard Worker IEnumerator IEnumerable.GetEnumerator() 315*1b3f573fSAndroid Build Coastguard Worker { 316*1b3f573fSAndroid Build Coastguard Worker return GetEnumerator(); 317*1b3f573fSAndroid Build Coastguard Worker } 318*1b3f573fSAndroid Build Coastguard Worker 319*1b3f573fSAndroid Build Coastguard Worker /// <summary> 320*1b3f573fSAndroid Build Coastguard Worker /// Creates a CodedInputStream from this ByteString's data. 321*1b3f573fSAndroid Build Coastguard Worker /// </summary> CreateCodedInput()322*1b3f573fSAndroid Build Coastguard Worker public CodedInputStream CreateCodedInput() 323*1b3f573fSAndroid Build Coastguard Worker { 324*1b3f573fSAndroid Build Coastguard Worker // We trust CodedInputStream not to reveal the provided byte array or modify it 325*1b3f573fSAndroid Build Coastguard Worker if (MemoryMarshal.TryGetArray(bytes, out ArraySegment<byte> segment) && segment.Count == bytes.Length) 326*1b3f573fSAndroid Build Coastguard Worker { 327*1b3f573fSAndroid Build Coastguard Worker // Fast path. ByteString was created with a complete array. 328*1b3f573fSAndroid Build Coastguard Worker return new CodedInputStream(segment.Array, segment.Offset, segment.Count); 329*1b3f573fSAndroid Build Coastguard Worker } 330*1b3f573fSAndroid Build Coastguard Worker else 331*1b3f573fSAndroid Build Coastguard Worker { 332*1b3f573fSAndroid Build Coastguard Worker // Slow path. BytesString is not an array, or is a slice of an array. 333*1b3f573fSAndroid Build Coastguard Worker // Convert memory and pass result to WriteRawBytes. 334*1b3f573fSAndroid Build Coastguard Worker return new CodedInputStream(bytes.ToArray()); 335*1b3f573fSAndroid Build Coastguard Worker } 336*1b3f573fSAndroid Build Coastguard Worker } 337*1b3f573fSAndroid Build Coastguard Worker 338*1b3f573fSAndroid Build Coastguard Worker /// <summary> 339*1b3f573fSAndroid Build Coastguard Worker /// Compares two byte strings for equality. 340*1b3f573fSAndroid Build Coastguard Worker /// </summary> 341*1b3f573fSAndroid Build Coastguard Worker /// <param name="lhs">The first byte string to compare.</param> 342*1b3f573fSAndroid Build Coastguard Worker /// <param name="rhs">The second byte string to compare.</param> 343*1b3f573fSAndroid Build Coastguard Worker /// <returns><c>true</c> if the byte strings are equal; false otherwise.</returns> operator ==(ByteString lhs, ByteString rhs)344*1b3f573fSAndroid Build Coastguard Worker public static bool operator ==(ByteString lhs, ByteString rhs) 345*1b3f573fSAndroid Build Coastguard Worker { 346*1b3f573fSAndroid Build Coastguard Worker if (ReferenceEquals(lhs, rhs)) 347*1b3f573fSAndroid Build Coastguard Worker { 348*1b3f573fSAndroid Build Coastguard Worker return true; 349*1b3f573fSAndroid Build Coastguard Worker } 350*1b3f573fSAndroid Build Coastguard Worker if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) 351*1b3f573fSAndroid Build Coastguard Worker { 352*1b3f573fSAndroid Build Coastguard Worker return false; 353*1b3f573fSAndroid Build Coastguard Worker } 354*1b3f573fSAndroid Build Coastguard Worker 355*1b3f573fSAndroid Build Coastguard Worker return lhs.bytes.Span.SequenceEqual(rhs.bytes.Span); 356*1b3f573fSAndroid Build Coastguard Worker } 357*1b3f573fSAndroid Build Coastguard Worker 358*1b3f573fSAndroid Build Coastguard Worker /// <summary> 359*1b3f573fSAndroid Build Coastguard Worker /// Compares two byte strings for inequality. 360*1b3f573fSAndroid Build Coastguard Worker /// </summary> 361*1b3f573fSAndroid Build Coastguard Worker /// <param name="lhs">The first byte string to compare.</param> 362*1b3f573fSAndroid Build Coastguard Worker /// <param name="rhs">The second byte string to compare.</param> 363*1b3f573fSAndroid Build Coastguard Worker /// <returns><c>false</c> if the byte strings are equal; true otherwise.</returns> operator !=(ByteString lhs, ByteString rhs)364*1b3f573fSAndroid Build Coastguard Worker public static bool operator !=(ByteString lhs, ByteString rhs) 365*1b3f573fSAndroid Build Coastguard Worker { 366*1b3f573fSAndroid Build Coastguard Worker return !(lhs == rhs); 367*1b3f573fSAndroid Build Coastguard Worker } 368*1b3f573fSAndroid Build Coastguard Worker 369*1b3f573fSAndroid Build Coastguard Worker /// <summary> 370*1b3f573fSAndroid Build Coastguard Worker /// Compares this byte string with another object. 371*1b3f573fSAndroid Build Coastguard Worker /// </summary> 372*1b3f573fSAndroid Build Coastguard Worker /// <param name="obj">The object to compare this with.</param> 373*1b3f573fSAndroid Build Coastguard Worker /// <returns><c>true</c> if <paramref name="obj"/> refers to an equal <see cref="ByteString"/>; <c>false</c> otherwise.</returns> 374*1b3f573fSAndroid Build Coastguard Worker [SecuritySafeCritical] Equals(object obj)375*1b3f573fSAndroid Build Coastguard Worker public override bool Equals(object obj) 376*1b3f573fSAndroid Build Coastguard Worker { 377*1b3f573fSAndroid Build Coastguard Worker return this == (obj as ByteString); 378*1b3f573fSAndroid Build Coastguard Worker } 379*1b3f573fSAndroid Build Coastguard Worker 380*1b3f573fSAndroid Build Coastguard Worker /// <summary> 381*1b3f573fSAndroid Build Coastguard Worker /// Returns a hash code for this object. Two equal byte strings 382*1b3f573fSAndroid Build Coastguard Worker /// will return the same hash code. 383*1b3f573fSAndroid Build Coastguard Worker /// </summary> 384*1b3f573fSAndroid Build Coastguard Worker /// <returns>A hash code for this object.</returns> 385*1b3f573fSAndroid Build Coastguard Worker [SecuritySafeCritical] GetHashCode()386*1b3f573fSAndroid Build Coastguard Worker public override int GetHashCode() 387*1b3f573fSAndroid Build Coastguard Worker { 388*1b3f573fSAndroid Build Coastguard Worker ReadOnlySpan<byte> b = bytes.Span; 389*1b3f573fSAndroid Build Coastguard Worker 390*1b3f573fSAndroid Build Coastguard Worker int ret = 23; 391*1b3f573fSAndroid Build Coastguard Worker for (int i = 0; i < b.Length; i++) 392*1b3f573fSAndroid Build Coastguard Worker { 393*1b3f573fSAndroid Build Coastguard Worker ret = (ret * 31) + b[i]; 394*1b3f573fSAndroid Build Coastguard Worker } 395*1b3f573fSAndroid Build Coastguard Worker return ret; 396*1b3f573fSAndroid Build Coastguard Worker } 397*1b3f573fSAndroid Build Coastguard Worker 398*1b3f573fSAndroid Build Coastguard Worker /// <summary> 399*1b3f573fSAndroid Build Coastguard Worker /// Compares this byte string with another. 400*1b3f573fSAndroid Build Coastguard Worker /// </summary> 401*1b3f573fSAndroid Build Coastguard Worker /// <param name="other">The <see cref="ByteString"/> to compare this with.</param> 402*1b3f573fSAndroid Build Coastguard Worker /// <returns><c>true</c> if <paramref name="other"/> refers to an equal byte string; <c>false</c> otherwise.</returns> Equals(ByteString other)403*1b3f573fSAndroid Build Coastguard Worker public bool Equals(ByteString other) 404*1b3f573fSAndroid Build Coastguard Worker { 405*1b3f573fSAndroid Build Coastguard Worker return this == other; 406*1b3f573fSAndroid Build Coastguard Worker } 407*1b3f573fSAndroid Build Coastguard Worker 408*1b3f573fSAndroid Build Coastguard Worker /// <summary> 409*1b3f573fSAndroid Build Coastguard Worker /// Copies the entire byte array to the destination array provided at the offset specified. 410*1b3f573fSAndroid Build Coastguard Worker /// </summary> CopyTo(byte[] array, int position)411*1b3f573fSAndroid Build Coastguard Worker public void CopyTo(byte[] array, int position) 412*1b3f573fSAndroid Build Coastguard Worker { 413*1b3f573fSAndroid Build Coastguard Worker bytes.CopyTo(array.AsMemory(position)); 414*1b3f573fSAndroid Build Coastguard Worker } 415*1b3f573fSAndroid Build Coastguard Worker 416*1b3f573fSAndroid Build Coastguard Worker /// <summary> 417*1b3f573fSAndroid Build Coastguard Worker /// Writes the entire byte array to the provided stream 418*1b3f573fSAndroid Build Coastguard Worker /// </summary> WriteTo(Stream outputStream)419*1b3f573fSAndroid Build Coastguard Worker public void WriteTo(Stream outputStream) 420*1b3f573fSAndroid Build Coastguard Worker { 421*1b3f573fSAndroid Build Coastguard Worker if (MemoryMarshal.TryGetArray(bytes, out ArraySegment<byte> segment)) 422*1b3f573fSAndroid Build Coastguard Worker { 423*1b3f573fSAndroid Build Coastguard Worker // Fast path. ByteString was created with an array, so pass the underlying array. 424*1b3f573fSAndroid Build Coastguard Worker outputStream.Write(segment.Array, segment.Offset, segment.Count); 425*1b3f573fSAndroid Build Coastguard Worker } 426*1b3f573fSAndroid Build Coastguard Worker else 427*1b3f573fSAndroid Build Coastguard Worker { 428*1b3f573fSAndroid Build Coastguard Worker // Slow path. BytesString is not an array. Convert memory and pass result to WriteRawBytes. 429*1b3f573fSAndroid Build Coastguard Worker var array = bytes.ToArray(); 430*1b3f573fSAndroid Build Coastguard Worker outputStream.Write(array, 0, array.Length); 431*1b3f573fSAndroid Build Coastguard Worker } 432*1b3f573fSAndroid Build Coastguard Worker } 433*1b3f573fSAndroid Build Coastguard Worker } 434*1b3f573fSAndroid Build Coastguard Worker }