CodedInputStream.cs 27 KB

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