CodedInputStream.cs 47 KB

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