CodedInputStream.cs 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  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. namespace Google.Protobuf
  37. {
  38. /// <summary>
  39. /// Reads and decodes protocol message fields.
  40. /// </summary>
  41. /// <remarks>
  42. /// <para>
  43. /// This class is generally used by generated code to read appropriate
  44. /// primitives from the stream. It effectively encapsulates the lowest
  45. /// levels of protocol buffer format.
  46. /// </para>
  47. /// <para>
  48. /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>
  49. /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.
  50. /// </para>
  51. /// </remarks>
  52. public sealed class CodedInputStream
  53. {
  54. /// <summary>
  55. /// Buffer of data read from the stream or provided at construction time.
  56. /// </summary>
  57. private readonly byte[] buffer;
  58. /// <summary>
  59. /// The index of the buffer at which we need to refill from the stream (if there is one).
  60. /// </summary>
  61. private int bufferSize;
  62. private int bufferSizeAfterLimit = 0;
  63. /// <summary>
  64. /// The position within the current buffer (i.e. the next byte to read)
  65. /// </summary>
  66. private int bufferPos = 0;
  67. /// <summary>
  68. /// The stream to read further input from, or null if the byte array buffer was provided
  69. /// directly on construction, with no further data available.
  70. /// </summary>
  71. private readonly Stream input;
  72. /// <summary>
  73. /// The last tag we read. 0 indicates we've read to the end of the stream
  74. /// (or haven't read anything yet).
  75. /// </summary>
  76. private uint lastTag = 0;
  77. /// <summary>
  78. /// The next tag, used to store the value read by PeekTag.
  79. /// </summary>
  80. private uint nextTag = 0;
  81. private bool hasNextTag = false;
  82. internal const int DefaultRecursionLimit = 64;
  83. internal const int DefaultSizeLimit = 64 << 20; // 64MB
  84. internal const int BufferSize = 4096;
  85. /// <summary>
  86. /// The total number of bytes read before the current buffer. The
  87. /// total bytes read up to the current position can be computed as
  88. /// totalBytesRetired + bufferPos.
  89. /// </summary>
  90. private int totalBytesRetired = 0;
  91. /// <summary>
  92. /// The absolute position of the end of the current message.
  93. /// </summary>
  94. private int currentLimit = int.MaxValue;
  95. private int recursionDepth = 0;
  96. private readonly int recursionLimit;
  97. private readonly int sizeLimit;
  98. #region Construction
  99. // Note that the checks are performed such that we don't end up checking obviously-valid things
  100. // like non-null references for arrays we've just created.
  101. /// <summary>
  102. /// Creates a new CodedInputStream reading data from the given byte array.
  103. /// </summary>
  104. public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)
  105. {
  106. }
  107. /// <summary>
  108. /// Creates a new CodedInputStream that reads from the given byte array slice.
  109. /// </summary>
  110. public CodedInputStream(byte[] buffer, int offset, int length)
  111. : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)
  112. {
  113. if (offset < 0 || offset > buffer.Length)
  114. {
  115. throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
  116. }
  117. if (length < 0 || offset + length > buffer.Length)
  118. {
  119. throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
  120. }
  121. }
  122. /// <summary>
  123. /// Creates a new CodedInputStream reading data from the given stream.
  124. /// </summary>
  125. public CodedInputStream(Stream input) : this(input, new byte[BufferSize], 0, 0)
  126. {
  127. ProtoPreconditions.CheckNotNull(input, "input");
  128. }
  129. /// <summary>
  130. /// Creates a new CodedInputStream reading data from the given
  131. /// stream and buffer, using the default limits.
  132. /// </summary>
  133. internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize)
  134. {
  135. this.input = input;
  136. this.buffer = buffer;
  137. this.bufferPos = bufferPos;
  138. this.bufferSize = bufferSize;
  139. this.sizeLimit = DefaultSizeLimit;
  140. this.recursionLimit = DefaultRecursionLimit;
  141. }
  142. /// <summary>
  143. /// Creates a new CodedInputStream reading data from the given
  144. /// stream and buffer, using the specified limits.
  145. /// </summary>
  146. /// <remarks>
  147. /// This chains to the version with the default limits instead of vice versa to avoid
  148. /// having to check that the default values are valid every time.
  149. /// </remarks>
  150. internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit)
  151. : this(input, buffer, bufferPos, bufferSize)
  152. {
  153. if (sizeLimit <= 0)
  154. {
  155. throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");
  156. }
  157. if (recursionLimit <= 0)
  158. {
  159. throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");
  160. }
  161. this.sizeLimit = sizeLimit;
  162. this.recursionLimit = recursionLimit;
  163. }
  164. #endregion
  165. /// <summary>
  166. /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading
  167. /// from an input stream.
  168. /// </summary>
  169. /// <remarks>
  170. /// This method exists separately from the constructor to reduce the number of constructor overloads.
  171. /// It is likely to be used considerably less frequently than the constructors, as the default limits
  172. /// are suitable for most use cases.
  173. /// </remarks>
  174. /// <param name="input">The input stream to read from</param>
  175. /// <param name="sizeLimit">The total limit of data to read from the stream.</param>
  176. /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>
  177. /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size
  178. /// and recursion limits.</returns>
  179. public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)
  180. {
  181. return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit);
  182. }
  183. /// <summary>
  184. /// Returns the current position in the input stream, or the position in the input buffer
  185. /// </summary>
  186. public long Position
  187. {
  188. get
  189. {
  190. if (input != null)
  191. {
  192. return input.Position - ((bufferSize + bufferSizeAfterLimit) - bufferPos);
  193. }
  194. return bufferPos;
  195. }
  196. }
  197. /// <summary>
  198. /// Returns the last tag read, or 0 if no tags have been read or we've read beyond
  199. /// the end of the stream.
  200. /// </summary>
  201. internal uint LastTag { get { return lastTag; } }
  202. /// <summary>
  203. /// Returns the size limit for this stream.
  204. /// </summary>
  205. /// <remarks>
  206. /// This limit is applied when reading from the underlying stream, as a sanity check. It is
  207. /// not applied when reading from a byte array data source without an underlying stream.
  208. /// The default value is 64MB.
  209. /// </remarks>
  210. /// <value>
  211. /// The size limit.
  212. /// </value>
  213. public int SizeLimit { get { return sizeLimit; } }
  214. /// <summary>
  215. /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,
  216. /// to avoid maliciously-recursive data.
  217. /// </summary>
  218. /// <remarks>
  219. /// The default limit is 64.
  220. /// </remarks>
  221. /// <value>
  222. /// The recursion limit for this stream.
  223. /// </value>
  224. public int RecursionLimit { get { return recursionLimit; } }
  225. #region Validation
  226. /// <summary>
  227. /// Verifies that the last call to ReadTag() returned tag 0 - in other words,
  228. /// we've reached the end of the stream when we expected to.
  229. /// </summary>
  230. /// <exception cref="InvalidProtocolBufferException">The
  231. /// tag read was not the one specified</exception>
  232. internal void CheckReadEndOfStreamTag()
  233. {
  234. if (lastTag != 0)
  235. {
  236. throw InvalidProtocolBufferException.MoreDataAvailable();
  237. }
  238. }
  239. #endregion
  240. #region Reading of tags etc
  241. /// <summary>
  242. /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the
  243. /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the
  244. /// same value.)
  245. /// </summary>
  246. public uint PeekTag()
  247. {
  248. if (hasNextTag)
  249. {
  250. return nextTag;
  251. }
  252. uint savedLast = lastTag;
  253. nextTag = ReadTag();
  254. hasNextTag = true;
  255. lastTag = savedLast; // Undo the side effect of ReadTag
  256. return nextTag;
  257. }
  258. /// <summary>
  259. /// Reads a field tag, returning the tag of 0 for "end of stream".
  260. /// </summary>
  261. /// <remarks>
  262. /// If this method returns 0, it doesn't necessarily mean the end of all
  263. /// the data in this CodedInputStream; it may be the end of the logical stream
  264. /// for an embedded message, for example.
  265. /// </remarks>
  266. /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>
  267. public uint ReadTag()
  268. {
  269. if (hasNextTag)
  270. {
  271. lastTag = nextTag;
  272. hasNextTag = false;
  273. return lastTag;
  274. }
  275. // Optimize for the incredibly common case of having at least two bytes left in the buffer,
  276. // and those two bytes being enough to get the tag. This will be true for fields up to 4095.
  277. if (bufferPos + 2 <= bufferSize)
  278. {
  279. int tmp = buffer[bufferPos++];
  280. if (tmp < 128)
  281. {
  282. lastTag = (uint)tmp;
  283. }
  284. else
  285. {
  286. int result = tmp & 0x7f;
  287. if ((tmp = buffer[bufferPos++]) < 128)
  288. {
  289. result |= tmp << 7;
  290. lastTag = (uint) result;
  291. }
  292. else
  293. {
  294. // Nope, rewind and go the potentially slow route.
  295. bufferPos -= 2;
  296. lastTag = ReadRawVarint32();
  297. }
  298. }
  299. }
  300. else
  301. {
  302. if (IsAtEnd)
  303. {
  304. lastTag = 0;
  305. return 0; // This is the only case in which we return 0.
  306. }
  307. lastTag = ReadRawVarint32();
  308. }
  309. if (lastTag == 0)
  310. {
  311. // If we actually read zero, that's not a valid tag.
  312. throw InvalidProtocolBufferException.InvalidTag();
  313. }
  314. return lastTag;
  315. }
  316. /// <summary>
  317. /// Skips the data for the field with the tag we've just read.
  318. /// This should be called directly after <see cref="ReadTag"/>, when
  319. /// the caller wishes to skip an unknown field.
  320. /// </summary>
  321. /// <remarks>
  322. /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.
  323. /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the
  324. /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly
  325. /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.
  326. /// </remarks>
  327. /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>
  328. /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>
  329. public void SkipLastField()
  330. {
  331. if (lastTag == 0)
  332. {
  333. throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");
  334. }
  335. switch (WireFormat.GetTagWireType(lastTag))
  336. {
  337. case WireFormat.WireType.StartGroup:
  338. SkipGroup(lastTag);
  339. break;
  340. case WireFormat.WireType.EndGroup:
  341. throw new InvalidProtocolBufferException(
  342. "SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing");
  343. case WireFormat.WireType.Fixed32:
  344. ReadFixed32();
  345. break;
  346. case WireFormat.WireType.Fixed64:
  347. ReadFixed64();
  348. break;
  349. case WireFormat.WireType.LengthDelimited:
  350. var length = ReadLength();
  351. SkipRawBytes(length);
  352. break;
  353. case WireFormat.WireType.Varint:
  354. ReadRawVarint32();
  355. break;
  356. }
  357. }
  358. private void SkipGroup(uint startGroupTag)
  359. {
  360. // Note: Currently we expect this to be the way that groups are read. We could put the recursion
  361. // depth changes into the ReadTag method instead, potentially...
  362. recursionDepth++;
  363. if (recursionDepth >= recursionLimit)
  364. {
  365. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  366. }
  367. uint tag;
  368. while (true)
  369. {
  370. tag = ReadTag();
  371. if (tag == 0)
  372. {
  373. throw InvalidProtocolBufferException.TruncatedMessage();
  374. }
  375. // Can't call SkipLastField for this case- that would throw.
  376. if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup)
  377. {
  378. break;
  379. }
  380. // This recursion will allow us to handle nested groups.
  381. SkipLastField();
  382. }
  383. int startField = WireFormat.GetTagFieldNumber(startGroupTag);
  384. int endField = WireFormat.GetTagFieldNumber(tag);
  385. if (startField != endField)
  386. {
  387. throw new InvalidProtocolBufferException(
  388. $"Mismatched end-group tag. Started with field {startField}; ended with field {endField}");
  389. }
  390. recursionDepth--;
  391. }
  392. /// <summary>
  393. /// Reads a double field from the stream.
  394. /// </summary>
  395. public double ReadDouble()
  396. {
  397. return BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
  398. }
  399. /// <summary>
  400. /// Reads a float field from the stream.
  401. /// </summary>
  402. public float ReadFloat()
  403. {
  404. if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)
  405. {
  406. float ret = BitConverter.ToSingle(buffer, bufferPos);
  407. bufferPos += 4;
  408. return ret;
  409. }
  410. else
  411. {
  412. byte[] rawBytes = ReadRawBytes(4);
  413. if (!BitConverter.IsLittleEndian)
  414. {
  415. ByteArray.Reverse(rawBytes);
  416. }
  417. return BitConverter.ToSingle(rawBytes, 0);
  418. }
  419. }
  420. /// <summary>
  421. /// Reads a uint64 field from the stream.
  422. /// </summary>
  423. public ulong ReadUInt64()
  424. {
  425. return ReadRawVarint64();
  426. }
  427. /// <summary>
  428. /// Reads an int64 field from the stream.
  429. /// </summary>
  430. public long ReadInt64()
  431. {
  432. return (long) ReadRawVarint64();
  433. }
  434. /// <summary>
  435. /// Reads an int32 field from the stream.
  436. /// </summary>
  437. public int ReadInt32()
  438. {
  439. return (int) ReadRawVarint32();
  440. }
  441. /// <summary>
  442. /// Reads a fixed64 field from the stream.
  443. /// </summary>
  444. public ulong ReadFixed64()
  445. {
  446. return ReadRawLittleEndian64();
  447. }
  448. /// <summary>
  449. /// Reads a fixed32 field from the stream.
  450. /// </summary>
  451. public uint ReadFixed32()
  452. {
  453. return ReadRawLittleEndian32();
  454. }
  455. /// <summary>
  456. /// Reads a bool field from the stream.
  457. /// </summary>
  458. public bool ReadBool()
  459. {
  460. return ReadRawVarint32() != 0;
  461. }
  462. /// <summary>
  463. /// Reads a string field from the stream.
  464. /// </summary>
  465. public string ReadString()
  466. {
  467. int length = ReadLength();
  468. // No need to read any data for an empty string.
  469. if (length == 0)
  470. {
  471. return "";
  472. }
  473. if (length <= bufferSize - bufferPos)
  474. {
  475. // Fast path: We already have the bytes in a contiguous buffer, so
  476. // just copy directly from it.
  477. String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);
  478. bufferPos += length;
  479. return result;
  480. }
  481. // Slow path: Build a byte array first then copy it.
  482. return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);
  483. }
  484. /// <summary>
  485. /// Reads an embedded message field value from the stream.
  486. /// </summary>
  487. public void ReadMessage(IMessage builder)
  488. {
  489. int length = ReadLength();
  490. if (recursionDepth >= recursionLimit)
  491. {
  492. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  493. }
  494. int oldLimit = PushLimit(length);
  495. ++recursionDepth;
  496. builder.MergeFrom(this);
  497. CheckReadEndOfStreamTag();
  498. // Check that we've read exactly as much data as expected.
  499. if (!ReachedLimit)
  500. {
  501. throw InvalidProtocolBufferException.TruncatedMessage();
  502. }
  503. --recursionDepth;
  504. PopLimit(oldLimit);
  505. }
  506. /// <summary>
  507. /// Reads a bytes field value from the stream.
  508. /// </summary>
  509. public ByteString ReadBytes()
  510. {
  511. int length = ReadLength();
  512. if (length <= bufferSize - bufferPos && length > 0)
  513. {
  514. // Fast path: We already have the bytes in a contiguous buffer, so
  515. // just copy directly from it.
  516. ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);
  517. bufferPos += length;
  518. return result;
  519. }
  520. else
  521. {
  522. // Slow path: Build a byte array and attach it to a new ByteString.
  523. return ByteString.AttachBytes(ReadRawBytes(length));
  524. }
  525. }
  526. /// <summary>
  527. /// Reads a uint32 field value from the stream.
  528. /// </summary>
  529. public uint ReadUInt32()
  530. {
  531. return ReadRawVarint32();
  532. }
  533. /// <summary>
  534. /// Reads an enum field value from the stream. If the enum is valid for type T,
  535. /// then the ref value is set and it returns true. Otherwise the unknown output
  536. /// value is set and this method returns false.
  537. /// </summary>
  538. public int ReadEnum()
  539. {
  540. // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
  541. return (int) ReadRawVarint32();
  542. }
  543. /// <summary>
  544. /// Reads an sfixed32 field value from the stream.
  545. /// </summary>
  546. public int ReadSFixed32()
  547. {
  548. return (int) ReadRawLittleEndian32();
  549. }
  550. /// <summary>
  551. /// Reads an sfixed64 field value from the stream.
  552. /// </summary>
  553. public long ReadSFixed64()
  554. {
  555. return (long) ReadRawLittleEndian64();
  556. }
  557. /// <summary>
  558. /// Reads an sint32 field value from the stream.
  559. /// </summary>
  560. public int ReadSInt32()
  561. {
  562. return DecodeZigZag32(ReadRawVarint32());
  563. }
  564. /// <summary>
  565. /// Reads an sint64 field value from the stream.
  566. /// </summary>
  567. public long ReadSInt64()
  568. {
  569. return DecodeZigZag64(ReadRawVarint64());
  570. }
  571. /// <summary>
  572. /// Reads a length for length-delimited data.
  573. /// </summary>
  574. /// <remarks>
  575. /// This is internally just reading a varint, but this method exists
  576. /// to make the calling code clearer.
  577. /// </remarks>
  578. public int ReadLength()
  579. {
  580. return (int) ReadRawVarint32();
  581. }
  582. /// <summary>
  583. /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
  584. /// the tag is consumed and the method returns <c>true</c>; otherwise, the
  585. /// stream is left in the original position and the method returns <c>false</c>.
  586. /// </summary>
  587. public bool MaybeConsumeTag(uint tag)
  588. {
  589. if (PeekTag() == tag)
  590. {
  591. hasNextTag = false;
  592. return true;
  593. }
  594. return false;
  595. }
  596. #endregion
  597. #region Underlying reading primitives
  598. /// <summary>
  599. /// Same code as ReadRawVarint32, but read each byte individually, checking for
  600. /// buffer overflow.
  601. /// </summary>
  602. private uint SlowReadRawVarint32()
  603. {
  604. int tmp = ReadRawByte();
  605. if (tmp < 128)
  606. {
  607. return (uint) tmp;
  608. }
  609. int result = tmp & 0x7f;
  610. if ((tmp = ReadRawByte()) < 128)
  611. {
  612. result |= tmp << 7;
  613. }
  614. else
  615. {
  616. result |= (tmp & 0x7f) << 7;
  617. if ((tmp = ReadRawByte()) < 128)
  618. {
  619. result |= tmp << 14;
  620. }
  621. else
  622. {
  623. result |= (tmp & 0x7f) << 14;
  624. if ((tmp = ReadRawByte()) < 128)
  625. {
  626. result |= tmp << 21;
  627. }
  628. else
  629. {
  630. result |= (tmp & 0x7f) << 21;
  631. result |= (tmp = ReadRawByte()) << 28;
  632. if (tmp >= 128)
  633. {
  634. // Discard upper 32 bits.
  635. for (int i = 0; i < 5; i++)
  636. {
  637. if (ReadRawByte() < 128)
  638. {
  639. return (uint) result;
  640. }
  641. }
  642. throw InvalidProtocolBufferException.MalformedVarint();
  643. }
  644. }
  645. }
  646. }
  647. return (uint) result;
  648. }
  649. /// <summary>
  650. /// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits.
  651. /// This method is optimised for the case where we've got lots of data in the buffer.
  652. /// That means we can check the size just once, then just read directly from the buffer
  653. /// without constant rechecking of the buffer length.
  654. /// </summary>
  655. internal uint ReadRawVarint32()
  656. {
  657. if (bufferPos + 5 > bufferSize)
  658. {
  659. return SlowReadRawVarint32();
  660. }
  661. int tmp = buffer[bufferPos++];
  662. if (tmp < 128)
  663. {
  664. return (uint) tmp;
  665. }
  666. int result = tmp & 0x7f;
  667. if ((tmp = buffer[bufferPos++]) < 128)
  668. {
  669. result |= tmp << 7;
  670. }
  671. else
  672. {
  673. result |= (tmp & 0x7f) << 7;
  674. if ((tmp = buffer[bufferPos++]) < 128)
  675. {
  676. result |= tmp << 14;
  677. }
  678. else
  679. {
  680. result |= (tmp & 0x7f) << 14;
  681. if ((tmp = buffer[bufferPos++]) < 128)
  682. {
  683. result |= tmp << 21;
  684. }
  685. else
  686. {
  687. result |= (tmp & 0x7f) << 21;
  688. result |= (tmp = buffer[bufferPos++]) << 28;
  689. if (tmp >= 128)
  690. {
  691. // Discard upper 32 bits.
  692. // Note that this has to use ReadRawByte() as we only ensure we've
  693. // got at least 5 bytes at the start of the method. This lets us
  694. // use the fast path in more cases, and we rarely hit this section of code.
  695. for (int i = 0; i < 5; i++)
  696. {
  697. if (ReadRawByte() < 128)
  698. {
  699. return (uint) result;
  700. }
  701. }
  702. throw InvalidProtocolBufferException.MalformedVarint();
  703. }
  704. }
  705. }
  706. }
  707. return (uint) result;
  708. }
  709. /// <summary>
  710. /// Reads a varint from the input one byte at a time, so that it does not
  711. /// read any bytes after the end of the varint. If you simply wrapped the
  712. /// stream in a CodedInputStream and used ReadRawVarint32(Stream)
  713. /// then you would probably end up reading past the end of the varint since
  714. /// CodedInputStream buffers its input.
  715. /// </summary>
  716. /// <param name="input"></param>
  717. /// <returns></returns>
  718. internal static uint ReadRawVarint32(Stream input)
  719. {
  720. int result = 0;
  721. int offset = 0;
  722. for (; offset < 32; offset += 7)
  723. {
  724. int b = input.ReadByte();
  725. if (b == -1)
  726. {
  727. throw InvalidProtocolBufferException.TruncatedMessage();
  728. }
  729. result |= (b & 0x7f) << offset;
  730. if ((b & 0x80) == 0)
  731. {
  732. return (uint) result;
  733. }
  734. }
  735. // Keep reading up to 64 bits.
  736. for (; offset < 64; offset += 7)
  737. {
  738. int b = input.ReadByte();
  739. if (b == -1)
  740. {
  741. throw InvalidProtocolBufferException.TruncatedMessage();
  742. }
  743. if ((b & 0x80) == 0)
  744. {
  745. return (uint) result;
  746. }
  747. }
  748. throw InvalidProtocolBufferException.MalformedVarint();
  749. }
  750. /// <summary>
  751. /// Reads a raw varint from the stream.
  752. /// </summary>
  753. internal ulong ReadRawVarint64()
  754. {
  755. int shift = 0;
  756. ulong result = 0;
  757. while (shift < 64)
  758. {
  759. byte b = ReadRawByte();
  760. result |= (ulong) (b & 0x7F) << shift;
  761. if ((b & 0x80) == 0)
  762. {
  763. return result;
  764. }
  765. shift += 7;
  766. }
  767. throw InvalidProtocolBufferException.MalformedVarint();
  768. }
  769. /// <summary>
  770. /// Reads a 32-bit little-endian integer from the stream.
  771. /// </summary>
  772. internal uint ReadRawLittleEndian32()
  773. {
  774. uint b1 = ReadRawByte();
  775. uint b2 = ReadRawByte();
  776. uint b3 = ReadRawByte();
  777. uint b4 = ReadRawByte();
  778. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
  779. }
  780. /// <summary>
  781. /// Reads a 64-bit little-endian integer from the stream.
  782. /// </summary>
  783. internal ulong ReadRawLittleEndian64()
  784. {
  785. ulong b1 = ReadRawByte();
  786. ulong b2 = ReadRawByte();
  787. ulong b3 = ReadRawByte();
  788. ulong b4 = ReadRawByte();
  789. ulong b5 = ReadRawByte();
  790. ulong b6 = ReadRawByte();
  791. ulong b7 = ReadRawByte();
  792. ulong b8 = ReadRawByte();
  793. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
  794. | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
  795. }
  796. /// <summary>
  797. /// Decode a 32-bit value with ZigZag encoding.
  798. /// </summary>
  799. /// <remarks>
  800. /// ZigZag encodes signed integers into values that can be efficiently
  801. /// encoded with varint. (Otherwise, negative values must be
  802. /// sign-extended to 64 bits to be varint encoded, thus always taking
  803. /// 10 bytes on the wire.)
  804. /// </remarks>
  805. internal static int DecodeZigZag32(uint n)
  806. {
  807. return (int)(n >> 1) ^ -(int)(n & 1);
  808. }
  809. /// <summary>
  810. /// Decode a 32-bit value with ZigZag encoding.
  811. /// </summary>
  812. /// <remarks>
  813. /// ZigZag encodes signed integers into values that can be efficiently
  814. /// encoded with varint. (Otherwise, negative values must be
  815. /// sign-extended to 64 bits to be varint encoded, thus always taking
  816. /// 10 bytes on the wire.)
  817. /// </remarks>
  818. internal static long DecodeZigZag64(ulong n)
  819. {
  820. return (long)(n >> 1) ^ -(long)(n & 1);
  821. }
  822. #endregion
  823. #region Internal reading and buffer management
  824. /// <summary>
  825. /// Sets currentLimit to (current position) + byteLimit. This is called
  826. /// when descending into a length-delimited embedded message. The previous
  827. /// limit is returned.
  828. /// </summary>
  829. /// <returns>The old limit.</returns>
  830. internal int PushLimit(int byteLimit)
  831. {
  832. if (byteLimit < 0)
  833. {
  834. throw InvalidProtocolBufferException.NegativeSize();
  835. }
  836. byteLimit += totalBytesRetired + bufferPos;
  837. int oldLimit = currentLimit;
  838. if (byteLimit > oldLimit)
  839. {
  840. throw InvalidProtocolBufferException.TruncatedMessage();
  841. }
  842. currentLimit = byteLimit;
  843. RecomputeBufferSizeAfterLimit();
  844. return oldLimit;
  845. }
  846. private void RecomputeBufferSizeAfterLimit()
  847. {
  848. bufferSize += bufferSizeAfterLimit;
  849. int bufferEnd = totalBytesRetired + bufferSize;
  850. if (bufferEnd > currentLimit)
  851. {
  852. // Limit is in current buffer.
  853. bufferSizeAfterLimit = bufferEnd - currentLimit;
  854. bufferSize -= bufferSizeAfterLimit;
  855. }
  856. else
  857. {
  858. bufferSizeAfterLimit = 0;
  859. }
  860. }
  861. /// <summary>
  862. /// Discards the current limit, returning the previous limit.
  863. /// </summary>
  864. internal void PopLimit(int oldLimit)
  865. {
  866. currentLimit = oldLimit;
  867. RecomputeBufferSizeAfterLimit();
  868. }
  869. /// <summary>
  870. /// Returns whether or not all the data before the limit has been read.
  871. /// </summary>
  872. /// <returns></returns>
  873. internal bool ReachedLimit
  874. {
  875. get
  876. {
  877. if (currentLimit == int.MaxValue)
  878. {
  879. return false;
  880. }
  881. int currentAbsolutePosition = totalBytesRetired + bufferPos;
  882. return currentAbsolutePosition >= currentLimit;
  883. }
  884. }
  885. /// <summary>
  886. /// Returns true if the stream has reached the end of the input. This is the
  887. /// case if either the end of the underlying input source has been reached or
  888. /// the stream has reached a limit created using PushLimit.
  889. /// </summary>
  890. public bool IsAtEnd
  891. {
  892. get { return bufferPos == bufferSize && !RefillBuffer(false); }
  893. }
  894. /// <summary>
  895. /// Called when buffer is empty to read more bytes from the
  896. /// input. If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that
  897. /// either there will be at least one byte in the buffer when it returns
  898. /// or it will throw an exception. If <paramref name="mustSucceed"/> is false,
  899. /// RefillBuffer() returns false if no more bytes were available.
  900. /// </summary>
  901. /// <param name="mustSucceed"></param>
  902. /// <returns></returns>
  903. private bool RefillBuffer(bool mustSucceed)
  904. {
  905. if (bufferPos < bufferSize)
  906. {
  907. throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");
  908. }
  909. if (totalBytesRetired + bufferSize == currentLimit)
  910. {
  911. // Oops, we hit a limit.
  912. if (mustSucceed)
  913. {
  914. throw InvalidProtocolBufferException.TruncatedMessage();
  915. }
  916. else
  917. {
  918. return false;
  919. }
  920. }
  921. totalBytesRetired += bufferSize;
  922. bufferPos = 0;
  923. bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);
  924. if (bufferSize < 0)
  925. {
  926. throw new InvalidOperationException("Stream.Read returned a negative count");
  927. }
  928. if (bufferSize == 0)
  929. {
  930. if (mustSucceed)
  931. {
  932. throw InvalidProtocolBufferException.TruncatedMessage();
  933. }
  934. else
  935. {
  936. return false;
  937. }
  938. }
  939. else
  940. {
  941. RecomputeBufferSizeAfterLimit();
  942. int totalBytesRead =
  943. totalBytesRetired + bufferSize + bufferSizeAfterLimit;
  944. if (totalBytesRead > sizeLimit || totalBytesRead < 0)
  945. {
  946. throw InvalidProtocolBufferException.SizeLimitExceeded();
  947. }
  948. return true;
  949. }
  950. }
  951. /// <summary>
  952. /// Read one byte from the input.
  953. /// </summary>
  954. /// <exception cref="InvalidProtocolBufferException">
  955. /// the end of the stream or the current limit was reached
  956. /// </exception>
  957. internal byte ReadRawByte()
  958. {
  959. if (bufferPos == bufferSize)
  960. {
  961. RefillBuffer(true);
  962. }
  963. return buffer[bufferPos++];
  964. }
  965. /// <summary>
  966. /// Reads a fixed size of bytes from the input.
  967. /// </summary>
  968. /// <exception cref="InvalidProtocolBufferException">
  969. /// the end of the stream or the current limit was reached
  970. /// </exception>
  971. internal byte[] ReadRawBytes(int size)
  972. {
  973. if (size < 0)
  974. {
  975. throw InvalidProtocolBufferException.NegativeSize();
  976. }
  977. if (totalBytesRetired + bufferPos + size > currentLimit)
  978. {
  979. // Read to the end of the stream (up to the current limit) anyway.
  980. SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
  981. // Then fail.
  982. throw InvalidProtocolBufferException.TruncatedMessage();
  983. }
  984. if (size <= bufferSize - bufferPos)
  985. {
  986. // We have all the bytes we need already.
  987. byte[] bytes = new byte[size];
  988. ByteArray.Copy(buffer, bufferPos, bytes, 0, size);
  989. bufferPos += size;
  990. return bytes;
  991. }
  992. else if (size < buffer.Length)
  993. {
  994. // Reading more bytes than are in the buffer, but not an excessive number
  995. // of bytes. We can safely allocate the resulting array ahead of time.
  996. // First copy what we have.
  997. byte[] bytes = new byte[size];
  998. int pos = bufferSize - bufferPos;
  999. ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);
  1000. bufferPos = bufferSize;
  1001. // We want to use RefillBuffer() and then copy from the buffer into our
  1002. // byte array rather than reading directly into our byte array because
  1003. // the input may be unbuffered.
  1004. RefillBuffer(true);
  1005. while (size - pos > bufferSize)
  1006. {
  1007. Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);
  1008. pos += bufferSize;
  1009. bufferPos = bufferSize;
  1010. RefillBuffer(true);
  1011. }
  1012. ByteArray.Copy(buffer, 0, bytes, pos, size - pos);
  1013. bufferPos = size - pos;
  1014. return bytes;
  1015. }
  1016. else
  1017. {
  1018. // The size is very large. For security reasons, we can't allocate the
  1019. // entire byte array yet. The size comes directly from the input, so a
  1020. // maliciously-crafted message could provide a bogus very large size in
  1021. // order to trick the app into allocating a lot of memory. We avoid this
  1022. // by allocating and reading only a small chunk at a time, so that the
  1023. // malicious message must actually *be* extremely large to cause
  1024. // problems. Meanwhile, we limit the allowed size of a message elsewhere.
  1025. // Remember the buffer markers since we'll have to copy the bytes out of
  1026. // it later.
  1027. int originalBufferPos = bufferPos;
  1028. int originalBufferSize = bufferSize;
  1029. // Mark the current buffer consumed.
  1030. totalBytesRetired += bufferSize;
  1031. bufferPos = 0;
  1032. bufferSize = 0;
  1033. // Read all the rest of the bytes we need.
  1034. int sizeLeft = size - (originalBufferSize - originalBufferPos);
  1035. List<byte[]> chunks = new List<byte[]>();
  1036. while (sizeLeft > 0)
  1037. {
  1038. byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)];
  1039. int pos = 0;
  1040. while (pos < chunk.Length)
  1041. {
  1042. int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);
  1043. if (n <= 0)
  1044. {
  1045. throw InvalidProtocolBufferException.TruncatedMessage();
  1046. }
  1047. totalBytesRetired += n;
  1048. pos += n;
  1049. }
  1050. sizeLeft -= chunk.Length;
  1051. chunks.Add(chunk);
  1052. }
  1053. // OK, got everything. Now concatenate it all into one buffer.
  1054. byte[] bytes = new byte[size];
  1055. // Start by copying the leftover bytes from this.buffer.
  1056. int newPos = originalBufferSize - originalBufferPos;
  1057. ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);
  1058. // And now all the chunks.
  1059. foreach (byte[] chunk in chunks)
  1060. {
  1061. Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);
  1062. newPos += chunk.Length;
  1063. }
  1064. // Done.
  1065. return bytes;
  1066. }
  1067. }
  1068. /// <summary>
  1069. /// Reads and discards <paramref name="size"/> bytes.
  1070. /// </summary>
  1071. /// <exception cref="InvalidProtocolBufferException">the end of the stream
  1072. /// or the current limit was reached</exception>
  1073. private void SkipRawBytes(int size)
  1074. {
  1075. if (size < 0)
  1076. {
  1077. throw InvalidProtocolBufferException.NegativeSize();
  1078. }
  1079. if (totalBytesRetired + bufferPos + size > currentLimit)
  1080. {
  1081. // Read to the end of the stream anyway.
  1082. SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
  1083. // Then fail.
  1084. throw InvalidProtocolBufferException.TruncatedMessage();
  1085. }
  1086. if (size <= bufferSize - bufferPos)
  1087. {
  1088. // We have all the bytes we need already.
  1089. bufferPos += size;
  1090. }
  1091. else
  1092. {
  1093. // Skipping more bytes than are in the buffer. First skip what we have.
  1094. int pos = bufferSize - bufferPos;
  1095. // ROK 5/7/2013 Issue #54: should retire all bytes in buffer (bufferSize)
  1096. // totalBytesRetired += pos;
  1097. totalBytesRetired += bufferSize;
  1098. bufferPos = 0;
  1099. bufferSize = 0;
  1100. // Then skip directly from the InputStream for the rest.
  1101. if (pos < size)
  1102. {
  1103. if (input == null)
  1104. {
  1105. throw InvalidProtocolBufferException.TruncatedMessage();
  1106. }
  1107. SkipImpl(size - pos);
  1108. totalBytesRetired += size - pos;
  1109. }
  1110. }
  1111. }
  1112. /// <summary>
  1113. /// Abstraction of skipping to cope with streams which can't really skip.
  1114. /// </summary>
  1115. private void SkipImpl(int amountToSkip)
  1116. {
  1117. if (input.CanSeek)
  1118. {
  1119. long previousPosition = input.Position;
  1120. input.Position += amountToSkip;
  1121. if (input.Position != previousPosition + amountToSkip)
  1122. {
  1123. throw InvalidProtocolBufferException.TruncatedMessage();
  1124. }
  1125. }
  1126. else
  1127. {
  1128. byte[] skipBuffer = new byte[Math.Min(1024, amountToSkip)];
  1129. while (amountToSkip > 0)
  1130. {
  1131. int bytesRead = input.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, amountToSkip));
  1132. if (bytesRead <= 0)
  1133. {
  1134. throw InvalidProtocolBufferException.TruncatedMessage();
  1135. }
  1136. amountToSkip -= bytesRead;
  1137. }
  1138. }
  1139. }
  1140. #endregion
  1141. }
  1142. }