xref: /aosp_15_r20/external/protobuf/csharp/src/Google.Protobuf/CodedInputStream.cs (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
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