CodedInputStream.cs 33 KB

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