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