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