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 Google.Protobuf.Collections; 34*1b3f573fSAndroid Build Coastguard Worker using System; 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.CompilerServices; 38*1b3f573fSAndroid Build Coastguard Worker using System.Runtime.InteropServices; 39*1b3f573fSAndroid Build Coastguard Worker using System.Security; 40*1b3f573fSAndroid Build Coastguard Worker 41*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf 42*1b3f573fSAndroid Build Coastguard Worker { 43*1b3f573fSAndroid Build Coastguard Worker /// <summary> 44*1b3f573fSAndroid Build Coastguard Worker /// Reads and decodes protocol message fields. 45*1b3f573fSAndroid Build Coastguard Worker /// </summary> 46*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 47*1b3f573fSAndroid Build Coastguard Worker /// <para> 48*1b3f573fSAndroid Build Coastguard Worker /// This class is generally used by generated code to read appropriate 49*1b3f573fSAndroid Build Coastguard Worker /// primitives from the stream. It effectively encapsulates the lowest 50*1b3f573fSAndroid Build Coastguard Worker /// levels of protocol buffer format. 51*1b3f573fSAndroid Build Coastguard Worker /// </para> 52*1b3f573fSAndroid Build Coastguard Worker /// <para> 53*1b3f573fSAndroid Build Coastguard Worker /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/> 54*1b3f573fSAndroid Build Coastguard Worker /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields. 55*1b3f573fSAndroid Build Coastguard Worker /// </para> 56*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 57*1b3f573fSAndroid Build Coastguard Worker [SecuritySafeCritical] 58*1b3f573fSAndroid Build Coastguard Worker public sealed class CodedInputStream : IDisposable 59*1b3f573fSAndroid Build Coastguard Worker { 60*1b3f573fSAndroid Build Coastguard Worker /// <summary> 61*1b3f573fSAndroid Build Coastguard Worker /// Whether to leave the underlying stream open when disposing of this stream. 62*1b3f573fSAndroid Build Coastguard Worker /// This is always true when there's no stream. 63*1b3f573fSAndroid Build Coastguard Worker /// </summary> 64*1b3f573fSAndroid Build Coastguard Worker private readonly bool leaveOpen; 65*1b3f573fSAndroid Build Coastguard Worker 66*1b3f573fSAndroid Build Coastguard Worker /// <summary> 67*1b3f573fSAndroid Build Coastguard Worker /// Buffer of data read from the stream or provided at construction time. 68*1b3f573fSAndroid Build Coastguard Worker /// </summary> 69*1b3f573fSAndroid Build Coastguard Worker private readonly byte[] buffer; 70*1b3f573fSAndroid Build Coastguard Worker 71*1b3f573fSAndroid Build Coastguard Worker /// <summary> 72*1b3f573fSAndroid Build Coastguard Worker /// The stream to read further input from, or null if the byte array buffer was provided 73*1b3f573fSAndroid Build Coastguard Worker /// directly on construction, with no further data available. 74*1b3f573fSAndroid Build Coastguard Worker /// </summary> 75*1b3f573fSAndroid Build Coastguard Worker private readonly Stream input; 76*1b3f573fSAndroid Build Coastguard Worker 77*1b3f573fSAndroid Build Coastguard Worker /// <summary> 78*1b3f573fSAndroid Build Coastguard Worker /// The parser state is kept separately so that other parse implementations can reuse the same 79*1b3f573fSAndroid Build Coastguard Worker /// parsing primitives. 80*1b3f573fSAndroid Build Coastguard Worker /// </summary> 81*1b3f573fSAndroid Build Coastguard Worker private ParserInternalState state; 82*1b3f573fSAndroid Build Coastguard Worker 83*1b3f573fSAndroid Build Coastguard Worker internal const int DefaultRecursionLimit = 100; 84*1b3f573fSAndroid Build Coastguard Worker internal const int DefaultSizeLimit = Int32.MaxValue; 85*1b3f573fSAndroid Build Coastguard Worker internal const int BufferSize = 4096; 86*1b3f573fSAndroid Build Coastguard Worker 87*1b3f573fSAndroid Build Coastguard Worker #region Construction 88*1b3f573fSAndroid Build Coastguard Worker // Note that the checks are performed such that we don't end up checking obviously-valid things 89*1b3f573fSAndroid Build Coastguard Worker // like non-null references for arrays we've just created. 90*1b3f573fSAndroid Build Coastguard Worker 91*1b3f573fSAndroid Build Coastguard Worker /// <summary> 92*1b3f573fSAndroid Build Coastguard Worker /// Creates a new CodedInputStream reading data from the given byte array. 93*1b3f573fSAndroid Build Coastguard Worker /// </summary> CodedInputStream(byte[] buffer)94*1b3f573fSAndroid Build Coastguard Worker public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, true) 95*1b3f573fSAndroid Build Coastguard Worker { 96*1b3f573fSAndroid Build Coastguard Worker } 97*1b3f573fSAndroid Build Coastguard Worker 98*1b3f573fSAndroid Build Coastguard Worker /// <summary> 99*1b3f573fSAndroid Build Coastguard Worker /// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice. 100*1b3f573fSAndroid Build Coastguard Worker /// </summary> CodedInputStream(byte[] buffer, int offset, int length)101*1b3f573fSAndroid Build Coastguard Worker public CodedInputStream(byte[] buffer, int offset, int length) 102*1b3f573fSAndroid Build Coastguard Worker : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, true) 103*1b3f573fSAndroid Build Coastguard Worker { 104*1b3f573fSAndroid Build Coastguard Worker if (offset < 0 || offset > buffer.Length) 105*1b3f573fSAndroid Build Coastguard Worker { 106*1b3f573fSAndroid Build Coastguard Worker throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer"); 107*1b3f573fSAndroid Build Coastguard Worker } 108*1b3f573fSAndroid Build Coastguard Worker if (length < 0 || offset + length > buffer.Length) 109*1b3f573fSAndroid Build Coastguard Worker { 110*1b3f573fSAndroid Build Coastguard Worker throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer"); 111*1b3f573fSAndroid Build Coastguard Worker } 112*1b3f573fSAndroid Build Coastguard Worker } 113*1b3f573fSAndroid Build Coastguard Worker 114*1b3f573fSAndroid Build Coastguard Worker /// <summary> 115*1b3f573fSAndroid Build Coastguard Worker /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed 116*1b3f573fSAndroid Build Coastguard Worker /// when the returned object is disposed. 117*1b3f573fSAndroid Build Coastguard Worker /// </summary> 118*1b3f573fSAndroid Build Coastguard Worker /// <param name="input">The stream to read from.</param> CodedInputStream(Stream input)119*1b3f573fSAndroid Build Coastguard Worker public CodedInputStream(Stream input) : this(input, false) 120*1b3f573fSAndroid Build Coastguard Worker { 121*1b3f573fSAndroid Build Coastguard Worker } 122*1b3f573fSAndroid Build Coastguard Worker 123*1b3f573fSAndroid Build Coastguard Worker /// <summary> 124*1b3f573fSAndroid Build Coastguard Worker /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream. 125*1b3f573fSAndroid Build Coastguard Worker /// </summary> 126*1b3f573fSAndroid Build Coastguard Worker /// <param name="input">The stream to read from.</param> 127*1b3f573fSAndroid Build Coastguard Worker /// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned 128*1b3f573fSAndroid Build Coastguard Worker /// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when the 129*1b3f573fSAndroid Build Coastguard Worker /// returned object is disposed.</param> CodedInputStream(Stream input, bool leaveOpen)130*1b3f573fSAndroid Build Coastguard Worker public CodedInputStream(Stream input, bool leaveOpen) 131*1b3f573fSAndroid Build Coastguard Worker : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0, leaveOpen) 132*1b3f573fSAndroid Build Coastguard Worker { 133*1b3f573fSAndroid Build Coastguard Worker } 134*1b3f573fSAndroid Build Coastguard Worker 135*1b3f573fSAndroid Build Coastguard Worker /// <summary> 136*1b3f573fSAndroid Build Coastguard Worker /// Creates a new CodedInputStream reading data from the given 137*1b3f573fSAndroid Build Coastguard Worker /// stream and buffer, using the default limits. 138*1b3f573fSAndroid Build Coastguard Worker /// </summary> CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen)139*1b3f573fSAndroid Build Coastguard Worker internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen) 140*1b3f573fSAndroid Build Coastguard Worker { 141*1b3f573fSAndroid Build Coastguard Worker this.input = input; 142*1b3f573fSAndroid Build Coastguard Worker this.buffer = buffer; 143*1b3f573fSAndroid Build Coastguard Worker this.state.bufferPos = bufferPos; 144*1b3f573fSAndroid Build Coastguard Worker this.state.bufferSize = bufferSize; 145*1b3f573fSAndroid Build Coastguard Worker this.state.sizeLimit = DefaultSizeLimit; 146*1b3f573fSAndroid Build Coastguard Worker this.state.recursionLimit = DefaultRecursionLimit; 147*1b3f573fSAndroid Build Coastguard Worker SegmentedBufferHelper.Initialize(this, out this.state.segmentedBufferHelper); 148*1b3f573fSAndroid Build Coastguard Worker this.leaveOpen = leaveOpen; 149*1b3f573fSAndroid Build Coastguard Worker 150*1b3f573fSAndroid Build Coastguard Worker this.state.currentLimit = int.MaxValue; 151*1b3f573fSAndroid Build Coastguard Worker } 152*1b3f573fSAndroid Build Coastguard Worker 153*1b3f573fSAndroid Build Coastguard Worker /// <summary> 154*1b3f573fSAndroid Build Coastguard Worker /// Creates a new CodedInputStream reading data from the given 155*1b3f573fSAndroid Build Coastguard Worker /// stream and buffer, using the specified limits. 156*1b3f573fSAndroid Build Coastguard Worker /// </summary> 157*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 158*1b3f573fSAndroid Build Coastguard Worker /// This chains to the version with the default limits instead of vice versa to avoid 159*1b3f573fSAndroid Build Coastguard Worker /// having to check that the default values are valid every time. 160*1b3f573fSAndroid Build Coastguard Worker /// </remarks> CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen)161*1b3f573fSAndroid Build Coastguard Worker internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen) 162*1b3f573fSAndroid Build Coastguard Worker : this(input, buffer, bufferPos, bufferSize, leaveOpen) 163*1b3f573fSAndroid Build Coastguard Worker { 164*1b3f573fSAndroid Build Coastguard Worker if (sizeLimit <= 0) 165*1b3f573fSAndroid Build Coastguard Worker { 166*1b3f573fSAndroid Build Coastguard Worker throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive"); 167*1b3f573fSAndroid Build Coastguard Worker } 168*1b3f573fSAndroid Build Coastguard Worker if (recursionLimit <= 0) 169*1b3f573fSAndroid Build Coastguard Worker { 170*1b3f573fSAndroid Build Coastguard Worker throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive"); 171*1b3f573fSAndroid Build Coastguard Worker } 172*1b3f573fSAndroid Build Coastguard Worker this.state.sizeLimit = sizeLimit; 173*1b3f573fSAndroid Build Coastguard Worker this.state.recursionLimit = recursionLimit; 174*1b3f573fSAndroid Build Coastguard Worker } 175*1b3f573fSAndroid Build Coastguard Worker #endregion 176*1b3f573fSAndroid Build Coastguard Worker 177*1b3f573fSAndroid Build Coastguard Worker /// <summary> 178*1b3f573fSAndroid Build Coastguard Worker /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading 179*1b3f573fSAndroid Build Coastguard Worker /// from an input stream. 180*1b3f573fSAndroid Build Coastguard Worker /// </summary> 181*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 182*1b3f573fSAndroid Build Coastguard Worker /// This method exists separately from the constructor to reduce the number of constructor overloads. 183*1b3f573fSAndroid Build Coastguard Worker /// It is likely to be used considerably less frequently than the constructors, as the default limits 184*1b3f573fSAndroid Build Coastguard Worker /// are suitable for most use cases. 185*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 186*1b3f573fSAndroid Build Coastguard Worker /// <param name="input">The input stream to read from</param> 187*1b3f573fSAndroid Build Coastguard Worker /// <param name="sizeLimit">The total limit of data to read from the stream.</param> 188*1b3f573fSAndroid Build Coastguard Worker /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param> 189*1b3f573fSAndroid Build Coastguard Worker /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size 190*1b3f573fSAndroid Build Coastguard Worker /// and recursion limits.</returns> CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)191*1b3f573fSAndroid Build Coastguard Worker public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit) 192*1b3f573fSAndroid Build Coastguard Worker { 193*1b3f573fSAndroid Build Coastguard Worker // Note: we may want an overload accepting leaveOpen 194*1b3f573fSAndroid Build Coastguard Worker return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit, false); 195*1b3f573fSAndroid Build Coastguard Worker } 196*1b3f573fSAndroid Build Coastguard Worker 197*1b3f573fSAndroid Build Coastguard Worker /// <summary> 198*1b3f573fSAndroid Build Coastguard Worker /// Returns the current position in the input stream, or the position in the input buffer 199*1b3f573fSAndroid Build Coastguard Worker /// </summary> 200*1b3f573fSAndroid Build Coastguard Worker public long Position 201*1b3f573fSAndroid Build Coastguard Worker { 202*1b3f573fSAndroid Build Coastguard Worker get 203*1b3f573fSAndroid Build Coastguard Worker { 204*1b3f573fSAndroid Build Coastguard Worker if (input != null) 205*1b3f573fSAndroid Build Coastguard Worker { 206*1b3f573fSAndroid Build Coastguard Worker return input.Position - ((state.bufferSize + state.bufferSizeAfterLimit) - state.bufferPos); 207*1b3f573fSAndroid Build Coastguard Worker } 208*1b3f573fSAndroid Build Coastguard Worker return state.bufferPos; 209*1b3f573fSAndroid Build Coastguard Worker } 210*1b3f573fSAndroid Build Coastguard Worker } 211*1b3f573fSAndroid Build Coastguard Worker 212*1b3f573fSAndroid Build Coastguard Worker /// <summary> 213*1b3f573fSAndroid Build Coastguard Worker /// Returns the last tag read, or 0 if no tags have been read or we've read beyond 214*1b3f573fSAndroid Build Coastguard Worker /// the end of the stream. 215*1b3f573fSAndroid Build Coastguard Worker /// </summary> 216*1b3f573fSAndroid Build Coastguard Worker internal uint LastTag { get { return state.lastTag; } } 217*1b3f573fSAndroid Build Coastguard Worker 218*1b3f573fSAndroid Build Coastguard Worker /// <summary> 219*1b3f573fSAndroid Build Coastguard Worker /// Returns the size limit for this stream. 220*1b3f573fSAndroid Build Coastguard Worker /// </summary> 221*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 222*1b3f573fSAndroid Build Coastguard Worker /// This limit is applied when reading from the underlying stream, as a sanity check. It is 223*1b3f573fSAndroid Build Coastguard Worker /// not applied when reading from a byte array data source without an underlying stream. 224*1b3f573fSAndroid Build Coastguard Worker /// The default value is Int32.MaxValue. 225*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 226*1b3f573fSAndroid Build Coastguard Worker /// <value> 227*1b3f573fSAndroid Build Coastguard Worker /// The size limit. 228*1b3f573fSAndroid Build Coastguard Worker /// </value> 229*1b3f573fSAndroid Build Coastguard Worker public int SizeLimit { get { return state.sizeLimit; } } 230*1b3f573fSAndroid Build Coastguard Worker 231*1b3f573fSAndroid Build Coastguard Worker /// <summary> 232*1b3f573fSAndroid Build Coastguard Worker /// Returns the recursion limit for this stream. This limit is applied whilst reading messages, 233*1b3f573fSAndroid Build Coastguard Worker /// to avoid maliciously-recursive data. 234*1b3f573fSAndroid Build Coastguard Worker /// </summary> 235*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 236*1b3f573fSAndroid Build Coastguard Worker /// The default limit is 100. 237*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 238*1b3f573fSAndroid Build Coastguard Worker /// <value> 239*1b3f573fSAndroid Build Coastguard Worker /// The recursion limit for this stream. 240*1b3f573fSAndroid Build Coastguard Worker /// </value> 241*1b3f573fSAndroid Build Coastguard Worker public int RecursionLimit { get { return state.recursionLimit; } } 242*1b3f573fSAndroid Build Coastguard Worker 243*1b3f573fSAndroid Build Coastguard Worker /// <summary> 244*1b3f573fSAndroid Build Coastguard Worker /// Internal-only property; when set to true, unknown fields will be discarded while parsing. 245*1b3f573fSAndroid Build Coastguard Worker /// </summary> 246*1b3f573fSAndroid Build Coastguard Worker internal bool DiscardUnknownFields 247*1b3f573fSAndroid Build Coastguard Worker { 248*1b3f573fSAndroid Build Coastguard Worker get { return state.DiscardUnknownFields; } 249*1b3f573fSAndroid Build Coastguard Worker set { state.DiscardUnknownFields = value; } 250*1b3f573fSAndroid Build Coastguard Worker } 251*1b3f573fSAndroid Build Coastguard Worker 252*1b3f573fSAndroid Build Coastguard Worker /// <summary> 253*1b3f573fSAndroid Build Coastguard Worker /// Internal-only property; provides extension identifiers to compatible messages while parsing. 254*1b3f573fSAndroid Build Coastguard Worker /// </summary> 255*1b3f573fSAndroid Build Coastguard Worker internal ExtensionRegistry ExtensionRegistry 256*1b3f573fSAndroid Build Coastguard Worker { 257*1b3f573fSAndroid Build Coastguard Worker get { return state.ExtensionRegistry; } 258*1b3f573fSAndroid Build Coastguard Worker set { state.ExtensionRegistry = value; } 259*1b3f573fSAndroid Build Coastguard Worker } 260*1b3f573fSAndroid Build Coastguard Worker 261*1b3f573fSAndroid Build Coastguard Worker internal byte[] InternalBuffer => buffer; 262*1b3f573fSAndroid Build Coastguard Worker 263*1b3f573fSAndroid Build Coastguard Worker internal Stream InternalInputStream => input; 264*1b3f573fSAndroid Build Coastguard Worker 265*1b3f573fSAndroid Build Coastguard Worker internal ref ParserInternalState InternalState => ref state; 266*1b3f573fSAndroid Build Coastguard Worker 267*1b3f573fSAndroid Build Coastguard Worker /// <summary> 268*1b3f573fSAndroid Build Coastguard Worker /// Disposes of this instance, potentially closing any underlying stream. 269*1b3f573fSAndroid Build Coastguard Worker /// </summary> 270*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 271*1b3f573fSAndroid Build Coastguard Worker /// As there is no flushing to perform here, disposing of a <see cref="CodedInputStream"/> which 272*1b3f573fSAndroid Build Coastguard Worker /// was constructed with the <c>leaveOpen</c> option parameter set to <c>true</c> (or one which 273*1b3f573fSAndroid Build Coastguard Worker /// was constructed to read from a byte array) has no effect. 274*1b3f573fSAndroid Build Coastguard Worker /// </remarks> Dispose()275*1b3f573fSAndroid Build Coastguard Worker public void Dispose() 276*1b3f573fSAndroid Build Coastguard Worker { 277*1b3f573fSAndroid Build Coastguard Worker if (!leaveOpen) 278*1b3f573fSAndroid Build Coastguard Worker { 279*1b3f573fSAndroid Build Coastguard Worker input.Dispose(); 280*1b3f573fSAndroid Build Coastguard Worker } 281*1b3f573fSAndroid Build Coastguard Worker } 282*1b3f573fSAndroid Build Coastguard Worker 283*1b3f573fSAndroid Build Coastguard Worker #region Validation 284*1b3f573fSAndroid Build Coastguard Worker /// <summary> 285*1b3f573fSAndroid Build Coastguard Worker /// Verifies that the last call to ReadTag() returned tag 0 - in other words, 286*1b3f573fSAndroid Build Coastguard Worker /// we've reached the end of the stream when we expected to. 287*1b3f573fSAndroid Build Coastguard Worker /// </summary> 288*1b3f573fSAndroid Build Coastguard Worker /// <exception cref="InvalidProtocolBufferException">The 289*1b3f573fSAndroid Build Coastguard Worker /// tag read was not the one specified</exception> CheckReadEndOfStreamTag()290*1b3f573fSAndroid Build Coastguard Worker internal void CheckReadEndOfStreamTag() 291*1b3f573fSAndroid Build Coastguard Worker { 292*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref state); 293*1b3f573fSAndroid Build Coastguard Worker } 294*1b3f573fSAndroid Build Coastguard Worker #endregion 295*1b3f573fSAndroid Build Coastguard Worker 296*1b3f573fSAndroid Build Coastguard Worker #region Reading of tags etc 297*1b3f573fSAndroid Build Coastguard Worker 298*1b3f573fSAndroid Build Coastguard Worker /// <summary> 299*1b3f573fSAndroid Build Coastguard Worker /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the 300*1b3f573fSAndroid Build Coastguard Worker /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the 301*1b3f573fSAndroid Build Coastguard Worker /// same value.) 302*1b3f573fSAndroid Build Coastguard Worker /// </summary> PeekTag()303*1b3f573fSAndroid Build Coastguard Worker public uint PeekTag() 304*1b3f573fSAndroid Build Coastguard Worker { 305*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 306*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.PeekTag(ref span, ref state); 307*1b3f573fSAndroid Build Coastguard Worker } 308*1b3f573fSAndroid Build Coastguard Worker 309*1b3f573fSAndroid Build Coastguard Worker /// <summary> 310*1b3f573fSAndroid Build Coastguard Worker /// Reads a field tag, returning the tag of 0 for "end of stream". 311*1b3f573fSAndroid Build Coastguard Worker /// </summary> 312*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 313*1b3f573fSAndroid Build Coastguard Worker /// If this method returns 0, it doesn't necessarily mean the end of all 314*1b3f573fSAndroid Build Coastguard Worker /// the data in this CodedInputStream; it may be the end of the logical stream 315*1b3f573fSAndroid Build Coastguard Worker /// for an embedded message, for example. 316*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 317*1b3f573fSAndroid Build Coastguard Worker /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns> ReadTag()318*1b3f573fSAndroid Build Coastguard Worker public uint ReadTag() 319*1b3f573fSAndroid Build Coastguard Worker { 320*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 321*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseTag(ref span, ref state); 322*1b3f573fSAndroid Build Coastguard Worker } 323*1b3f573fSAndroid Build Coastguard Worker 324*1b3f573fSAndroid Build Coastguard Worker /// <summary> 325*1b3f573fSAndroid Build Coastguard Worker /// Skips the data for the field with the tag we've just read. 326*1b3f573fSAndroid Build Coastguard Worker /// This should be called directly after <see cref="ReadTag"/>, when 327*1b3f573fSAndroid Build Coastguard Worker /// the caller wishes to skip an unknown field. 328*1b3f573fSAndroid Build Coastguard Worker /// </summary> 329*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 330*1b3f573fSAndroid Build Coastguard Worker /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag. 331*1b3f573fSAndroid Build Coastguard Worker /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the 332*1b3f573fSAndroid Build Coastguard Worker /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly 333*1b3f573fSAndroid Build Coastguard Worker /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag. 334*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 335*1b3f573fSAndroid Build Coastguard Worker /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception> 336*1b3f573fSAndroid Build Coastguard Worker /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception> SkipLastField()337*1b3f573fSAndroid Build Coastguard Worker public void SkipLastField() 338*1b3f573fSAndroid Build Coastguard Worker { 339*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 340*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.SkipLastField(ref span, ref state); 341*1b3f573fSAndroid Build Coastguard Worker } 342*1b3f573fSAndroid Build Coastguard Worker 343*1b3f573fSAndroid Build Coastguard Worker /// <summary> 344*1b3f573fSAndroid Build Coastguard Worker /// Skip a group. 345*1b3f573fSAndroid Build Coastguard Worker /// </summary> SkipGroup(uint startGroupTag)346*1b3f573fSAndroid Build Coastguard Worker internal void SkipGroup(uint startGroupTag) 347*1b3f573fSAndroid Build Coastguard Worker { 348*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 349*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.SkipGroup(ref span, ref state, startGroupTag); 350*1b3f573fSAndroid Build Coastguard Worker } 351*1b3f573fSAndroid Build Coastguard Worker 352*1b3f573fSAndroid Build Coastguard Worker /// <summary> 353*1b3f573fSAndroid Build Coastguard Worker /// Reads a double field from the stream. 354*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadDouble()355*1b3f573fSAndroid Build Coastguard Worker public double ReadDouble() 356*1b3f573fSAndroid Build Coastguard Worker { 357*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 358*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseDouble(ref span, ref state); 359*1b3f573fSAndroid Build Coastguard Worker } 360*1b3f573fSAndroid Build Coastguard Worker 361*1b3f573fSAndroid Build Coastguard Worker /// <summary> 362*1b3f573fSAndroid Build Coastguard Worker /// Reads a float field from the stream. 363*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadFloat()364*1b3f573fSAndroid Build Coastguard Worker public float ReadFloat() 365*1b3f573fSAndroid Build Coastguard Worker { 366*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 367*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseFloat(ref span, ref state); 368*1b3f573fSAndroid Build Coastguard Worker } 369*1b3f573fSAndroid Build Coastguard Worker 370*1b3f573fSAndroid Build Coastguard Worker /// <summary> 371*1b3f573fSAndroid Build Coastguard Worker /// Reads a uint64 field from the stream. 372*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadUInt64()373*1b3f573fSAndroid Build Coastguard Worker public ulong ReadUInt64() 374*1b3f573fSAndroid Build Coastguard Worker { 375*1b3f573fSAndroid Build Coastguard Worker return ReadRawVarint64(); 376*1b3f573fSAndroid Build Coastguard Worker } 377*1b3f573fSAndroid Build Coastguard Worker 378*1b3f573fSAndroid Build Coastguard Worker /// <summary> 379*1b3f573fSAndroid Build Coastguard Worker /// Reads an int64 field from the stream. 380*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadInt64()381*1b3f573fSAndroid Build Coastguard Worker public long ReadInt64() 382*1b3f573fSAndroid Build Coastguard Worker { 383*1b3f573fSAndroid Build Coastguard Worker return (long) ReadRawVarint64(); 384*1b3f573fSAndroid Build Coastguard Worker } 385*1b3f573fSAndroid Build Coastguard Worker 386*1b3f573fSAndroid Build Coastguard Worker /// <summary> 387*1b3f573fSAndroid Build Coastguard Worker /// Reads an int32 field from the stream. 388*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadInt32()389*1b3f573fSAndroid Build Coastguard Worker public int ReadInt32() 390*1b3f573fSAndroid Build Coastguard Worker { 391*1b3f573fSAndroid Build Coastguard Worker return (int) ReadRawVarint32(); 392*1b3f573fSAndroid Build Coastguard Worker } 393*1b3f573fSAndroid Build Coastguard Worker 394*1b3f573fSAndroid Build Coastguard Worker /// <summary> 395*1b3f573fSAndroid Build Coastguard Worker /// Reads a fixed64 field from the stream. 396*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadFixed64()397*1b3f573fSAndroid Build Coastguard Worker public ulong ReadFixed64() 398*1b3f573fSAndroid Build Coastguard Worker { 399*1b3f573fSAndroid Build Coastguard Worker return ReadRawLittleEndian64(); 400*1b3f573fSAndroid Build Coastguard Worker } 401*1b3f573fSAndroid Build Coastguard Worker 402*1b3f573fSAndroid Build Coastguard Worker /// <summary> 403*1b3f573fSAndroid Build Coastguard Worker /// Reads a fixed32 field from the stream. 404*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadFixed32()405*1b3f573fSAndroid Build Coastguard Worker public uint ReadFixed32() 406*1b3f573fSAndroid Build Coastguard Worker { 407*1b3f573fSAndroid Build Coastguard Worker return ReadRawLittleEndian32(); 408*1b3f573fSAndroid Build Coastguard Worker } 409*1b3f573fSAndroid Build Coastguard Worker 410*1b3f573fSAndroid Build Coastguard Worker /// <summary> 411*1b3f573fSAndroid Build Coastguard Worker /// Reads a bool field from the stream. 412*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadBool()413*1b3f573fSAndroid Build Coastguard Worker public bool ReadBool() 414*1b3f573fSAndroid Build Coastguard Worker { 415*1b3f573fSAndroid Build Coastguard Worker return ReadRawVarint64() != 0; 416*1b3f573fSAndroid Build Coastguard Worker } 417*1b3f573fSAndroid Build Coastguard Worker 418*1b3f573fSAndroid Build Coastguard Worker /// <summary> 419*1b3f573fSAndroid Build Coastguard Worker /// Reads a string field from the stream. 420*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadString()421*1b3f573fSAndroid Build Coastguard Worker public string ReadString() 422*1b3f573fSAndroid Build Coastguard Worker { 423*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 424*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ReadString(ref span, ref state); 425*1b3f573fSAndroid Build Coastguard Worker } 426*1b3f573fSAndroid Build Coastguard Worker 427*1b3f573fSAndroid Build Coastguard Worker /// <summary> 428*1b3f573fSAndroid Build Coastguard Worker /// Reads an embedded message field value from the stream. 429*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadMessage(IMessage builder)430*1b3f573fSAndroid Build Coastguard Worker public void ReadMessage(IMessage builder) 431*1b3f573fSAndroid Build Coastguard Worker { 432*1b3f573fSAndroid Build Coastguard Worker // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalMergeFrom method), 433*1b3f573fSAndroid Build Coastguard Worker // what we're doing here works fine, but could be more efficient. 434*1b3f573fSAndroid Build Coastguard Worker // What happens is that we first initialize a ParseContext from the current coded input stream only to parse the length of the message, at which point 435*1b3f573fSAndroid Build Coastguard Worker // we will need to switch back again to CodedInputStream-based parsing (which involves copying and storing the state) to be able to 436*1b3f573fSAndroid Build Coastguard Worker // invoke the legacy MergeFrom(CodedInputStream) method. 437*1b3f573fSAndroid Build Coastguard Worker // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). 438*1b3f573fSAndroid Build Coastguard Worker ParseContext.Initialize(buffer.AsSpan(), ref state, out ParseContext ctx); 439*1b3f573fSAndroid Build Coastguard Worker try 440*1b3f573fSAndroid Build Coastguard Worker { 441*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.ReadMessage(ref ctx, builder); 442*1b3f573fSAndroid Build Coastguard Worker } 443*1b3f573fSAndroid Build Coastguard Worker finally 444*1b3f573fSAndroid Build Coastguard Worker { 445*1b3f573fSAndroid Build Coastguard Worker ctx.CopyStateTo(this); 446*1b3f573fSAndroid Build Coastguard Worker } 447*1b3f573fSAndroid Build Coastguard Worker } 448*1b3f573fSAndroid Build Coastguard Worker 449*1b3f573fSAndroid Build Coastguard Worker /// <summary> 450*1b3f573fSAndroid Build Coastguard Worker /// Reads an embedded group field from the stream. 451*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadGroup(IMessage builder)452*1b3f573fSAndroid Build Coastguard Worker public void ReadGroup(IMessage builder) 453*1b3f573fSAndroid Build Coastguard Worker { 454*1b3f573fSAndroid Build Coastguard Worker ParseContext.Initialize(this, out ParseContext ctx); 455*1b3f573fSAndroid Build Coastguard Worker try 456*1b3f573fSAndroid Build Coastguard Worker { 457*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.ReadGroup(ref ctx, builder); 458*1b3f573fSAndroid Build Coastguard Worker } 459*1b3f573fSAndroid Build Coastguard Worker finally 460*1b3f573fSAndroid Build Coastguard Worker { 461*1b3f573fSAndroid Build Coastguard Worker ctx.CopyStateTo(this); 462*1b3f573fSAndroid Build Coastguard Worker } 463*1b3f573fSAndroid Build Coastguard Worker } 464*1b3f573fSAndroid Build Coastguard Worker 465*1b3f573fSAndroid Build Coastguard Worker /// <summary> 466*1b3f573fSAndroid Build Coastguard Worker /// Reads a bytes field value from the stream. 467*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadBytes()468*1b3f573fSAndroid Build Coastguard Worker public ByteString ReadBytes() 469*1b3f573fSAndroid Build Coastguard Worker { 470*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 471*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ReadBytes(ref span, ref state); 472*1b3f573fSAndroid Build Coastguard Worker } 473*1b3f573fSAndroid Build Coastguard Worker 474*1b3f573fSAndroid Build Coastguard Worker /// <summary> 475*1b3f573fSAndroid Build Coastguard Worker /// Reads a uint32 field value from the stream. 476*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadUInt32()477*1b3f573fSAndroid Build Coastguard Worker public uint ReadUInt32() 478*1b3f573fSAndroid Build Coastguard Worker { 479*1b3f573fSAndroid Build Coastguard Worker return ReadRawVarint32(); 480*1b3f573fSAndroid Build Coastguard Worker } 481*1b3f573fSAndroid Build Coastguard Worker 482*1b3f573fSAndroid Build Coastguard Worker /// <summary> 483*1b3f573fSAndroid Build Coastguard Worker /// Reads an enum field value from the stream. 484*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadEnum()485*1b3f573fSAndroid Build Coastguard Worker public int ReadEnum() 486*1b3f573fSAndroid Build Coastguard Worker { 487*1b3f573fSAndroid Build Coastguard Worker // Currently just a pass-through, but it's nice to separate it logically from WriteInt32. 488*1b3f573fSAndroid Build Coastguard Worker return (int) ReadRawVarint32(); 489*1b3f573fSAndroid Build Coastguard Worker } 490*1b3f573fSAndroid Build Coastguard Worker 491*1b3f573fSAndroid Build Coastguard Worker /// <summary> 492*1b3f573fSAndroid Build Coastguard Worker /// Reads an sfixed32 field value from the stream. 493*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadSFixed32()494*1b3f573fSAndroid Build Coastguard Worker public int ReadSFixed32() 495*1b3f573fSAndroid Build Coastguard Worker { 496*1b3f573fSAndroid Build Coastguard Worker return (int) ReadRawLittleEndian32(); 497*1b3f573fSAndroid Build Coastguard Worker } 498*1b3f573fSAndroid Build Coastguard Worker 499*1b3f573fSAndroid Build Coastguard Worker /// <summary> 500*1b3f573fSAndroid Build Coastguard Worker /// Reads an sfixed64 field value from the stream. 501*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadSFixed64()502*1b3f573fSAndroid Build Coastguard Worker public long ReadSFixed64() 503*1b3f573fSAndroid Build Coastguard Worker { 504*1b3f573fSAndroid Build Coastguard Worker return (long) ReadRawLittleEndian64(); 505*1b3f573fSAndroid Build Coastguard Worker } 506*1b3f573fSAndroid Build Coastguard Worker 507*1b3f573fSAndroid Build Coastguard Worker /// <summary> 508*1b3f573fSAndroid Build Coastguard Worker /// Reads an sint32 field value from the stream. 509*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadSInt32()510*1b3f573fSAndroid Build Coastguard Worker public int ReadSInt32() 511*1b3f573fSAndroid Build Coastguard Worker { 512*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.DecodeZigZag32(ReadRawVarint32()); 513*1b3f573fSAndroid Build Coastguard Worker } 514*1b3f573fSAndroid Build Coastguard Worker 515*1b3f573fSAndroid Build Coastguard Worker /// <summary> 516*1b3f573fSAndroid Build Coastguard Worker /// Reads an sint64 field value from the stream. 517*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadSInt64()518*1b3f573fSAndroid Build Coastguard Worker public long ReadSInt64() 519*1b3f573fSAndroid Build Coastguard Worker { 520*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.DecodeZigZag64(ReadRawVarint64()); 521*1b3f573fSAndroid Build Coastguard Worker } 522*1b3f573fSAndroid Build Coastguard Worker 523*1b3f573fSAndroid Build Coastguard Worker /// <summary> 524*1b3f573fSAndroid Build Coastguard Worker /// Reads a length for length-delimited data. 525*1b3f573fSAndroid Build Coastguard Worker /// </summary> 526*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 527*1b3f573fSAndroid Build Coastguard Worker /// This is internally just reading a varint, but this method exists 528*1b3f573fSAndroid Build Coastguard Worker /// to make the calling code clearer. 529*1b3f573fSAndroid Build Coastguard Worker /// </remarks> ReadLength()530*1b3f573fSAndroid Build Coastguard Worker public int ReadLength() 531*1b3f573fSAndroid Build Coastguard Worker { 532*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 533*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseLength(ref span, ref state); 534*1b3f573fSAndroid Build Coastguard Worker } 535*1b3f573fSAndroid Build Coastguard Worker 536*1b3f573fSAndroid Build Coastguard Worker /// <summary> 537*1b3f573fSAndroid Build Coastguard Worker /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>, 538*1b3f573fSAndroid Build Coastguard Worker /// the tag is consumed and the method returns <c>true</c>; otherwise, the 539*1b3f573fSAndroid Build Coastguard Worker /// stream is left in the original position and the method returns <c>false</c>. 540*1b3f573fSAndroid Build Coastguard Worker /// </summary> MaybeConsumeTag(uint tag)541*1b3f573fSAndroid Build Coastguard Worker public bool MaybeConsumeTag(uint tag) 542*1b3f573fSAndroid Build Coastguard Worker { 543*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 544*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.MaybeConsumeTag(ref span, ref state, tag); 545*1b3f573fSAndroid Build Coastguard Worker } 546*1b3f573fSAndroid Build Coastguard Worker 547*1b3f573fSAndroid Build Coastguard Worker #endregion 548*1b3f573fSAndroid Build Coastguard Worker 549*1b3f573fSAndroid Build Coastguard Worker #region Underlying reading primitives 550*1b3f573fSAndroid Build Coastguard Worker 551*1b3f573fSAndroid Build Coastguard Worker /// <summary> 552*1b3f573fSAndroid Build Coastguard Worker /// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits. 553*1b3f573fSAndroid Build Coastguard Worker /// This method is optimised for the case where we've got lots of data in the buffer. 554*1b3f573fSAndroid Build Coastguard Worker /// That means we can check the size just once, then just read directly from the buffer 555*1b3f573fSAndroid Build Coastguard Worker /// without constant rechecking of the buffer length. 556*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadRawVarint32()557*1b3f573fSAndroid Build Coastguard Worker internal uint ReadRawVarint32() 558*1b3f573fSAndroid Build Coastguard Worker { 559*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 560*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseRawVarint32(ref span, ref state); 561*1b3f573fSAndroid Build Coastguard Worker } 562*1b3f573fSAndroid Build Coastguard Worker 563*1b3f573fSAndroid Build Coastguard Worker /// <summary> 564*1b3f573fSAndroid Build Coastguard Worker /// Reads a varint from the input one byte at a time, so that it does not 565*1b3f573fSAndroid Build Coastguard Worker /// read any bytes after the end of the varint. If you simply wrapped the 566*1b3f573fSAndroid Build Coastguard Worker /// stream in a CodedInputStream and used ReadRawVarint32(Stream) 567*1b3f573fSAndroid Build Coastguard Worker /// then you would probably end up reading past the end of the varint since 568*1b3f573fSAndroid Build Coastguard Worker /// CodedInputStream buffers its input. 569*1b3f573fSAndroid Build Coastguard Worker /// </summary> 570*1b3f573fSAndroid Build Coastguard Worker /// <param name="input"></param> 571*1b3f573fSAndroid Build Coastguard Worker /// <returns></returns> ReadRawVarint32(Stream input)572*1b3f573fSAndroid Build Coastguard Worker internal static uint ReadRawVarint32(Stream input) 573*1b3f573fSAndroid Build Coastguard Worker { 574*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ReadRawVarint32(input); 575*1b3f573fSAndroid Build Coastguard Worker } 576*1b3f573fSAndroid Build Coastguard Worker 577*1b3f573fSAndroid Build Coastguard Worker /// <summary> 578*1b3f573fSAndroid Build Coastguard Worker /// Reads a raw varint from the stream. 579*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadRawVarint64()580*1b3f573fSAndroid Build Coastguard Worker internal ulong ReadRawVarint64() 581*1b3f573fSAndroid Build Coastguard Worker { 582*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 583*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseRawVarint64(ref span, ref state); 584*1b3f573fSAndroid Build Coastguard Worker } 585*1b3f573fSAndroid Build Coastguard Worker 586*1b3f573fSAndroid Build Coastguard Worker /// <summary> 587*1b3f573fSAndroid Build Coastguard Worker /// Reads a 32-bit little-endian integer from the stream. 588*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadRawLittleEndian32()589*1b3f573fSAndroid Build Coastguard Worker internal uint ReadRawLittleEndian32() 590*1b3f573fSAndroid Build Coastguard Worker { 591*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 592*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseRawLittleEndian32(ref span, ref state); 593*1b3f573fSAndroid Build Coastguard Worker } 594*1b3f573fSAndroid Build Coastguard Worker 595*1b3f573fSAndroid Build Coastguard Worker /// <summary> 596*1b3f573fSAndroid Build Coastguard Worker /// Reads a 64-bit little-endian integer from the stream. 597*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadRawLittleEndian64()598*1b3f573fSAndroid Build Coastguard Worker internal ulong ReadRawLittleEndian64() 599*1b3f573fSAndroid Build Coastguard Worker { 600*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 601*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ParseRawLittleEndian64(ref span, ref state); 602*1b3f573fSAndroid Build Coastguard Worker } 603*1b3f573fSAndroid Build Coastguard Worker #endregion 604*1b3f573fSAndroid Build Coastguard Worker 605*1b3f573fSAndroid Build Coastguard Worker #region Internal reading and buffer management 606*1b3f573fSAndroid Build Coastguard Worker 607*1b3f573fSAndroid Build Coastguard Worker /// <summary> 608*1b3f573fSAndroid Build Coastguard Worker /// Sets currentLimit to (current position) + byteLimit. This is called 609*1b3f573fSAndroid Build Coastguard Worker /// when descending into a length-delimited embedded message. The previous 610*1b3f573fSAndroid Build Coastguard Worker /// limit is returned. 611*1b3f573fSAndroid Build Coastguard Worker /// </summary> 612*1b3f573fSAndroid Build Coastguard Worker /// <returns>The old limit.</returns> PushLimit(int byteLimit)613*1b3f573fSAndroid Build Coastguard Worker internal int PushLimit(int byteLimit) 614*1b3f573fSAndroid Build Coastguard Worker { 615*1b3f573fSAndroid Build Coastguard Worker return SegmentedBufferHelper.PushLimit(ref state, byteLimit); 616*1b3f573fSAndroid Build Coastguard Worker } 617*1b3f573fSAndroid Build Coastguard Worker 618*1b3f573fSAndroid Build Coastguard Worker /// <summary> 619*1b3f573fSAndroid Build Coastguard Worker /// Discards the current limit, returning the previous limit. 620*1b3f573fSAndroid Build Coastguard Worker /// </summary> PopLimit(int oldLimit)621*1b3f573fSAndroid Build Coastguard Worker internal void PopLimit(int oldLimit) 622*1b3f573fSAndroid Build Coastguard Worker { 623*1b3f573fSAndroid Build Coastguard Worker SegmentedBufferHelper.PopLimit(ref state, oldLimit); 624*1b3f573fSAndroid Build Coastguard Worker } 625*1b3f573fSAndroid Build Coastguard Worker 626*1b3f573fSAndroid Build Coastguard Worker /// <summary> 627*1b3f573fSAndroid Build Coastguard Worker /// Returns whether or not all the data before the limit has been read. 628*1b3f573fSAndroid Build Coastguard Worker /// </summary> 629*1b3f573fSAndroid Build Coastguard Worker /// <returns></returns> 630*1b3f573fSAndroid Build Coastguard Worker internal bool ReachedLimit 631*1b3f573fSAndroid Build Coastguard Worker { 632*1b3f573fSAndroid Build Coastguard Worker get 633*1b3f573fSAndroid Build Coastguard Worker { 634*1b3f573fSAndroid Build Coastguard Worker return SegmentedBufferHelper.IsReachedLimit(ref state); 635*1b3f573fSAndroid Build Coastguard Worker } 636*1b3f573fSAndroid Build Coastguard Worker } 637*1b3f573fSAndroid Build Coastguard Worker 638*1b3f573fSAndroid Build Coastguard Worker /// <summary> 639*1b3f573fSAndroid Build Coastguard Worker /// Returns true if the stream has reached the end of the input. This is the 640*1b3f573fSAndroid Build Coastguard Worker /// case if either the end of the underlying input source has been reached or 641*1b3f573fSAndroid Build Coastguard Worker /// the stream has reached a limit created using PushLimit. 642*1b3f573fSAndroid Build Coastguard Worker /// </summary> 643*1b3f573fSAndroid Build Coastguard Worker public bool IsAtEnd 644*1b3f573fSAndroid Build Coastguard Worker { 645*1b3f573fSAndroid Build Coastguard Worker get 646*1b3f573fSAndroid Build Coastguard Worker { 647*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 648*1b3f573fSAndroid Build Coastguard Worker return SegmentedBufferHelper.IsAtEnd(ref span, ref state); 649*1b3f573fSAndroid Build Coastguard Worker } 650*1b3f573fSAndroid Build Coastguard Worker } 651*1b3f573fSAndroid Build Coastguard Worker 652*1b3f573fSAndroid Build Coastguard Worker /// <summary> 653*1b3f573fSAndroid Build Coastguard Worker /// Called when buffer is empty to read more bytes from the 654*1b3f573fSAndroid Build Coastguard Worker /// input. If <paramref name="mustSucceed"/> is true, RefillBuffer() guarantees that 655*1b3f573fSAndroid Build Coastguard Worker /// either there will be at least one byte in the buffer when it returns 656*1b3f573fSAndroid Build Coastguard Worker /// or it will throw an exception. If <paramref name="mustSucceed"/> is false, 657*1b3f573fSAndroid Build Coastguard Worker /// RefillBuffer() returns false if no more bytes were available. 658*1b3f573fSAndroid Build Coastguard Worker /// </summary> 659*1b3f573fSAndroid Build Coastguard Worker /// <param name="mustSucceed"></param> 660*1b3f573fSAndroid Build Coastguard Worker /// <returns></returns> RefillBuffer(bool mustSucceed)661*1b3f573fSAndroid Build Coastguard Worker private bool RefillBuffer(bool mustSucceed) 662*1b3f573fSAndroid Build Coastguard Worker { 663*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 664*1b3f573fSAndroid Build Coastguard Worker return state.segmentedBufferHelper.RefillBuffer(ref span, ref state, mustSucceed); 665*1b3f573fSAndroid Build Coastguard Worker } 666*1b3f573fSAndroid Build Coastguard Worker 667*1b3f573fSAndroid Build Coastguard Worker /// <summary> 668*1b3f573fSAndroid Build Coastguard Worker /// Reads a fixed size of bytes from the input. 669*1b3f573fSAndroid Build Coastguard Worker /// </summary> 670*1b3f573fSAndroid Build Coastguard Worker /// <exception cref="InvalidProtocolBufferException"> 671*1b3f573fSAndroid Build Coastguard Worker /// the end of the stream or the current limit was reached 672*1b3f573fSAndroid Build Coastguard Worker /// </exception> ReadRawBytes(int size)673*1b3f573fSAndroid Build Coastguard Worker internal byte[] ReadRawBytes(int size) 674*1b3f573fSAndroid Build Coastguard Worker { 675*1b3f573fSAndroid Build Coastguard Worker var span = new ReadOnlySpan<byte>(buffer); 676*1b3f573fSAndroid Build Coastguard Worker return ParsingPrimitives.ReadRawBytes(ref span, ref state, size); 677*1b3f573fSAndroid Build Coastguard Worker } 678*1b3f573fSAndroid Build Coastguard Worker 679*1b3f573fSAndroid Build Coastguard Worker /// <summary> 680*1b3f573fSAndroid Build Coastguard Worker /// Reads a top-level message or a nested message after the limits for this message have been pushed. 681*1b3f573fSAndroid Build Coastguard Worker /// (parser will proceed until the end of the current limit) 682*1b3f573fSAndroid Build Coastguard Worker /// NOTE: this method needs to be public because it's invoked by the generated code - e.g. msg.MergeFrom(CodedInputStream input) method 683*1b3f573fSAndroid Build Coastguard Worker /// </summary> ReadRawMessage(IMessage message)684*1b3f573fSAndroid Build Coastguard Worker public void ReadRawMessage(IMessage message) 685*1b3f573fSAndroid Build Coastguard Worker { 686*1b3f573fSAndroid Build Coastguard Worker ParseContext.Initialize(this, out ParseContext ctx); 687*1b3f573fSAndroid Build Coastguard Worker try 688*1b3f573fSAndroid Build Coastguard Worker { 689*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message); 690*1b3f573fSAndroid Build Coastguard Worker } 691*1b3f573fSAndroid Build Coastguard Worker finally 692*1b3f573fSAndroid Build Coastguard Worker { 693*1b3f573fSAndroid Build Coastguard Worker ctx.CopyStateTo(this); 694*1b3f573fSAndroid Build Coastguard Worker } 695*1b3f573fSAndroid Build Coastguard Worker } 696*1b3f573fSAndroid Build Coastguard Worker #endregion 697*1b3f573fSAndroid Build Coastguard Worker } 698*1b3f573fSAndroid Build Coastguard Worker } 699