CodedInputStream.cs 40 KB

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