PageRenderTime 42ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ProtocolBuffers/CodedInputStream.cs

https://code.google.com/p/protobuf-csharp-port/
C# | 1841 lines | 1368 code | 132 blank | 341 comment | 185 complexity | 733cdc7607b4a5f7db78bf9c676404d2 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-2.0
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // http://github.com/jskeet/dotnet-protobufs/
  5. // Original C++/Java/Python code:
  6. // http://code.google.com/p/protobuf/
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * Neither the name of Google Inc. nor the names of its
  19. // contributors may be used to endorse or promote products derived from
  20. // this software without specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. #endregion
  34. using System;
  35. using System.Collections.Generic;
  36. using System.IO;
  37. using System.Text;
  38. using Google.ProtocolBuffers.Descriptors;
  39. namespace Google.ProtocolBuffers
  40. {
  41. /// <summary>
  42. /// Readings and decodes protocol message fields.
  43. /// </summary>
  44. /// <remarks>
  45. /// This class contains two kinds of methods: methods that read specific
  46. /// protocol message constructs and field types (e.g. ReadTag and
  47. /// ReadInt32) and methods that read low-level values (e.g.
  48. /// ReadRawVarint32 and ReadRawBytes). If you are reading encoded protocol
  49. /// messages, you should use the former methods, but if you are reading some
  50. /// other format of your own design, use the latter. The names of the former
  51. /// methods are taken from the protocol buffer type names, not .NET types.
  52. /// (Hence ReadFloat instead of ReadSingle, and ReadBool instead of ReadBoolean.)
  53. ///
  54. /// TODO(jonskeet): Consider whether recursion and size limits shouldn't be readonly,
  55. /// set at construction time.
  56. /// </remarks>
  57. public sealed class CodedInputStream : ICodedInputStream
  58. {
  59. private readonly byte[] buffer;
  60. private int bufferSize;
  61. private int bufferSizeAfterLimit = 0;
  62. private int bufferPos = 0;
  63. private readonly Stream input;
  64. private uint lastTag = 0;
  65. private uint nextTag = 0;
  66. private bool hasNextTag = false;
  67. internal const int DefaultRecursionLimit = 64;
  68. internal const int DefaultSizeLimit = 64 << 20; // 64MB
  69. public const int BufferSize = 4096;
  70. /// <summary>
  71. /// The total number of bytes read before the current buffer. The
  72. /// total bytes read up to the current position can be computed as
  73. /// totalBytesRetired + bufferPos.
  74. /// </summary>
  75. private int totalBytesRetired = 0;
  76. /// <summary>
  77. /// The absolute position of the end of the current message.
  78. /// </summary>
  79. private int currentLimit = int.MaxValue;
  80. /// <summary>
  81. /// <see cref="SetRecursionLimit"/>
  82. /// </summary>
  83. private int recursionDepth = 0;
  84. private int recursionLimit = DefaultRecursionLimit;
  85. /// <summary>
  86. /// <see cref="SetSizeLimit"/>
  87. /// </summary>
  88. private int sizeLimit = DefaultSizeLimit;
  89. #region Construction
  90. /// <summary>
  91. /// Creates a new CodedInputStream reading data from the given
  92. /// stream.
  93. /// </summary>
  94. public static CodedInputStream CreateInstance(Stream input)
  95. {
  96. return new CodedInputStream(input);
  97. }
  98. /// <summary>
  99. /// Creates a new CodedInputStream reading data from the given
  100. /// byte array.
  101. /// </summary>
  102. public static CodedInputStream CreateInstance(byte[] buf)
  103. {
  104. return new CodedInputStream(buf, 0, buf.Length);
  105. }
  106. /// <summary>
  107. /// Creates a new CodedInputStream that reads from the given
  108. /// byte array slice.
  109. /// </summary>
  110. public static CodedInputStream CreateInstance(byte[] buf, int offset, int length)
  111. {
  112. return new CodedInputStream(buf, offset, length);
  113. }
  114. private CodedInputStream(byte[] buffer, int offset, int length)
  115. {
  116. this.buffer = buffer;
  117. this.bufferPos = offset;
  118. this.bufferSize = offset + length;
  119. this.input = null;
  120. }
  121. private CodedInputStream(Stream input)
  122. {
  123. this.buffer = new byte[BufferSize];
  124. this.bufferSize = 0;
  125. this.input = input;
  126. }
  127. #endregion
  128. void ICodedInputStream.ReadMessageStart() { }
  129. void ICodedInputStream.ReadMessageEnd() { }
  130. #region Validation
  131. /// <summary>
  132. /// Verifies that the last call to ReadTag() returned the given tag value.
  133. /// This is used to verify that a nested group ended with the correct
  134. /// end tag.
  135. /// </summary>
  136. /// <exception cref="InvalidProtocolBufferException">The last
  137. /// tag read was not the one specified</exception>
  138. [CLSCompliant(false)]
  139. public void CheckLastTagWas(uint value)
  140. {
  141. if (lastTag != value)
  142. {
  143. throw InvalidProtocolBufferException.InvalidEndTag();
  144. }
  145. }
  146. #endregion
  147. #region Reading of tags etc
  148. /// <summary>
  149. /// Attempt to peek at the next field tag.
  150. /// </summary>
  151. [CLSCompliant(false)]
  152. public bool PeekNextTag(out uint fieldTag, out string fieldName)
  153. {
  154. if (hasNextTag)
  155. {
  156. fieldName = null;
  157. fieldTag = nextTag;
  158. return true;
  159. }
  160. uint savedLast = lastTag;
  161. hasNextTag = ReadTag(out nextTag, out fieldName);
  162. lastTag = savedLast;
  163. fieldTag = nextTag;
  164. return hasNextTag;
  165. }
  166. /// <summary>
  167. /// Attempt to read a field tag, returning false if we have reached the end
  168. /// of the input data.
  169. /// </summary>
  170. /// <param name="fieldTag">The 'tag' of the field (id * 8 + wire-format)</param>
  171. /// <param name="fieldName">Not Supported - For protobuffer streams, this parameter is always null</param>
  172. /// <returns>true if the next fieldTag was read</returns>
  173. [CLSCompliant(false)]
  174. public bool ReadTag(out uint fieldTag, out string fieldName)
  175. {
  176. fieldName = null;
  177. if (hasNextTag)
  178. {
  179. fieldTag = nextTag;
  180. lastTag = fieldTag;
  181. hasNextTag = false;
  182. return true;
  183. }
  184. if (IsAtEnd)
  185. {
  186. fieldTag = 0;
  187. lastTag = fieldTag;
  188. return false;
  189. }
  190. fieldTag = ReadRawVarint32();
  191. lastTag = fieldTag;
  192. if (lastTag == 0)
  193. {
  194. // If we actually read zero, that's not a valid tag.
  195. throw InvalidProtocolBufferException.InvalidTag();
  196. }
  197. return true;
  198. }
  199. /// <summary>
  200. /// Read a double field from the stream.
  201. /// </summary>
  202. public bool ReadDouble(ref double value)
  203. {
  204. #if SILVERLIGHT || COMPACT_FRAMEWORK_35
  205. if (BitConverter.IsLittleEndian && 8 <= bufferSize - bufferPos)
  206. {
  207. value = BitConverter.ToDouble(buffer, bufferPos);
  208. bufferPos += 8;
  209. }
  210. else
  211. {
  212. byte[] rawBytes = ReadRawBytes(8);
  213. if (!BitConverter.IsLittleEndian)
  214. ByteArray.Reverse(rawBytes);
  215. value = BitConverter.ToDouble(rawBytes, 0);
  216. }
  217. #else
  218. value = BitConverter.Int64BitsToDouble((long) ReadRawLittleEndian64());
  219. #endif
  220. return true;
  221. }
  222. /// <summary>
  223. /// Read a float field from the stream.
  224. /// </summary>
  225. public bool ReadFloat(ref float value)
  226. {
  227. if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)
  228. {
  229. value = BitConverter.ToSingle(buffer, bufferPos);
  230. bufferPos += 4;
  231. }
  232. else
  233. {
  234. byte[] rawBytes = ReadRawBytes(4);
  235. if (!BitConverter.IsLittleEndian)
  236. {
  237. ByteArray.Reverse(rawBytes);
  238. }
  239. value = BitConverter.ToSingle(rawBytes, 0);
  240. }
  241. return true;
  242. }
  243. /// <summary>
  244. /// Read a uint64 field from the stream.
  245. /// </summary>
  246. [CLSCompliant(false)]
  247. public bool ReadUInt64(ref ulong value)
  248. {
  249. value = ReadRawVarint64();
  250. return true;
  251. }
  252. /// <summary>
  253. /// Read an int64 field from the stream.
  254. /// </summary>
  255. public bool ReadInt64(ref long value)
  256. {
  257. value = (long) ReadRawVarint64();
  258. return true;
  259. }
  260. /// <summary>
  261. /// Read an int32 field from the stream.
  262. /// </summary>
  263. public bool ReadInt32(ref int value)
  264. {
  265. value = (int) ReadRawVarint32();
  266. return true;
  267. }
  268. /// <summary>
  269. /// Read a fixed64 field from the stream.
  270. /// </summary>
  271. [CLSCompliant(false)]
  272. public bool ReadFixed64(ref ulong value)
  273. {
  274. value = ReadRawLittleEndian64();
  275. return true;
  276. }
  277. /// <summary>
  278. /// Read a fixed32 field from the stream.
  279. /// </summary>
  280. [CLSCompliant(false)]
  281. public bool ReadFixed32(ref uint value)
  282. {
  283. value = ReadRawLittleEndian32();
  284. return true;
  285. }
  286. /// <summary>
  287. /// Read a bool field from the stream.
  288. /// </summary>
  289. public bool ReadBool(ref bool value)
  290. {
  291. value = ReadRawVarint32() != 0;
  292. return true;
  293. }
  294. /// <summary>
  295. /// Reads a string field from the stream.
  296. /// </summary>
  297. public bool ReadString(ref string value)
  298. {
  299. int size = (int) ReadRawVarint32();
  300. // No need to read any data for an empty string.
  301. if (size == 0)
  302. {
  303. value = "";
  304. return true;
  305. }
  306. if (size <= bufferSize - bufferPos)
  307. {
  308. // Fast path: We already have the bytes in a contiguous buffer, so
  309. // just copy directly from it.
  310. String result = Encoding.UTF8.GetString(buffer, bufferPos, size);
  311. bufferPos += size;
  312. value = result;
  313. return true;
  314. }
  315. // Slow path: Build a byte array first then copy it.
  316. value = Encoding.UTF8.GetString(ReadRawBytes(size), 0, size);
  317. return true;
  318. }
  319. /// <summary>
  320. /// Reads a group field value from the stream.
  321. /// </summary>
  322. public void ReadGroup(int fieldNumber, IBuilderLite builder,
  323. ExtensionRegistry extensionRegistry)
  324. {
  325. if (recursionDepth >= recursionLimit)
  326. {
  327. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  328. }
  329. ++recursionDepth;
  330. builder.WeakMergeFrom(this, extensionRegistry);
  331. CheckLastTagWas(WireFormat.MakeTag(fieldNumber, WireFormat.WireType.EndGroup));
  332. --recursionDepth;
  333. }
  334. /// <summary>
  335. /// Reads a group field value from the stream and merges it into the given
  336. /// UnknownFieldSet.
  337. /// </summary>
  338. [Obsolete]
  339. public void ReadUnknownGroup(int fieldNumber, IBuilderLite builder)
  340. {
  341. if (recursionDepth >= recursionLimit)
  342. {
  343. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  344. }
  345. ++recursionDepth;
  346. builder.WeakMergeFrom(this);
  347. CheckLastTagWas(WireFormat.MakeTag(fieldNumber, WireFormat.WireType.EndGroup));
  348. --recursionDepth;
  349. }
  350. /// <summary>
  351. /// Reads an embedded message field value from the stream.
  352. /// </summary>
  353. public void ReadMessage(IBuilderLite builder, ExtensionRegistry extensionRegistry)
  354. {
  355. int length = (int) ReadRawVarint32();
  356. if (recursionDepth >= recursionLimit)
  357. {
  358. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  359. }
  360. int oldLimit = PushLimit(length);
  361. ++recursionDepth;
  362. builder.WeakMergeFrom(this, extensionRegistry);
  363. CheckLastTagWas(0);
  364. --recursionDepth;
  365. PopLimit(oldLimit);
  366. }
  367. /// <summary>
  368. /// Reads a bytes field value from the stream.
  369. /// </summary>
  370. public bool ReadBytes(ref ByteString value)
  371. {
  372. int size = (int) ReadRawVarint32();
  373. if (size < bufferSize - bufferPos && size > 0)
  374. {
  375. // Fast path: We already have the bytes in a contiguous buffer, so
  376. // just copy directly from it.
  377. ByteString result = ByteString.CopyFrom(buffer, bufferPos, size);
  378. bufferPos += size;
  379. value = result;
  380. return true;
  381. }
  382. else
  383. {
  384. // Slow path: Build a byte array and attach it to a new ByteString.
  385. value = ByteString.AttachBytes(ReadRawBytes(size));
  386. return true;
  387. }
  388. }
  389. /// <summary>
  390. /// Reads a uint32 field value from the stream.
  391. /// </summary>
  392. [CLSCompliant(false)]
  393. public bool ReadUInt32(ref uint value)
  394. {
  395. value = ReadRawVarint32();
  396. return true;
  397. }
  398. /// <summary>
  399. /// Reads an enum field value from the stream. The caller is responsible
  400. /// for converting the numeric value to an actual enum.
  401. /// </summary>
  402. public bool ReadEnum(ref IEnumLite value, out object unknown, IEnumLiteMap mapping)
  403. {
  404. int rawValue = (int) ReadRawVarint32();
  405. value = mapping.FindValueByNumber(rawValue);
  406. if (value != null)
  407. {
  408. unknown = null;
  409. return true;
  410. }
  411. unknown = rawValue;
  412. return false;
  413. }
  414. /// <summary>
  415. /// Reads an enum field value from the stream. If the enum is valid for type T,
  416. /// then the ref value is set and it returns true. Otherwise the unkown output
  417. /// value is set and this method returns false.
  418. /// </summary>
  419. [CLSCompliant(false)]
  420. public bool ReadEnum<T>(ref T value, out object unknown)
  421. where T : struct, IComparable, IFormattable, IConvertible
  422. {
  423. int number = (int) ReadRawVarint32();
  424. if (Enum.IsDefined(typeof (T), number))
  425. {
  426. unknown = null;
  427. value = (T) (object) number;
  428. return true;
  429. }
  430. unknown = number;
  431. return false;
  432. }
  433. /// <summary>
  434. /// Reads an sfixed32 field value from the stream.
  435. /// </summary>
  436. public bool ReadSFixed32(ref int value)
  437. {
  438. value = (int) ReadRawLittleEndian32();
  439. return true;
  440. }
  441. /// <summary>
  442. /// Reads an sfixed64 field value from the stream.
  443. /// </summary>
  444. public bool ReadSFixed64(ref long value)
  445. {
  446. value = (long) ReadRawLittleEndian64();
  447. return true;
  448. }
  449. /// <summary>
  450. /// Reads an sint32 field value from the stream.
  451. /// </summary>
  452. public bool ReadSInt32(ref int value)
  453. {
  454. value = DecodeZigZag32(ReadRawVarint32());
  455. return true;
  456. }
  457. /// <summary>
  458. /// Reads an sint64 field value from the stream.
  459. /// </summary>
  460. public bool ReadSInt64(ref long value)
  461. {
  462. value = DecodeZigZag64(ReadRawVarint64());
  463. return true;
  464. }
  465. private bool BeginArray(uint fieldTag, out bool isPacked, out int oldLimit)
  466. {
  467. isPacked = WireFormat.GetTagWireType(fieldTag) == WireFormat.WireType.LengthDelimited;
  468. if (isPacked)
  469. {
  470. int length = (int) (ReadRawVarint32() & int.MaxValue);
  471. if (length > 0)
  472. {
  473. oldLimit = PushLimit(length);
  474. return true;
  475. }
  476. oldLimit = -1;
  477. return false; //packed but empty
  478. }
  479. oldLimit = -1;
  480. return true;
  481. }
  482. /// <summary>
  483. /// Returns true if the next tag is also part of the same unpacked array.
  484. /// </summary>
  485. private bool ContinueArray(uint currentTag)
  486. {
  487. string ignore;
  488. uint next;
  489. if (PeekNextTag(out next, out ignore))
  490. {
  491. if (next == currentTag)
  492. {
  493. hasNextTag = false;
  494. return true;
  495. }
  496. }
  497. return false;
  498. }
  499. /// <summary>
  500. /// Returns true if the next tag is also part of the same array, which may or may not be packed.
  501. /// </summary>
  502. private bool ContinueArray(uint currentTag, bool packed, int oldLimit)
  503. {
  504. if (packed)
  505. {
  506. if (ReachedLimit)
  507. {
  508. PopLimit(oldLimit);
  509. return false;
  510. }
  511. return true;
  512. }
  513. string ignore;
  514. uint next;
  515. if (PeekNextTag(out next, out ignore))
  516. {
  517. if (next == currentTag)
  518. {
  519. hasNextTag = false;
  520. return true;
  521. }
  522. }
  523. return false;
  524. }
  525. [CLSCompliant(false)]
  526. public void ReadPrimitiveArray(FieldType fieldType, uint fieldTag, string fieldName, ICollection<object> list)
  527. {
  528. WireFormat.WireType normal = WireFormat.GetWireType(fieldType);
  529. WireFormat.WireType wformat = WireFormat.GetTagWireType(fieldTag);
  530. // 2.3 allows packed form even if the field is not declared packed.
  531. if (normal != wformat && wformat == WireFormat.WireType.LengthDelimited)
  532. {
  533. int length = (int) (ReadRawVarint32() & int.MaxValue);
  534. int limit = PushLimit(length);
  535. while (!ReachedLimit)
  536. {
  537. Object value = null;
  538. if (ReadPrimitiveField(fieldType, ref value))
  539. {
  540. list.Add(value);
  541. }
  542. }
  543. PopLimit(limit);
  544. }
  545. else
  546. {
  547. Object value = null;
  548. do
  549. {
  550. if (ReadPrimitiveField(fieldType, ref value))
  551. {
  552. list.Add(value);
  553. }
  554. } while (ContinueArray(fieldTag));
  555. }
  556. }
  557. [CLSCompliant(false)]
  558. public void ReadStringArray(uint fieldTag, string fieldName, ICollection<string> list)
  559. {
  560. string tmp = null;
  561. do
  562. {
  563. ReadString(ref tmp);
  564. list.Add(tmp);
  565. } while (ContinueArray(fieldTag));
  566. }
  567. [CLSCompliant(false)]
  568. public void ReadBytesArray(uint fieldTag, string fieldName, ICollection<ByteString> list)
  569. {
  570. ByteString tmp = null;
  571. do
  572. {
  573. ReadBytes(ref tmp);
  574. list.Add(tmp);
  575. } while (ContinueArray(fieldTag));
  576. }
  577. [CLSCompliant(false)]
  578. public void ReadBoolArray(uint fieldTag, string fieldName, ICollection<bool> list)
  579. {
  580. bool isPacked;
  581. int holdLimit;
  582. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  583. {
  584. bool tmp = false;
  585. do
  586. {
  587. ReadBool(ref tmp);
  588. list.Add(tmp);
  589. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  590. }
  591. }
  592. [CLSCompliant(false)]
  593. public void ReadInt32Array(uint fieldTag, string fieldName, ICollection<int> list)
  594. {
  595. bool isPacked;
  596. int holdLimit;
  597. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  598. {
  599. int tmp = 0;
  600. do
  601. {
  602. ReadInt32(ref tmp);
  603. list.Add(tmp);
  604. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  605. }
  606. }
  607. [CLSCompliant(false)]
  608. public void ReadSInt32Array(uint fieldTag, string fieldName, ICollection<int> list)
  609. {
  610. bool isPacked;
  611. int holdLimit;
  612. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  613. {
  614. int tmp = 0;
  615. do
  616. {
  617. ReadSInt32(ref tmp);
  618. list.Add(tmp);
  619. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  620. }
  621. }
  622. [CLSCompliant(false)]
  623. public void ReadUInt32Array(uint fieldTag, string fieldName, ICollection<uint> list)
  624. {
  625. bool isPacked;
  626. int holdLimit;
  627. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  628. {
  629. uint tmp = 0;
  630. do
  631. {
  632. ReadUInt32(ref tmp);
  633. list.Add(tmp);
  634. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  635. }
  636. }
  637. [CLSCompliant(false)]
  638. public void ReadFixed32Array(uint fieldTag, string fieldName, ICollection<uint> list)
  639. {
  640. bool isPacked;
  641. int holdLimit;
  642. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  643. {
  644. uint tmp = 0;
  645. do
  646. {
  647. ReadFixed32(ref tmp);
  648. list.Add(tmp);
  649. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  650. }
  651. }
  652. [CLSCompliant(false)]
  653. public void ReadSFixed32Array(uint fieldTag, string fieldName, ICollection<int> list)
  654. {
  655. bool isPacked;
  656. int holdLimit;
  657. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  658. {
  659. int tmp = 0;
  660. do
  661. {
  662. ReadSFixed32(ref tmp);
  663. list.Add(tmp);
  664. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  665. }
  666. }
  667. [CLSCompliant(false)]
  668. public void ReadInt64Array(uint fieldTag, string fieldName, ICollection<long> list)
  669. {
  670. bool isPacked;
  671. int holdLimit;
  672. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  673. {
  674. long tmp = 0;
  675. do
  676. {
  677. ReadInt64(ref tmp);
  678. list.Add(tmp);
  679. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  680. }
  681. }
  682. [CLSCompliant(false)]
  683. public void ReadSInt64Array(uint fieldTag, string fieldName, ICollection<long> list)
  684. {
  685. bool isPacked;
  686. int holdLimit;
  687. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  688. {
  689. long tmp = 0;
  690. do
  691. {
  692. ReadSInt64(ref tmp);
  693. list.Add(tmp);
  694. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  695. }
  696. }
  697. [CLSCompliant(false)]
  698. public void ReadUInt64Array(uint fieldTag, string fieldName, ICollection<ulong> list)
  699. {
  700. bool isPacked;
  701. int holdLimit;
  702. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  703. {
  704. ulong tmp = 0;
  705. do
  706. {
  707. ReadUInt64(ref tmp);
  708. list.Add(tmp);
  709. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  710. }
  711. }
  712. [CLSCompliant(false)]
  713. public void ReadFixed64Array(uint fieldTag, string fieldName, ICollection<ulong> list)
  714. {
  715. bool isPacked;
  716. int holdLimit;
  717. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  718. {
  719. ulong tmp = 0;
  720. do
  721. {
  722. ReadFixed64(ref tmp);
  723. list.Add(tmp);
  724. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  725. }
  726. }
  727. [CLSCompliant(false)]
  728. public void ReadSFixed64Array(uint fieldTag, string fieldName, ICollection<long> list)
  729. {
  730. bool isPacked;
  731. int holdLimit;
  732. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  733. {
  734. long tmp = 0;
  735. do
  736. {
  737. ReadSFixed64(ref tmp);
  738. list.Add(tmp);
  739. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  740. }
  741. }
  742. [CLSCompliant(false)]
  743. public void ReadDoubleArray(uint fieldTag, string fieldName, ICollection<double> list)
  744. {
  745. bool isPacked;
  746. int holdLimit;
  747. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  748. {
  749. double tmp = 0;
  750. do
  751. {
  752. ReadDouble(ref tmp);
  753. list.Add(tmp);
  754. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  755. }
  756. }
  757. [CLSCompliant(false)]
  758. public void ReadFloatArray(uint fieldTag, string fieldName, ICollection<float> list)
  759. {
  760. bool isPacked;
  761. int holdLimit;
  762. if (BeginArray(fieldTag, out isPacked, out holdLimit))
  763. {
  764. float tmp = 0;
  765. do
  766. {
  767. ReadFloat(ref tmp);
  768. list.Add(tmp);
  769. } while (ContinueArray(fieldTag, isPacked, holdLimit));
  770. }
  771. }
  772. [CLSCompliant(false)]
  773. public void ReadEnumArray(uint fieldTag, string fieldName, ICollection<IEnumLite> list,
  774. out ICollection<object> unknown, IEnumLiteMap mapping)
  775. {
  776. unknown = null;
  777. object unkval;
  778. IEnumLite value = null;
  779. WireFormat.WireType wformat = WireFormat.GetTagWireType(fieldTag);
  780. // 2.3 allows packed form even if the field is not declared packed.
  781. if (wformat == WireFormat.WireType.LengthDelimited)
  782. {
  783. int length = (int) (ReadRawVarint32() & int.MaxValue);
  784. int limit = PushLimit(length);
  785. while (!ReachedLimit)
  786. {
  787. if (ReadEnum(ref value, out unkval, mapping))
  788. {
  789. list.Add(value);
  790. }
  791. else
  792. {
  793. if (unknown == null)
  794. {
  795. unknown = new List<object>();
  796. }
  797. unknown.Add(unkval);
  798. }
  799. }
  800. PopLimit(limit);
  801. }
  802. else
  803. {
  804. do
  805. {
  806. if (ReadEnum(ref value, out unkval, mapping))
  807. {
  808. list.Add(value);
  809. }
  810. else
  811. {
  812. if (unknown == null)
  813. {
  814. unknown = new List<object>();
  815. }
  816. unknown.Add(unkval);
  817. }
  818. } while (ContinueArray(fieldTag));
  819. }
  820. }
  821. [CLSCompliant(false)]
  822. public void ReadEnumArray<T>(uint fieldTag, string fieldName, ICollection<T> list,
  823. out ICollection<object> unknown)
  824. where T : struct, IComparable, IFormattable, IConvertible
  825. {
  826. unknown = null;
  827. object unkval;
  828. T value = default(T);
  829. WireFormat.WireType wformat = WireFormat.GetTagWireType(fieldTag);
  830. // 2.3 allows packed form even if the field is not declared packed.
  831. if (wformat == WireFormat.WireType.LengthDelimited)
  832. {
  833. int length = (int) (ReadRawVarint32() & int.MaxValue);
  834. int limit = PushLimit(length);
  835. while (!ReachedLimit)
  836. {
  837. if (ReadEnum<T>(ref value, out unkval))
  838. {
  839. list.Add(value);
  840. }
  841. else
  842. {
  843. if (unknown == null)
  844. {
  845. unknown = new List<object>();
  846. }
  847. unknown.Add(unkval);
  848. }
  849. }
  850. PopLimit(limit);
  851. }
  852. else
  853. {
  854. do
  855. {
  856. if (ReadEnum(ref value, out unkval))
  857. {
  858. list.Add(value);
  859. }
  860. else
  861. {
  862. if (unknown == null)
  863. {
  864. unknown = new List<object>();
  865. }
  866. unknown.Add(unkval);
  867. }
  868. } while (ContinueArray(fieldTag));
  869. }
  870. }
  871. [CLSCompliant(false)]
  872. public void ReadMessageArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType,
  873. ExtensionRegistry registry) where T : IMessageLite
  874. {
  875. do
  876. {
  877. IBuilderLite builder = messageType.WeakCreateBuilderForType();
  878. ReadMessage(builder, registry);
  879. list.Add((T) builder.WeakBuildPartial());
  880. } while (ContinueArray(fieldTag));
  881. }
  882. [CLSCompliant(false)]
  883. public void ReadGroupArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType,
  884. ExtensionRegistry registry) where T : IMessageLite
  885. {
  886. do
  887. {
  888. IBuilderLite builder = messageType.WeakCreateBuilderForType();
  889. ReadGroup(WireFormat.GetTagFieldNumber(fieldTag), builder, registry);
  890. list.Add((T) builder.WeakBuildPartial());
  891. } while (ContinueArray(fieldTag));
  892. }
  893. /// <summary>
  894. /// Reads a field of any primitive type. Enums, groups and embedded
  895. /// messages are not handled by this method.
  896. /// </summary>
  897. public bool ReadPrimitiveField(FieldType fieldType, ref object value)
  898. {
  899. switch (fieldType)
  900. {
  901. case FieldType.Double:
  902. {
  903. double tmp = 0;
  904. if (ReadDouble(ref tmp))
  905. {
  906. value = tmp;
  907. return true;
  908. }
  909. return false;
  910. }
  911. case FieldType.Float:
  912. {
  913. float tmp = 0;
  914. if (ReadFloat(ref tmp))
  915. {
  916. value = tmp;
  917. return true;
  918. }
  919. return false;
  920. }
  921. case FieldType.Int64:
  922. {
  923. long tmp = 0;
  924. if (ReadInt64(ref tmp))
  925. {
  926. value = tmp;
  927. return true;
  928. }
  929. return false;
  930. }
  931. case FieldType.UInt64:
  932. {
  933. ulong tmp = 0;
  934. if (ReadUInt64(ref tmp))
  935. {
  936. value = tmp;
  937. return true;
  938. }
  939. return false;
  940. }
  941. case FieldType.Int32:
  942. {
  943. int tmp = 0;
  944. if (ReadInt32(ref tmp))
  945. {
  946. value = tmp;
  947. return true;
  948. }
  949. return false;
  950. }
  951. case FieldType.Fixed64:
  952. {
  953. ulong tmp = 0;
  954. if (ReadFixed64(ref tmp))
  955. {
  956. value = tmp;
  957. return true;
  958. }
  959. return false;
  960. }
  961. case FieldType.Fixed32:
  962. {
  963. uint tmp = 0;
  964. if (ReadFixed32(ref tmp))
  965. {
  966. value = tmp;
  967. return true;
  968. }
  969. return false;
  970. }
  971. case FieldType.Bool:
  972. {
  973. bool tmp = false;
  974. if (ReadBool(ref tmp))
  975. {
  976. value = tmp;
  977. return true;
  978. }
  979. return false;
  980. }
  981. case FieldType.String:
  982. {
  983. string tmp = null;
  984. if (ReadString(ref tmp))
  985. {
  986. value = tmp;
  987. return true;
  988. }
  989. return false;
  990. }
  991. case FieldType.Bytes:
  992. {
  993. ByteString tmp = null;
  994. if (ReadBytes(ref tmp))
  995. {
  996. value = tmp;
  997. return true;
  998. }
  999. return false;
  1000. }
  1001. case FieldType.UInt32:
  1002. {
  1003. uint tmp = 0;
  1004. if (ReadUInt32(ref tmp))
  1005. {
  1006. value = tmp;
  1007. return true;
  1008. }
  1009. return false;
  1010. }
  1011. case FieldType.SFixed32:
  1012. {
  1013. int tmp = 0;
  1014. if (ReadSFixed32(ref tmp))
  1015. {
  1016. value = tmp;
  1017. return true;
  1018. }
  1019. return false;
  1020. }
  1021. case FieldType.SFixed64:
  1022. {
  1023. long tmp = 0;
  1024. if (ReadSFixed64(ref tmp))
  1025. {
  1026. value = tmp;
  1027. return true;
  1028. }
  1029. return false;
  1030. }
  1031. case FieldType.SInt32:
  1032. {
  1033. int tmp = 0;
  1034. if (ReadSInt32(ref tmp))
  1035. {
  1036. value = tmp;
  1037. return true;
  1038. }
  1039. return false;
  1040. }
  1041. case FieldType.SInt64:
  1042. {
  1043. long tmp = 0;
  1044. if (ReadSInt64(ref tmp))
  1045. {
  1046. value = tmp;
  1047. return true;
  1048. }
  1049. return false;
  1050. }
  1051. case FieldType.Group:
  1052. throw new ArgumentException("ReadPrimitiveField() cannot handle nested groups.");
  1053. case FieldType.Message:
  1054. throw new ArgumentException("ReadPrimitiveField() cannot handle embedded messages.");
  1055. // We don't handle enums because we don't know what to do if the
  1056. // value is not recognized.
  1057. case FieldType.Enum:
  1058. throw new ArgumentException("ReadPrimitiveField() cannot handle enums.");
  1059. default:
  1060. throw new ArgumentOutOfRangeException("Invalid field type " + fieldType);
  1061. }
  1062. }
  1063. #endregion
  1064. #region Underlying reading primitives
  1065. /// <summary>
  1066. /// Same code as ReadRawVarint32, but read each byte individually, checking for
  1067. /// buffer overflow.
  1068. /// </summary>
  1069. private uint SlowReadRawVarint32()
  1070. {
  1071. int tmp = ReadRawByte();
  1072. if (tmp < 128)
  1073. {
  1074. return (uint) tmp;
  1075. }
  1076. int result = tmp & 0x7f;
  1077. if ((tmp = ReadRawByte()) < 128)
  1078. {
  1079. result |= tmp << 7;
  1080. }
  1081. else
  1082. {
  1083. result |= (tmp & 0x7f) << 7;
  1084. if ((tmp = ReadRawByte()) < 128)
  1085. {
  1086. result |= tmp << 14;
  1087. }
  1088. else
  1089. {
  1090. result |= (tmp & 0x7f) << 14;
  1091. if ((tmp = ReadRawByte()) < 128)
  1092. {
  1093. result |= tmp << 21;
  1094. }
  1095. else
  1096. {
  1097. result |= (tmp & 0x7f) << 21;
  1098. result |= (tmp = ReadRawByte()) << 28;
  1099. if (tmp >= 128)
  1100. {
  1101. // Discard upper 32 bits.
  1102. for (int i = 0; i < 5; i++)
  1103. {
  1104. if (ReadRawByte() < 128)
  1105. {
  1106. return (uint) result;
  1107. }
  1108. }
  1109. throw InvalidProtocolBufferException.MalformedVarint();
  1110. }
  1111. }
  1112. }
  1113. }
  1114. return (uint) result;
  1115. }
  1116. /// <summary>
  1117. /// Read a raw Varint from the stream. If larger than 32 bits, discard the upper bits.
  1118. /// This method is optimised for the case where we've got lots of data in the buffer.
  1119. /// That means we can check the size just once, then just read directly from the buffer
  1120. /// without constant rechecking of the buffer length.
  1121. /// </summary>
  1122. [CLSCompliant(false)]
  1123. public uint ReadRawVarint32()
  1124. {
  1125. if (bufferPos + 5 > bufferSize)
  1126. {
  1127. return SlowReadRawVarint32();
  1128. }
  1129. int tmp = buffer[bufferPos++];
  1130. if (tmp < 128)
  1131. {
  1132. return (uint) tmp;
  1133. }
  1134. int result = tmp & 0x7f;
  1135. if ((tmp = buffer[bufferPos++]) < 128)
  1136. {
  1137. result |= tmp << 7;
  1138. }
  1139. else
  1140. {
  1141. result |= (tmp & 0x7f) << 7;
  1142. if ((tmp = buffer[bufferPos++]) < 128)
  1143. {
  1144. result |= tmp << 14;
  1145. }
  1146. else
  1147. {
  1148. result |= (tmp & 0x7f) << 14;
  1149. if ((tmp = buffer[bufferPos++]) < 128)
  1150. {
  1151. result |= tmp << 21;
  1152. }
  1153. else
  1154. {
  1155. result |= (tmp & 0x7f) << 21;
  1156. result |= (tmp = buffer[bufferPos++]) << 28;
  1157. if (tmp >= 128)
  1158. {
  1159. // Discard upper 32 bits.
  1160. // Note that this has to use ReadRawByte() as we only ensure we've
  1161. // got at least 5 bytes at the start of the method. This lets us
  1162. // use the fast path in more cases, and we rarely hit this section of code.
  1163. for (int i = 0; i < 5; i++)
  1164. {
  1165. if (ReadRawByte() < 128)
  1166. {
  1167. return (uint) result;
  1168. }
  1169. }
  1170. throw InvalidProtocolBufferException.MalformedVarint();
  1171. }
  1172. }
  1173. }
  1174. }
  1175. return (uint) result;
  1176. }
  1177. /// <summary>
  1178. /// Reads a varint from the input one byte at a time, so that it does not
  1179. /// read any bytes after the end of the varint. If you simply wrapped the
  1180. /// stream in a CodedInputStream and used ReadRawVarint32(Stream)}
  1181. /// then you would probably end up reading past the end of the varint since
  1182. /// CodedInputStream buffers its input.
  1183. /// </summary>
  1184. /// <param name="input"></param>
  1185. /// <returns></returns>
  1186. [CLSCompliant(false)]
  1187. public static uint ReadRawVarint32(Stream input)
  1188. {
  1189. int result = 0;
  1190. int offset = 0;
  1191. for (; offset < 32; offset += 7)
  1192. {
  1193. int b = input.ReadByte();
  1194. if (b == -1)
  1195. {
  1196. throw InvalidProtocolBufferException.TruncatedMessage();
  1197. }
  1198. result |= (b & 0x7f) << offset;
  1199. if ((b & 0x80) == 0)
  1200. {
  1201. return (uint) result;
  1202. }
  1203. }
  1204. // Keep reading up to 64 bits.
  1205. for (; offset < 64; offset += 7)
  1206. {
  1207. int b = input.ReadByte();
  1208. if (b == -1)
  1209. {
  1210. throw InvalidProtocolBufferException.TruncatedMessage();
  1211. }
  1212. if ((b & 0x80) == 0)
  1213. {
  1214. return (uint) result;
  1215. }
  1216. }
  1217. throw InvalidProtocolBufferException.MalformedVarint();
  1218. }
  1219. /// <summary>
  1220. /// Read a raw varint from the stream.
  1221. /// </summary>
  1222. [CLSCompliant(false)]
  1223. public ulong ReadRawVarint64()
  1224. {
  1225. int shift = 0;
  1226. ulong result = 0;
  1227. while (shift < 64)
  1228. {
  1229. byte b = ReadRawByte();
  1230. result |= (ulong) (b & 0x7F) << shift;
  1231. if ((b & 0x80) == 0)
  1232. {
  1233. return result;
  1234. }
  1235. shift += 7;
  1236. }
  1237. throw InvalidProtocolBufferException.MalformedVarint();
  1238. }
  1239. /// <summary>
  1240. /// Read a 32-bit little-endian integer from the stream.
  1241. /// </summary>
  1242. [CLSCompliant(false)]
  1243. public uint ReadRawLittleEndian32()
  1244. {
  1245. uint b1 = ReadRawByte();
  1246. uint b2 = ReadRawByte();
  1247. uint b3 = ReadRawByte();
  1248. uint b4 = ReadRawByte();
  1249. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
  1250. }
  1251. /// <summary>
  1252. /// Read a 64-bit little-endian integer from the stream.
  1253. /// </summary>
  1254. [CLSCompliant(false)]
  1255. public ulong ReadRawLittleEndian64()
  1256. {
  1257. ulong b1 = ReadRawByte();
  1258. ulong b2 = ReadRawByte();
  1259. ulong b3 = ReadRawByte();
  1260. ulong b4 = ReadRawByte();
  1261. ulong b5 = ReadRawByte();
  1262. ulong b6 = ReadRawByte();
  1263. ulong b7 = ReadRawByte();
  1264. ulong b8 = ReadRawByte();
  1265. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
  1266. | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
  1267. }
  1268. #endregion
  1269. /// <summary>
  1270. /// Decode a 32-bit value with ZigZag encoding.
  1271. /// </summary>
  1272. /// <remarks>
  1273. /// ZigZag encodes signed integers into values that can be efficiently
  1274. /// encoded with varint. (Otherwise, negative values must be
  1275. /// sign-extended to 64 bits to be varint encoded, thus always taking
  1276. /// 10 bytes on the wire.)
  1277. /// </remarks>
  1278. [CLSCompliant(false)]
  1279. public static int DecodeZigZag32(uint n)
  1280. {
  1281. return (int) (n >> 1) ^ -(int) (n & 1);
  1282. }
  1283. /// <summary>
  1284. /// Decode a 32-bit value with ZigZag encoding.
  1285. /// </summary>
  1286. /// <remarks>
  1287. /// ZigZag encodes signed integers into values that can be efficiently
  1288. /// encoded with varint. (Otherwise, negative values must be
  1289. /// sign-extended to 64 bits to be varint encoded, thus always taking
  1290. /// 10 bytes on the wire.)
  1291. /// </remarks>
  1292. [CLSCompliant(false)]
  1293. public static long DecodeZigZag64(ulong n)
  1294. {
  1295. return (long) (n >> 1) ^ -(long) (n & 1);
  1296. }
  1297. /// <summary>
  1298. /// Set the maximum message recursion depth.
  1299. /// </summary>
  1300. /// <remarks>
  1301. /// In order to prevent malicious
  1302. /// messages from causing stack overflows, CodedInputStream limits
  1303. /// how deeply messages may be nested. The default limit is 64.
  1304. /// </remarks>
  1305. public int SetRecursionLimit(int limit)
  1306. {
  1307. if (limit < 0)
  1308. {
  1309. throw new ArgumentOutOfRangeException("Recursion limit cannot be negative: " + limit);
  1310. }
  1311. int oldLimit = recursionLimit;
  1312. recursionLimit = limit;
  1313. return oldLimit;
  1314. }
  1315. /// <summary>
  1316. /// Set the maximum message size.
  1317. /// </summary>
  1318. /// <remarks>
  1319. /// In order to prevent malicious messages from exhausting memory or
  1320. /// causing integer overflows, CodedInputStream limits how large a message may be.
  1321. /// The default limit is 64MB. You should set this limit as small
  1322. /// as you can without harming your app's functionality. Note that
  1323. /// size limits only apply when reading from an InputStream, not
  1324. /// when constructed around a raw byte array (nor with ByteString.NewCodedInput).
  1325. /// If you want to read several messages from a single CodedInputStream, you
  1326. /// can call ResetSizeCounter() after each message to avoid hitting the
  1327. /// size limit.
  1328. /// </remarks>
  1329. public int SetSizeLimit(int limit)
  1330. {
  1331. if (limit < 0)
  1332. {
  1333. throw new ArgumentOutOfRangeException("Size limit cannot be negative: " + limit);
  1334. }
  1335. int oldLimit = sizeLimit;
  1336. sizeLimit = limit;
  1337. return oldLimit;
  1338. }
  1339. #region Internal reading and buffer management
  1340. /// <summary>
  1341. /// Resets the current size counter to zero (see SetSizeLimit).
  1342. /// </summary>
  1343. public void ResetSizeCounter()
  1344. {
  1345. totalBytesRetired = 0;
  1346. }
  1347. /// <summary>
  1348. /// Sets currentLimit to (current position) + byteLimit. This is called
  1349. /// when descending into a length-delimited embedded message. The previous
  1350. /// limit is returned.
  1351. /// </summary>
  1352. /// <returns>The old limit.</returns>
  1353. public int PushLimit(int byteLimit)
  1354. {
  1355. if (byteLimit < 0)
  1356. {
  1357. throw InvalidProtocolBufferException.NegativeSize();
  1358. }
  1359. byteLimit += totalBytesRetired + bufferPos;
  1360. int oldLimit = currentLimit;
  1361. if (byteLimit > oldLimit)
  1362. {
  1363. throw InvalidProtocolBufferException.TruncatedMessage();
  1364. }
  1365. currentLimit = byteLimit;
  1366. RecomputeBufferSizeAfterLimit();
  1367. return oldLimit;
  1368. }
  1369. private void RecomputeBufferSizeAfterLimit()
  1370. {
  1371. bufferSize += bufferSizeAfterLimit;
  1372. int bufferEnd = totalBytesRetired + bufferSize;
  1373. if (bufferEnd > currentLimit)
  1374. {
  1375. // Limit is in current buffer.
  1376. bufferSizeAfterLimit = bufferEnd - currentLimit;
  1377. bufferSize -= bufferSizeAfterLimit;
  1378. }
  1379. else
  1380. {
  1381. bufferSizeAfterLimit = 0;
  1382. }
  1383. }
  1384. /// <summary>
  1385. /// Discards the current limit, returning the previous limit.
  1386. /// </summary>
  1387. public void PopLimit(int oldLimit)
  1388. {
  1389. currentLimit = oldLimit;
  1390. RecomputeBufferSizeAfterLimit();
  1391. }
  1392. /// <summary>
  1393. /// Returns whether or not all the data before the limit has been read.
  1394. /// </summary>
  1395. /// <returns></returns>
  1396. public bool ReachedLimit
  1397. {
  1398. get
  1399. {
  1400. if (currentLimit == int.MaxValue)
  1401. {
  1402. return false;
  1403. }
  1404. int currentAbsolutePosition = totalBytesRetired + bufferPos;
  1405. return currentAbsolutePosition >= currentLimit;
  1406. }
  1407. }
  1408. /// <summary>
  1409. /// Returns true if the stream has reached the end of the input. This is the
  1410. /// case if either the end of the underlying input source has been reached or
  1411. /// the stream has reached a limit created using PushLimit.
  1412. /// </summary>
  1413. public bool IsAtEnd
  1414. {
  1415. get { return bufferPos == bufferSize && !RefillBuffer(false); }
  1416. }
  1417. /// <summary>
  1418. /// Called when buffer is empty to read more bytes from the
  1419. /// input. If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that
  1420. /// either there will be at least one byte in the buffer when it returns
  1421. /// or it will throw an exception. If <paramref name="mustSucceed"/> is false,
  1422. /// RefillBuffer() returns false if no more bytes were available.
  1423. /// </summary>
  1424. /// <param name="mustSucceed"></param>
  1425. /// <returns></returns>
  1426. private bool RefillBuffer(bool mustSucceed)
  1427. {
  1428. if (bufferPos < bufferSize)
  1429. {
  1430. throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");
  1431. }
  1432. if (totalBytesRetired + bufferSize == currentLimit)
  1433. {
  1434. // Oops, we hit a limit.
  1435. if (mustSucceed)
  1436. {
  1437. throw InvalidProtocolBufferException.TruncatedMessage();
  1438. }
  1439. else
  1440. {
  1441. return false;
  1442. }
  1443. }
  1444. totalBytesRetired += bufferSize;
  1445. bufferPos = 0;
  1446. bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);
  1447. if (bufferSize < 0)
  1448. {
  1449. throw new InvalidOperationException("Stream.Read returned a negative count");
  1450. }
  1451. if (bufferSize == 0)
  1452. {
  1453. if (mustSucceed)
  1454. {
  1455. throw InvalidProtocolBufferException.TruncatedMessage();
  1456. }
  1457. else
  1458. {
  1459. return false;
  1460. }
  1461. }
  1462. else
  1463. {
  1464. RecomputeBufferSizeAfterLimit();
  1465. int totalBytesRead =
  1466. totalBytesRetired + bufferSize + bufferSizeAfterLimit;
  1467. if (totalBytesRead > sizeLimit || totalBytesRead < 0)
  1468. {
  1469. throw InvalidProtocolBufferException.SizeLimitExceeded();
  1470. }
  1471. return true;
  1472. }
  1473. }
  1474. /// <summary>
  1475. /// Read one byte from the input.
  1476. /// </summary>
  1477. /// <exception cref="InvalidProtocolBufferException">
  1478. /// the end of the stream or the current limit was reached
  1479. /// </exception>
  1480. public byte ReadRawByte()
  1481. {
  1482. if (bufferPos == bufferSize)
  1483. {
  1484. RefillBuffer(true);
  1485. }
  1486. return buffer[bufferPos++];
  1487. }
  1488. /// <summary>
  1489. /// Read a fixed size of bytes from the input.
  1490. /// </summary>
  1491. /// <exception cref="InvalidProtocolBufferException">
  1492. /// the end of the stream or the current limit was reached
  1493. /// </exception>
  1494. public byte[] ReadRawBytes(int size)
  1495. {
  1496. if (size < 0)
  1497. {
  1498. throw InvalidProtocolBufferException.NegativeSize();
  1499. }
  1500. if (totalBytesRetired + bufferPos + size > currentLimit)
  1501. {
  1502. // Read to the end of the stream anyway.
  1503. SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
  1504. // Then fail.
  1505. throw InvalidProtocolBufferException.TruncatedMessage();
  1506. }
  1507. if (size <= bufferSize - bufferPos)
  1508. {
  1509. // We have all the bytes we need already.
  1510. byte[] bytes = new byte[size];
  1511. ByteArray.Copy(buffer, bufferPos, bytes, 0, size);
  1512. bufferPos += size;
  1513. return bytes;
  1514. }
  1515. else if (size < BufferSize)
  1516. {
  1517. // Reading more bytes than are in the buffer, but not an excessive number
  1518. // of bytes. We can safely allocate the resulting array ahead of time.
  1519. // First copy what we have.
  1520. byte[] bytes = new byte[size];
  1521. int pos = bufferSize - bufferPos;
  1522. ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);
  1523. bufferPos = bufferSize;
  1524. // We want to use RefillBuffer() and then copy from the buffer into our
  1525. // byte array rather than reading directly into our byte array because
  1526. // the input may be unbuffered.
  1527. RefillBuffer(true);
  1528. while (size - pos > bufferSize)
  1529. {
  1530. Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);
  1531. pos += bufferSize;
  1532. bufferPos = bufferSize;
  1533. RefillBuffer(true);
  1534. }
  1535. ByteArray.Copy(buffer, 0, bytes, pos, size - pos);
  1536. bufferPos = size - pos;
  1537. return bytes;
  1538. }
  1539. else
  1540. {
  1541. // The size is very large. For security reasons, we can't allocate the
  1542. // entire byte array yet. The size comes directly from the input, so a
  1543. // maliciously-crafted message could provide a bogus very large size in
  1544. // order to trick the app into allocating a lot of memory. We avoid this
  1545. // by allocating and reading only a small chunk at a time, so that the
  1546. // malicious message must actually *be* extremely large to cause
  1547. // problems. Meanwhile, we limit the allowed size of a message elsewhere.
  1548. // Remember the buffer markers since we'll have to copy the bytes out of
  1549. // it later.
  1550. int originalBufferPos = bufferPos;
  1551. int originalBufferSize = bufferSize;
  1552. // Mark the current buffer consumed.
  1553. totalBytesRetired += bufferSize;
  1554. bufferPos = 0;
  1555. bufferSize = 0;
  1556. // Read all the rest of the bytes we need.
  1557. int sizeLeft = size - (originalBufferSize - originalBufferPos);
  1558. List<byte[]> chunks = new List<byte[]>();
  1559. while (sizeLeft > 0)
  1560. {
  1561. byte[] chunk = new byte[Math.Min(sizeLeft, BufferSize)];
  1562. int pos = 0;
  1563. while (pos < chunk.Length)
  1564. {
  1565. int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);
  1566. if (n <= 0)
  1567. {
  1568. throw InvalidProtocolBufferException.TruncatedMessage();
  1569. }
  1570. totalBytesRetired += n;
  1571. pos += n;
  1572. }
  1573. sizeLeft -= chunk.Length;
  1574. chunks.Add(chunk);
  1575. }
  1576. // OK, got everything. Now concatenate it all into one buffer.
  1577. byte[] bytes = new byte[size];
  1578. // Start by copying the leftover bytes from this.buffer.
  1579. int newPos = originalBufferSize - originalBufferPos;
  1580. ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);
  1581. // And now all the chunks.
  1582. foreach (byte[] chunk in chunks)
  1583. {
  1584. Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);
  1585. newPos += chunk.Length;
  1586. }
  1587. // Done.
  1588. return bytes;
  1589. }
  1590. }
  1591. /// <summary>
  1592. /// Reads and discards a single field, given its tag value.
  1593. /// </summary>
  1594. /// <returns>false if the tag is an end-group tag, in which case
  1595. /// nothing is skipped. Otherwise, returns true.</returns>
  1596. [CLSCompliant(false)]
  1597. public bool SkipField()
  1598. {
  1599. uint tag = lastTag;
  1600. switch (WireFormat.GetTagWireType(tag))
  1601. {
  1602. case WireFormat.WireType.Varint:
  1603. ReadRawVarint64();
  1604. return true;
  1605. case WireFormat.WireType.Fixed64:
  1606. ReadRawLittleEndian64();
  1607. return true;
  1608. case WireFormat.WireType.LengthDelimited:
  1609. SkipRawBytes((int) ReadRawVarint32());
  1610. return true;
  1611. case WireFormat.WireType.StartGroup:
  1612. SkipMessage();
  1613. CheckLastTagWas(
  1614. WireFormat.MakeTag(WireFormat.GetTagFieldNumber(tag),
  1615. WireFormat.WireType.EndGroup));
  1616. return true;
  1617. case WireFormat.WireType.EndGroup:
  1618. return false;
  1619. case WireFormat.WireType.Fixed32:
  1620. ReadRawLittleEndian32();
  1621. return true;
  1622. default:
  1623. throw InvalidProtocolBufferException.InvalidWireType();
  1624. }
  1625. }
  1626. /// <summary>
  1627. /// Reads and discards an entire message. This will read either until EOF
  1628. /// or until an endgroup tag, whichever comes first.
  1629. /// </summary>
  1630. public void SkipMessage()
  1631. {
  1632. uint tag;
  1633. string name;
  1634. while (ReadTag(out tag, out name))
  1635. {
  1636. if (!SkipField())
  1637. {
  1638. return;
  1639. }
  1640. }
  1641. }
  1642. /// <summary>
  1643. /// Reads and discards <paramref name="size"/> bytes.
  1644. /// </summary>
  1645. /// <exception cref="InvalidProtocolBufferException">the end of the stream
  1646. /// or the current limit was reached</exception>
  1647. public void SkipRawBytes(int size)
  1648. {
  1649. if (size < 0)
  1650. {
  1651. throw InvalidProtocolBufferException.NegativeSize();
  1652. }
  1653. if (totalBytesRetired + bufferPos + size > currentLimit)
  1654. {
  1655. // Read to the end of the stream anyway.
  1656. SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
  1657. // Then fail.
  1658. throw InvalidProtocolBufferException.TruncatedMessage();
  1659. }
  1660. if (size <= bufferSize - bufferPos)
  1661. {
  1662. // We have all the bytes we need already.
  1663. bufferPos += size;
  1664. }
  1665. else
  1666. {
  1667. // Skipping more bytes than are in the buffer. First skip what we have.
  1668. int pos = bufferSize - bufferPos;
  1669. totalBytesRetired += pos;
  1670. bufferPos = 0;
  1671. bufferSize = 0;
  1672. // Then skip directly from the InputStream for the rest.
  1673. if (pos < size)
  1674. {
  1675. if (input == null)
  1676. {
  1677. throw InvalidProtocolBufferException.TruncatedMessage();
  1678. }
  1679. SkipImpl(size - pos);
  1680. totalBytesRetired += size - pos;
  1681. }
  1682. }
  1683. }
  1684. /// <summary>
  1685. /// Abstraction of skipping to cope with streams which can't really skip.
  1686. /// </summary>
  1687. private void SkipImpl(int amountToSkip)
  1688. {
  1689. if (input.CanSeek)
  1690. {
  1691. long previousPosition = input.Position;
  1692. input.Position += amountToSkip;
  1693. if (input.Position != previousPosition + amountToSkip)
  1694. {
  1695. throw InvalidProtocolBufferException.TruncatedMessage();
  1696. }
  1697. }
  1698. else
  1699. {
  1700. byte[] skipBuffer = new byte[1024];
  1701. while (amountToSkip > 0)
  1702. {
  1703. int bytesRead = input.Read(skipBuffer, 0, skipBuffer.Length);
  1704. if (bytesRead <= 0)
  1705. {
  1706. throw InvalidProtocolBufferException.TruncatedMessage();
  1707. }
  1708. amountToSkip -= bytesRead;
  1709. }