CodedInputStream.cs 40 KB

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