CodedInputStream.cs 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // https://developers.google.com/protocol-buffers/
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. #endregion
  32. using Google.Protobuf.Collections;
  33. using System;
  34. using System.Collections.Generic;
  35. using System.IO;
  36. namespace Google.Protobuf
  37. {
  38. /// <summary>
  39. /// Reads and decodes protocol message fields.
  40. /// </summary>
  41. /// <remarks>
  42. /// <para>
  43. /// This class is generally used by generated code to read appropriate
  44. /// primitives from the stream. It effectively encapsulates the lowest
  45. /// levels of protocol buffer format.
  46. /// </para>
  47. /// <para>
  48. /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>
  49. /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.
  50. /// </para>
  51. /// </remarks>
  52. public sealed class CodedInputStream : IDisposable
  53. {
  54. /// <summary>
  55. /// Whether to leave the underlying stream open when disposing of this stream.
  56. /// This is always true when there's no stream.
  57. /// </summary>
  58. private readonly bool leaveOpen;
  59. /// <summary>
  60. /// Buffer of data read from the stream or provided at construction time.
  61. /// </summary>
  62. private readonly byte[] buffer;
  63. /// <summary>
  64. /// The index of the buffer at which we need to refill from the stream (if there is one).
  65. /// </summary>
  66. private int bufferSize;
  67. private int bufferSizeAfterLimit = 0;
  68. /// <summary>
  69. /// The position within the current buffer (i.e. the next byte to read)
  70. /// </summary>
  71. private int bufferPos = 0;
  72. /// <summary>
  73. /// The stream to read further input from, or null if the byte array buffer was provided
  74. /// directly on construction, with no further data available.
  75. /// </summary>
  76. private readonly Stream input;
  77. /// <summary>
  78. /// The last tag we read. 0 indicates we've read to the end of the stream
  79. /// (or haven't read anything yet).
  80. /// </summary>
  81. private uint lastTag = 0;
  82. /// <summary>
  83. /// The next tag, used to store the value read by PeekTag.
  84. /// </summary>
  85. private uint nextTag = 0;
  86. private bool hasNextTag = false;
  87. internal const int DefaultRecursionLimit = 100;
  88. internal const int DefaultSizeLimit = Int32.MaxValue;
  89. internal const int BufferSize = 4096;
  90. /// <summary>
  91. /// The total number of bytes read before the current buffer. The
  92. /// total bytes read up to the current position can be computed as
  93. /// totalBytesRetired + bufferPos.
  94. /// </summary>
  95. private int totalBytesRetired = 0;
  96. /// <summary>
  97. /// The absolute position of the end of the current message.
  98. /// </summary>
  99. private int currentLimit = int.MaxValue;
  100. private int recursionDepth = 0;
  101. private readonly int recursionLimit;
  102. private readonly int sizeLimit;
  103. #region Construction
  104. // Note that the checks are performed such that we don't end up checking obviously-valid things
  105. // like non-null references for arrays we've just created.
  106. /// <summary>
  107. /// Creates a new CodedInputStream reading data from the given byte array.
  108. /// </summary>
  109. public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, true)
  110. {
  111. }
  112. /// <summary>
  113. /// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice.
  114. /// </summary>
  115. public CodedInputStream(byte[] buffer, int offset, int length)
  116. : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, true)
  117. {
  118. if (offset < 0 || offset > buffer.Length)
  119. {
  120. throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
  121. }
  122. if (length < 0 || offset + length > buffer.Length)
  123. {
  124. throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
  125. }
  126. }
  127. /// <summary>
  128. /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed
  129. /// when the returned object is disposed.
  130. /// </summary>
  131. /// <param name="input">The stream to read from.</param>
  132. public CodedInputStream(Stream input) : this(input, false)
  133. {
  134. }
  135. /// <summary>
  136. /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream.
  137. /// </summary>
  138. /// <param name="input">The stream to read from.</param>
  139. /// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned
  140. /// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when the
  141. /// returned object is disposed.</param>
  142. public CodedInputStream(Stream input, bool leaveOpen)
  143. : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0, leaveOpen)
  144. {
  145. }
  146. /// <summary>
  147. /// Creates a new CodedInputStream reading data from the given
  148. /// stream and buffer, using the default limits.
  149. /// </summary>
  150. internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen)
  151. {
  152. this.input = input;
  153. this.buffer = buffer;
  154. this.bufferPos = bufferPos;
  155. this.bufferSize = bufferSize;
  156. this.sizeLimit = DefaultSizeLimit;
  157. this.recursionLimit = DefaultRecursionLimit;
  158. this.leaveOpen = leaveOpen;
  159. }
  160. /// <summary>
  161. /// Creates a new CodedInputStream reading data from the given
  162. /// stream and buffer, using the specified limits.
  163. /// </summary>
  164. /// <remarks>
  165. /// This chains to the version with the default limits instead of vice versa to avoid
  166. /// having to check that the default values are valid every time.
  167. /// </remarks>
  168. internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen)
  169. : this(input, buffer, bufferPos, bufferSize, leaveOpen)
  170. {
  171. if (sizeLimit <= 0)
  172. {
  173. throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");
  174. }
  175. if (recursionLimit <= 0)
  176. {
  177. throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");
  178. }
  179. this.sizeLimit = sizeLimit;
  180. this.recursionLimit = recursionLimit;
  181. }
  182. #endregion
  183. /// <summary>
  184. /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading
  185. /// from an input stream.
  186. /// </summary>
  187. /// <remarks>
  188. /// This method exists separately from the constructor to reduce the number of constructor overloads.
  189. /// It is likely to be used considerably less frequently than the constructors, as the default limits
  190. /// are suitable for most use cases.
  191. /// </remarks>
  192. /// <param name="input">The input stream to read from</param>
  193. /// <param name="sizeLimit">The total limit of data to read from the stream.</param>
  194. /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>
  195. /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size
  196. /// and recursion limits.</returns>
  197. public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)
  198. {
  199. // Note: we may want an overload accepting leaveOpen
  200. return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit, false);
  201. }
  202. /// <summary>
  203. /// Returns the current position in the input stream, or the position in the input buffer
  204. /// </summary>
  205. public long Position
  206. {
  207. get
  208. {
  209. if (input != null)
  210. {
  211. return input.Position - ((bufferSize + bufferSizeAfterLimit) - bufferPos);
  212. }
  213. return bufferPos;
  214. }
  215. }
  216. /// <summary>
  217. /// Returns the last tag read, or 0 if no tags have been read or we've read beyond
  218. /// the end of the stream.
  219. /// </summary>
  220. internal uint LastTag { get { return lastTag; } }
  221. /// <summary>
  222. /// Returns the size limit for this stream.
  223. /// </summary>
  224. /// <remarks>
  225. /// This limit is applied when reading from the underlying stream, as a sanity check. It is
  226. /// not applied when reading from a byte array data source without an underlying stream.
  227. /// The default value is Int32.MaxValue.
  228. /// </remarks>
  229. /// <value>
  230. /// The size limit.
  231. /// </value>
  232. public int SizeLimit { get { return sizeLimit; } }
  233. /// <summary>
  234. /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,
  235. /// to avoid maliciously-recursive data.
  236. /// </summary>
  237. /// <remarks>
  238. /// The default limit is 100.
  239. /// </remarks>
  240. /// <value>
  241. /// The recursion limit for this stream.
  242. /// </value>
  243. public int RecursionLimit { get { return recursionLimit; } }
  244. /// <summary>
  245. /// Internal-only property; when set to true, unknown fields will be discarded while parsing.
  246. /// </summary>
  247. internal bool DiscardUnknownFields { get; set; }
  248. /// <summary>
  249. /// Internal-only property; provides extension identifiers to compatible messages while parsing.
  250. /// </summary>
  251. internal ExtensionRegistry ExtensionRegistry { get; set; }
  252. /// <summary>
  253. /// Disposes of this instance, potentially closing any underlying stream.
  254. /// </summary>
  255. /// <remarks>
  256. /// As there is no flushing to perform here, disposing of a <see cref="CodedInputStream"/> which
  257. /// was constructed with the <c>leaveOpen</c> option parameter set to <c>true</c> (or one which
  258. /// was constructed to read from a byte array) has no effect.
  259. /// </remarks>
  260. public void Dispose()
  261. {
  262. if (!leaveOpen)
  263. {
  264. input.Dispose();
  265. }
  266. }
  267. #region Validation
  268. /// <summary>
  269. /// Verifies that the last call to ReadTag() returned tag 0 - in other words,
  270. /// we've reached the end of the stream when we expected to.
  271. /// </summary>
  272. /// <exception cref="InvalidProtocolBufferException">The
  273. /// tag read was not the one specified</exception>
  274. internal void CheckReadEndOfStreamTag()
  275. {
  276. if (lastTag != 0)
  277. {
  278. throw InvalidProtocolBufferException.MoreDataAvailable();
  279. }
  280. }
  281. #endregion
  282. #region Reading of tags etc
  283. /// <summary>
  284. /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the
  285. /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the
  286. /// same value.)
  287. /// </summary>
  288. public uint PeekTag()
  289. {
  290. if (hasNextTag)
  291. {
  292. return nextTag;
  293. }
  294. uint savedLast = lastTag;
  295. nextTag = ReadTag();
  296. hasNextTag = true;
  297. lastTag = savedLast; // Undo the side effect of ReadTag
  298. return nextTag;
  299. }
  300. /// <summary>
  301. /// Reads a field tag, returning the tag of 0 for "end of stream".
  302. /// </summary>
  303. /// <remarks>
  304. /// If this method returns 0, it doesn't necessarily mean the end of all
  305. /// the data in this CodedInputStream; it may be the end of the logical stream
  306. /// for an embedded message, for example.
  307. /// </remarks>
  308. /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>
  309. public uint ReadTag()
  310. {
  311. if (hasNextTag)
  312. {
  313. lastTag = nextTag;
  314. hasNextTag = false;
  315. return lastTag;
  316. }
  317. // Optimize for the incredibly common case of having at least two bytes left in the buffer,
  318. // and those two bytes being enough to get the tag. This will be true for fields up to 4095.
  319. if (bufferPos + 2 <= bufferSize)
  320. {
  321. int tmp = buffer[bufferPos++];
  322. if (tmp < 128)
  323. {
  324. lastTag = (uint)tmp;
  325. }
  326. else
  327. {
  328. int result = tmp & 0x7f;
  329. if ((tmp = buffer[bufferPos++]) < 128)
  330. {
  331. result |= tmp << 7;
  332. lastTag = (uint) result;
  333. }
  334. else
  335. {
  336. // Nope, rewind and go the potentially slow route.
  337. bufferPos -= 2;
  338. lastTag = ReadRawVarint32();
  339. }
  340. }
  341. }
  342. else
  343. {
  344. if (IsAtEnd)
  345. {
  346. lastTag = 0;
  347. return 0;
  348. }
  349. lastTag = ReadRawVarint32();
  350. }
  351. if (WireFormat.GetTagFieldNumber(lastTag) == 0)
  352. {
  353. // If we actually read a tag with a field of 0, that's not a valid tag.
  354. throw InvalidProtocolBufferException.InvalidTag();
  355. }
  356. if (ReachedLimit)
  357. {
  358. return 0;
  359. }
  360. return lastTag;
  361. }
  362. /// <summary>
  363. /// Skips the data for the field with the tag we've just read.
  364. /// This should be called directly after <see cref="ReadTag"/>, when
  365. /// the caller wishes to skip an unknown field.
  366. /// </summary>
  367. /// <remarks>
  368. /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.
  369. /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the
  370. /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly
  371. /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.
  372. /// </remarks>
  373. /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>
  374. /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>
  375. public void SkipLastField()
  376. {
  377. if (lastTag == 0)
  378. {
  379. throw new InvalidOperationException("SkipLastField cannot be called at the end of a stream");
  380. }
  381. switch (WireFormat.GetTagWireType(lastTag))
  382. {
  383. case WireFormat.WireType.StartGroup:
  384. SkipGroup(lastTag);
  385. break;
  386. case WireFormat.WireType.EndGroup:
  387. throw new InvalidProtocolBufferException(
  388. "SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing");
  389. case WireFormat.WireType.Fixed32:
  390. ReadFixed32();
  391. break;
  392. case WireFormat.WireType.Fixed64:
  393. ReadFixed64();
  394. break;
  395. case WireFormat.WireType.LengthDelimited:
  396. var length = ReadLength();
  397. SkipRawBytes(length);
  398. break;
  399. case WireFormat.WireType.Varint:
  400. ReadRawVarint32();
  401. break;
  402. }
  403. }
  404. /// <summary>
  405. /// Skip a group.
  406. /// </summary>
  407. internal void SkipGroup(uint startGroupTag)
  408. {
  409. // Note: Currently we expect this to be the way that groups are read. We could put the recursion
  410. // depth changes into the ReadTag method instead, potentially...
  411. recursionDepth++;
  412. if (recursionDepth >= recursionLimit)
  413. {
  414. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  415. }
  416. uint tag;
  417. while (true)
  418. {
  419. tag = ReadTag();
  420. if (tag == 0)
  421. {
  422. throw InvalidProtocolBufferException.TruncatedMessage();
  423. }
  424. // Can't call SkipLastField for this case- that would throw.
  425. if (WireFormat.GetTagWireType(tag) == WireFormat.WireType.EndGroup)
  426. {
  427. break;
  428. }
  429. // This recursion will allow us to handle nested groups.
  430. SkipLastField();
  431. }
  432. int startField = WireFormat.GetTagFieldNumber(startGroupTag);
  433. int endField = WireFormat.GetTagFieldNumber(tag);
  434. if (startField != endField)
  435. {
  436. throw new InvalidProtocolBufferException(
  437. $"Mismatched end-group tag. Started with field {startField}; ended with field {endField}");
  438. }
  439. recursionDepth--;
  440. }
  441. /// <summary>
  442. /// Reads a double field from the stream.
  443. /// </summary>
  444. public double ReadDouble()
  445. {
  446. if (bufferPos + 8 <= bufferSize)
  447. {
  448. if (BitConverter.IsLittleEndian)
  449. {
  450. var result = BitConverter.ToDouble(buffer, bufferPos);
  451. bufferPos += 8;
  452. return result;
  453. }
  454. else
  455. {
  456. var bytes = new byte[8];
  457. bytes[0] = buffer[bufferPos + 7];
  458. bytes[1] = buffer[bufferPos + 6];
  459. bytes[2] = buffer[bufferPos + 5];
  460. bytes[3] = buffer[bufferPos + 4];
  461. bytes[4] = buffer[bufferPos + 3];
  462. bytes[5] = buffer[bufferPos + 2];
  463. bytes[6] = buffer[bufferPos + 1];
  464. bytes[7] = buffer[bufferPos];
  465. bufferPos += 8;
  466. return BitConverter.ToDouble(bytes, 0);
  467. }
  468. }
  469. else
  470. {
  471. return BitConverter.Int64BitsToDouble((long)ReadRawLittleEndian64());
  472. }
  473. }
  474. /// <summary>
  475. /// Reads a float field from the stream.
  476. /// </summary>
  477. public float ReadFloat()
  478. {
  479. if (BitConverter.IsLittleEndian && 4 <= bufferSize - bufferPos)
  480. {
  481. float ret = BitConverter.ToSingle(buffer, bufferPos);
  482. bufferPos += 4;
  483. return ret;
  484. }
  485. else
  486. {
  487. byte[] rawBytes = ReadRawBytes(4);
  488. if (!BitConverter.IsLittleEndian)
  489. {
  490. ByteArray.Reverse(rawBytes);
  491. }
  492. return BitConverter.ToSingle(rawBytes, 0);
  493. }
  494. }
  495. /// <summary>
  496. /// Reads a uint64 field from the stream.
  497. /// </summary>
  498. public ulong ReadUInt64()
  499. {
  500. return ReadRawVarint64();
  501. }
  502. /// <summary>
  503. /// Reads an int64 field from the stream.
  504. /// </summary>
  505. public long ReadInt64()
  506. {
  507. return (long) ReadRawVarint64();
  508. }
  509. /// <summary>
  510. /// Reads an int32 field from the stream.
  511. /// </summary>
  512. public int ReadInt32()
  513. {
  514. return (int) ReadRawVarint32();
  515. }
  516. /// <summary>
  517. /// Reads a fixed64 field from the stream.
  518. /// </summary>
  519. public ulong ReadFixed64()
  520. {
  521. return ReadRawLittleEndian64();
  522. }
  523. /// <summary>
  524. /// Reads a fixed32 field from the stream.
  525. /// </summary>
  526. public uint ReadFixed32()
  527. {
  528. return ReadRawLittleEndian32();
  529. }
  530. /// <summary>
  531. /// Reads a bool field from the stream.
  532. /// </summary>
  533. public bool ReadBool()
  534. {
  535. return ReadRawVarint32() != 0;
  536. }
  537. /// <summary>
  538. /// Reads a string field from the stream.
  539. /// </summary>
  540. public string ReadString()
  541. {
  542. int length = ReadLength();
  543. // No need to read any data for an empty string.
  544. if (length == 0)
  545. {
  546. return "";
  547. }
  548. if (length <= bufferSize - bufferPos && length > 0)
  549. {
  550. // Fast path: We already have the bytes in a contiguous buffer, so
  551. // just copy directly from it.
  552. String result = CodedOutputStream.Utf8Encoding.GetString(buffer, bufferPos, length);
  553. bufferPos += length;
  554. return result;
  555. }
  556. // Slow path: Build a byte array first then copy it.
  557. return CodedOutputStream.Utf8Encoding.GetString(ReadRawBytes(length), 0, length);
  558. }
  559. /// <summary>
  560. /// Reads an embedded message field value from the stream.
  561. /// </summary>
  562. public void ReadMessage(IMessage builder)
  563. {
  564. int length = ReadLength();
  565. if (recursionDepth >= recursionLimit)
  566. {
  567. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  568. }
  569. int oldLimit = PushLimit(length);
  570. ++recursionDepth;
  571. builder.MergeFrom(this);
  572. CheckReadEndOfStreamTag();
  573. // Check that we've read exactly as much data as expected.
  574. if (!ReachedLimit)
  575. {
  576. throw InvalidProtocolBufferException.TruncatedMessage();
  577. }
  578. --recursionDepth;
  579. PopLimit(oldLimit);
  580. }
  581. /// <summary>
  582. /// Reads an embedded group field from the stream.
  583. /// </summary>
  584. public void ReadGroup(IMessage builder)
  585. {
  586. if (recursionDepth >= recursionLimit)
  587. {
  588. throw InvalidProtocolBufferException.RecursionLimitExceeded();
  589. }
  590. ++recursionDepth;
  591. builder.MergeFrom(this);
  592. --recursionDepth;
  593. }
  594. /// <summary>
  595. /// Reads a bytes field value from the stream.
  596. /// </summary>
  597. public ByteString ReadBytes()
  598. {
  599. int length = ReadLength();
  600. if (length <= bufferSize - bufferPos && length > 0)
  601. {
  602. // Fast path: We already have the bytes in a contiguous buffer, so
  603. // just copy directly from it.
  604. ByteString result = ByteString.CopyFrom(buffer, bufferPos, length);
  605. bufferPos += length;
  606. return result;
  607. }
  608. else
  609. {
  610. // Slow path: Build a byte array and attach it to a new ByteString.
  611. return ByteString.AttachBytes(ReadRawBytes(length));
  612. }
  613. }
  614. /// <summary>
  615. /// Reads a uint32 field value from the stream.
  616. /// </summary>
  617. public uint ReadUInt32()
  618. {
  619. return ReadRawVarint32();
  620. }
  621. /// <summary>
  622. /// Reads an enum field value from the stream.
  623. /// </summary>
  624. public int ReadEnum()
  625. {
  626. // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
  627. return (int) ReadRawVarint32();
  628. }
  629. /// <summary>
  630. /// Reads an sfixed32 field value from the stream.
  631. /// </summary>
  632. public int ReadSFixed32()
  633. {
  634. return (int) ReadRawLittleEndian32();
  635. }
  636. /// <summary>
  637. /// Reads an sfixed64 field value from the stream.
  638. /// </summary>
  639. public long ReadSFixed64()
  640. {
  641. return (long) ReadRawLittleEndian64();
  642. }
  643. /// <summary>
  644. /// Reads an sint32 field value from the stream.
  645. /// </summary>
  646. public int ReadSInt32()
  647. {
  648. return DecodeZigZag32(ReadRawVarint32());
  649. }
  650. /// <summary>
  651. /// Reads an sint64 field value from the stream.
  652. /// </summary>
  653. public long ReadSInt64()
  654. {
  655. return DecodeZigZag64(ReadRawVarint64());
  656. }
  657. /// <summary>
  658. /// Reads a length for length-delimited data.
  659. /// </summary>
  660. /// <remarks>
  661. /// This is internally just reading a varint, but this method exists
  662. /// to make the calling code clearer.
  663. /// </remarks>
  664. public int ReadLength()
  665. {
  666. return (int) ReadRawVarint32();
  667. }
  668. /// <summary>
  669. /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
  670. /// the tag is consumed and the method returns <c>true</c>; otherwise, the
  671. /// stream is left in the original position and the method returns <c>false</c>.
  672. /// </summary>
  673. public bool MaybeConsumeTag(uint tag)
  674. {
  675. if (PeekTag() == tag)
  676. {
  677. hasNextTag = false;
  678. return true;
  679. }
  680. return false;
  681. }
  682. internal static float? ReadFloatWrapperLittleEndian(CodedInputStream input)
  683. {
  684. // length:1 + tag:1 + value:4 = 6 bytes
  685. if (input.bufferPos + 6 <= input.bufferSize)
  686. {
  687. // The entire wrapper message is already contained in `buffer`.
  688. int length = input.buffer[input.bufferPos];
  689. if (length == 0)
  690. {
  691. input.bufferPos++;
  692. return 0F;
  693. }
  694. // tag:1 + value:4 = length of 5 bytes
  695. // field=1, type=32-bit = tag of 13
  696. if (length != 5 || input.buffer[input.bufferPos + 1] != 13)
  697. {
  698. return ReadFloatWrapperSlow(input);
  699. }
  700. var result = BitConverter.ToSingle(input.buffer, input.bufferPos + 2);
  701. input.bufferPos += 6;
  702. return result;
  703. }
  704. else
  705. {
  706. return ReadFloatWrapperSlow(input);
  707. }
  708. }
  709. internal static float? ReadFloatWrapperSlow(CodedInputStream input)
  710. {
  711. int length = input.ReadLength();
  712. if (length == 0)
  713. {
  714. return 0F;
  715. }
  716. int finalBufferPos = input.totalBytesRetired + input.bufferPos + length;
  717. float result = 0F;
  718. do
  719. {
  720. // field=1, type=32-bit = tag of 13
  721. if (input.ReadTag() == 13)
  722. {
  723. result = input.ReadFloat();
  724. }
  725. else
  726. {
  727. input.SkipLastField();
  728. }
  729. }
  730. while (input.totalBytesRetired + input.bufferPos < finalBufferPos);
  731. return result;
  732. }
  733. internal static double? ReadDoubleWrapperLittleEndian(CodedInputStream input)
  734. {
  735. // length:1 + tag:1 + value:8 = 10 bytes
  736. if (input.bufferPos + 10 <= input.bufferSize)
  737. {
  738. // The entire wrapper message is already contained in `buffer`.
  739. int length = input.buffer[input.bufferPos];
  740. if (length == 0)
  741. {
  742. input.bufferPos++;
  743. return 0D;
  744. }
  745. // tag:1 + value:8 = length of 9 bytes
  746. // field=1, type=64-bit = tag of 9
  747. if (length != 9 || input.buffer[input.bufferPos + 1] != 9)
  748. {
  749. return ReadDoubleWrapperSlow(input);
  750. }
  751. var result = BitConverter.ToDouble(input.buffer, input.bufferPos + 2);
  752. input.bufferPos += 10;
  753. return result;
  754. }
  755. else
  756. {
  757. return ReadDoubleWrapperSlow(input);
  758. }
  759. }
  760. internal static double? ReadDoubleWrapperSlow(CodedInputStream input)
  761. {
  762. int length = input.ReadLength();
  763. if (length == 0)
  764. {
  765. return 0D;
  766. }
  767. int finalBufferPos = input.totalBytesRetired + input.bufferPos + length;
  768. double result = 0D;
  769. do
  770. {
  771. // field=1, type=64-bit = tag of 9
  772. if (input.ReadTag() == 9)
  773. {
  774. result = input.ReadDouble();
  775. }
  776. else
  777. {
  778. input.SkipLastField();
  779. }
  780. }
  781. while (input.totalBytesRetired + input.bufferPos < finalBufferPos);
  782. return result;
  783. }
  784. internal static bool? ReadBoolWrapper(CodedInputStream input)
  785. {
  786. return ReadUInt32Wrapper(input) != 0;
  787. }
  788. internal static uint? ReadUInt32Wrapper(CodedInputStream input)
  789. {
  790. // length:1 + tag:1 + value:5(varint32-max) = 7 bytes
  791. if (input.bufferPos + 7 <= input.bufferSize)
  792. {
  793. // The entire wrapper message is already contained in `buffer`.
  794. int pos0 = input.bufferPos;
  795. int length = input.buffer[input.bufferPos++];
  796. if (length == 0)
  797. {
  798. return 0;
  799. }
  800. // Length will always fit in a single byte.
  801. if (length >= 128)
  802. {
  803. input.bufferPos = pos0;
  804. return ReadUInt32WrapperSlow(input);
  805. }
  806. int finalBufferPos = input.bufferPos + length;
  807. // field=1, type=varint = tag of 8
  808. if (input.buffer[input.bufferPos++] != 8)
  809. {
  810. input.bufferPos = pos0;
  811. return ReadUInt32WrapperSlow(input);
  812. }
  813. var result = input.ReadUInt32();
  814. // Verify this message only contained a single field.
  815. if (input.bufferPos != finalBufferPos)
  816. {
  817. input.bufferPos = pos0;
  818. return ReadUInt32WrapperSlow(input);
  819. }
  820. return result;
  821. }
  822. else
  823. {
  824. return ReadUInt32WrapperSlow(input);
  825. }
  826. }
  827. private static uint? ReadUInt32WrapperSlow(CodedInputStream input)
  828. {
  829. int length = input.ReadLength();
  830. if (length == 0)
  831. {
  832. return 0;
  833. }
  834. int finalBufferPos = input.totalBytesRetired + input.bufferPos + length;
  835. uint result = 0;
  836. do
  837. {
  838. // field=1, type=varint = tag of 8
  839. if (input.ReadTag() == 8)
  840. {
  841. result = input.ReadUInt32();
  842. }
  843. else
  844. {
  845. input.SkipLastField();
  846. }
  847. }
  848. while (input.totalBytesRetired + input.bufferPos < finalBufferPos);
  849. return result;
  850. }
  851. internal static int? ReadInt32Wrapper(CodedInputStream input)
  852. {
  853. return (int?)ReadUInt32Wrapper(input);
  854. }
  855. internal static ulong? ReadUInt64Wrapper(CodedInputStream input)
  856. {
  857. // field=1, type=varint = tag of 8
  858. const int expectedTag = 8;
  859. // length:1 + tag:1 + value:10(varint64-max) = 12 bytes
  860. if (input.bufferPos + 12 <= input.bufferSize)
  861. {
  862. // The entire wrapper message is already contained in `buffer`.
  863. int pos0 = input.bufferPos;
  864. int length = input.buffer[input.bufferPos++];
  865. if (length == 0)
  866. {
  867. return 0L;
  868. }
  869. // Length will always fit in a single byte.
  870. if (length >= 128)
  871. {
  872. input.bufferPos = pos0;
  873. return ReadUInt64WrapperSlow(input);
  874. }
  875. int finalBufferPos = input.bufferPos + length;
  876. if (input.buffer[input.bufferPos++] != expectedTag)
  877. {
  878. input.bufferPos = pos0;
  879. return ReadUInt64WrapperSlow(input);
  880. }
  881. var result = input.ReadUInt64();
  882. // Verify this message only contained a single field.
  883. if (input.bufferPos != finalBufferPos)
  884. {
  885. input.bufferPos = pos0;
  886. return ReadUInt64WrapperSlow(input);
  887. }
  888. return result;
  889. }
  890. else
  891. {
  892. return ReadUInt64WrapperSlow(input);
  893. }
  894. }
  895. internal static ulong? ReadUInt64WrapperSlow(CodedInputStream input)
  896. {
  897. // field=1, type=varint = tag of 8
  898. const int expectedTag = 8;
  899. int length = input.ReadLength();
  900. if (length == 0)
  901. {
  902. return 0L;
  903. }
  904. int finalBufferPos = input.totalBytesRetired + input.bufferPos + length;
  905. ulong result = 0L;
  906. do
  907. {
  908. if (input.ReadTag() == expectedTag)
  909. {
  910. result = input.ReadUInt64();
  911. }
  912. else
  913. {
  914. input.SkipLastField();
  915. }
  916. }
  917. while (input.totalBytesRetired + input.bufferPos < finalBufferPos);
  918. return result;
  919. }
  920. internal static long? ReadInt64Wrapper(CodedInputStream input)
  921. {
  922. return (long?)ReadUInt64Wrapper(input);
  923. }
  924. #endregion
  925. #region Underlying reading primitives
  926. /// <summary>
  927. /// Same code as ReadRawVarint32, but read each byte individually, checking for
  928. /// buffer overflow.
  929. /// </summary>
  930. private uint SlowReadRawVarint32()
  931. {
  932. int tmp = ReadRawByte();
  933. if (tmp < 128)
  934. {
  935. return (uint) tmp;
  936. }
  937. int result = tmp & 0x7f;
  938. if ((tmp = ReadRawByte()) < 128)
  939. {
  940. result |= tmp << 7;
  941. }
  942. else
  943. {
  944. result |= (tmp & 0x7f) << 7;
  945. if ((tmp = ReadRawByte()) < 128)
  946. {
  947. result |= tmp << 14;
  948. }
  949. else
  950. {
  951. result |= (tmp & 0x7f) << 14;
  952. if ((tmp = ReadRawByte()) < 128)
  953. {
  954. result |= tmp << 21;
  955. }
  956. else
  957. {
  958. result |= (tmp & 0x7f) << 21;
  959. result |= (tmp = ReadRawByte()) << 28;
  960. if (tmp >= 128)
  961. {
  962. // Discard upper 32 bits.
  963. for (int i = 0; i < 5; i++)
  964. {
  965. if (ReadRawByte() < 128)
  966. {
  967. return (uint) result;
  968. }
  969. }
  970. throw InvalidProtocolBufferException.MalformedVarint();
  971. }
  972. }
  973. }
  974. }
  975. return (uint) result;
  976. }
  977. /// <summary>
  978. /// Reads a raw Varint from the stream. If larger than 32 bits, discard the upper bits.
  979. /// This method is optimised for the case where we've got lots of data in the buffer.
  980. /// That means we can check the size just once, then just read directly from the buffer
  981. /// without constant rechecking of the buffer length.
  982. /// </summary>
  983. internal uint ReadRawVarint32()
  984. {
  985. if (bufferPos + 5 > bufferSize)
  986. {
  987. return SlowReadRawVarint32();
  988. }
  989. int tmp = buffer[bufferPos++];
  990. if (tmp < 128)
  991. {
  992. return (uint) tmp;
  993. }
  994. int result = tmp & 0x7f;
  995. if ((tmp = buffer[bufferPos++]) < 128)
  996. {
  997. result |= tmp << 7;
  998. }
  999. else
  1000. {
  1001. result |= (tmp & 0x7f) << 7;
  1002. if ((tmp = buffer[bufferPos++]) < 128)
  1003. {
  1004. result |= tmp << 14;
  1005. }
  1006. else
  1007. {
  1008. result |= (tmp & 0x7f) << 14;
  1009. if ((tmp = buffer[bufferPos++]) < 128)
  1010. {
  1011. result |= tmp << 21;
  1012. }
  1013. else
  1014. {
  1015. result |= (tmp & 0x7f) << 21;
  1016. result |= (tmp = buffer[bufferPos++]) << 28;
  1017. if (tmp >= 128)
  1018. {
  1019. // Discard upper 32 bits.
  1020. // Note that this has to use ReadRawByte() as we only ensure we've
  1021. // got at least 5 bytes at the start of the method. This lets us
  1022. // use the fast path in more cases, and we rarely hit this section of code.
  1023. for (int i = 0; i < 5; i++)
  1024. {
  1025. if (ReadRawByte() < 128)
  1026. {
  1027. return (uint) result;
  1028. }
  1029. }
  1030. throw InvalidProtocolBufferException.MalformedVarint();
  1031. }
  1032. }
  1033. }
  1034. }
  1035. return (uint) result;
  1036. }
  1037. /// <summary>
  1038. /// Reads a varint from the input one byte at a time, so that it does not
  1039. /// read any bytes after the end of the varint. If you simply wrapped the
  1040. /// stream in a CodedInputStream and used ReadRawVarint32(Stream)
  1041. /// then you would probably end up reading past the end of the varint since
  1042. /// CodedInputStream buffers its input.
  1043. /// </summary>
  1044. /// <param name="input"></param>
  1045. /// <returns></returns>
  1046. internal static uint ReadRawVarint32(Stream input)
  1047. {
  1048. int result = 0;
  1049. int offset = 0;
  1050. for (; offset < 32; offset += 7)
  1051. {
  1052. int b = input.ReadByte();
  1053. if (b == -1)
  1054. {
  1055. throw InvalidProtocolBufferException.TruncatedMessage();
  1056. }
  1057. result |= (b & 0x7f) << offset;
  1058. if ((b & 0x80) == 0)
  1059. {
  1060. return (uint) result;
  1061. }
  1062. }
  1063. // Keep reading up to 64 bits.
  1064. for (; offset < 64; offset += 7)
  1065. {
  1066. int b = input.ReadByte();
  1067. if (b == -1)
  1068. {
  1069. throw InvalidProtocolBufferException.TruncatedMessage();
  1070. }
  1071. if ((b & 0x80) == 0)
  1072. {
  1073. return (uint) result;
  1074. }
  1075. }
  1076. throw InvalidProtocolBufferException.MalformedVarint();
  1077. }
  1078. /// <summary>
  1079. /// Reads a raw varint from the stream.
  1080. /// </summary>
  1081. internal ulong ReadRawVarint64()
  1082. {
  1083. if (bufferPos + 10 <= bufferSize)
  1084. {
  1085. ulong result = buffer[bufferPos++];
  1086. if (result < 128)
  1087. {
  1088. return result;
  1089. }
  1090. result &= 0x7f;
  1091. int shift = 7;
  1092. do
  1093. {
  1094. byte b = buffer[bufferPos++];
  1095. result |= (ulong)(b & 0x7F) << shift;
  1096. if (b < 0x80)
  1097. {
  1098. return result;
  1099. }
  1100. shift += 7;
  1101. }
  1102. while (shift < 64);
  1103. }
  1104. else
  1105. {
  1106. int shift = 0;
  1107. ulong result = 0;
  1108. do
  1109. {
  1110. byte b = ReadRawByte();
  1111. result |= (ulong)(b & 0x7F) << shift;
  1112. if (b < 0x80)
  1113. {
  1114. return result;
  1115. }
  1116. shift += 7;
  1117. }
  1118. while (shift < 64);
  1119. }
  1120. throw InvalidProtocolBufferException.MalformedVarint();
  1121. }
  1122. /// <summary>
  1123. /// Reads a 32-bit little-endian integer from the stream.
  1124. /// </summary>
  1125. internal uint ReadRawLittleEndian32()
  1126. {
  1127. if (bufferPos + 4 <= bufferSize)
  1128. {
  1129. if (BitConverter.IsLittleEndian)
  1130. {
  1131. var result = BitConverter.ToUInt32(buffer, bufferPos);
  1132. bufferPos += 4;
  1133. return result;
  1134. }
  1135. else
  1136. {
  1137. uint b1 = buffer[bufferPos];
  1138. uint b2 = buffer[bufferPos + 1];
  1139. uint b3 = buffer[bufferPos + 2];
  1140. uint b4 = buffer[bufferPos + 3];
  1141. bufferPos += 4;
  1142. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
  1143. }
  1144. }
  1145. else
  1146. {
  1147. uint b1 = ReadRawByte();
  1148. uint b2 = ReadRawByte();
  1149. uint b3 = ReadRawByte();
  1150. uint b4 = ReadRawByte();
  1151. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
  1152. }
  1153. }
  1154. /// <summary>
  1155. /// Reads a 64-bit little-endian integer from the stream.
  1156. /// </summary>
  1157. internal ulong ReadRawLittleEndian64()
  1158. {
  1159. if (bufferPos + 8 <= bufferSize)
  1160. {
  1161. if (BitConverter.IsLittleEndian)
  1162. {
  1163. var result = BitConverter.ToUInt64(buffer, bufferPos);
  1164. bufferPos += 8;
  1165. return result;
  1166. }
  1167. else
  1168. {
  1169. ulong b1 = buffer[bufferPos];
  1170. ulong b2 = buffer[bufferPos + 1];
  1171. ulong b3 = buffer[bufferPos + 2];
  1172. ulong b4 = buffer[bufferPos + 3];
  1173. ulong b5 = buffer[bufferPos + 4];
  1174. ulong b6 = buffer[bufferPos + 5];
  1175. ulong b7 = buffer[bufferPos + 6];
  1176. ulong b8 = buffer[bufferPos + 7];
  1177. bufferPos += 8;
  1178. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
  1179. | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
  1180. }
  1181. }
  1182. else
  1183. {
  1184. ulong b1 = ReadRawByte();
  1185. ulong b2 = ReadRawByte();
  1186. ulong b3 = ReadRawByte();
  1187. ulong b4 = ReadRawByte();
  1188. ulong b5 = ReadRawByte();
  1189. ulong b6 = ReadRawByte();
  1190. ulong b7 = ReadRawByte();
  1191. ulong b8 = ReadRawByte();
  1192. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24)
  1193. | (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
  1194. }
  1195. }
  1196. /// <summary>
  1197. /// Decode a 32-bit value with ZigZag encoding.
  1198. /// </summary>
  1199. /// <remarks>
  1200. /// ZigZag encodes signed integers into values that can be efficiently
  1201. /// encoded with varint. (Otherwise, negative values must be
  1202. /// sign-extended to 64 bits to be varint encoded, thus always taking
  1203. /// 10 bytes on the wire.)
  1204. /// </remarks>
  1205. internal static int DecodeZigZag32(uint n)
  1206. {
  1207. return (int)(n >> 1) ^ -(int)(n & 1);
  1208. }
  1209. /// <summary>
  1210. /// Decode a 32-bit value with ZigZag encoding.
  1211. /// </summary>
  1212. /// <remarks>
  1213. /// ZigZag encodes signed integers into values that can be efficiently
  1214. /// encoded with varint. (Otherwise, negative values must be
  1215. /// sign-extended to 64 bits to be varint encoded, thus always taking
  1216. /// 10 bytes on the wire.)
  1217. /// </remarks>
  1218. internal static long DecodeZigZag64(ulong n)
  1219. {
  1220. return (long)(n >> 1) ^ -(long)(n & 1);
  1221. }
  1222. #endregion
  1223. #region Internal reading and buffer management
  1224. /// <summary>
  1225. /// Sets currentLimit to (current position) + byteLimit. This is called
  1226. /// when descending into a length-delimited embedded message. The previous
  1227. /// limit is returned.
  1228. /// </summary>
  1229. /// <returns>The old limit.</returns>
  1230. internal int PushLimit(int byteLimit)
  1231. {
  1232. if (byteLimit < 0)
  1233. {
  1234. throw InvalidProtocolBufferException.NegativeSize();
  1235. }
  1236. byteLimit += totalBytesRetired + bufferPos;
  1237. int oldLimit = currentLimit;
  1238. if (byteLimit > oldLimit)
  1239. {
  1240. throw InvalidProtocolBufferException.TruncatedMessage();
  1241. }
  1242. currentLimit = byteLimit;
  1243. RecomputeBufferSizeAfterLimit();
  1244. return oldLimit;
  1245. }
  1246. private void RecomputeBufferSizeAfterLimit()
  1247. {
  1248. bufferSize += bufferSizeAfterLimit;
  1249. int bufferEnd = totalBytesRetired + bufferSize;
  1250. if (bufferEnd > currentLimit)
  1251. {
  1252. // Limit is in current buffer.
  1253. bufferSizeAfterLimit = bufferEnd - currentLimit;
  1254. bufferSize -= bufferSizeAfterLimit;
  1255. }
  1256. else
  1257. {
  1258. bufferSizeAfterLimit = 0;
  1259. }
  1260. }
  1261. /// <summary>
  1262. /// Discards the current limit, returning the previous limit.
  1263. /// </summary>
  1264. internal void PopLimit(int oldLimit)
  1265. {
  1266. currentLimit = oldLimit;
  1267. RecomputeBufferSizeAfterLimit();
  1268. }
  1269. /// <summary>
  1270. /// Returns whether or not all the data before the limit has been read.
  1271. /// </summary>
  1272. /// <returns></returns>
  1273. internal bool ReachedLimit
  1274. {
  1275. get
  1276. {
  1277. if (currentLimit == int.MaxValue)
  1278. {
  1279. return false;
  1280. }
  1281. int currentAbsolutePosition = totalBytesRetired + bufferPos;
  1282. return currentAbsolutePosition >= currentLimit;
  1283. }
  1284. }
  1285. /// <summary>
  1286. /// Returns true if the stream has reached the end of the input. This is the
  1287. /// case if either the end of the underlying input source has been reached or
  1288. /// the stream has reached a limit created using PushLimit.
  1289. /// </summary>
  1290. public bool IsAtEnd
  1291. {
  1292. get { return bufferPos == bufferSize && !RefillBuffer(false); }
  1293. }
  1294. /// <summary>
  1295. /// Called when buffer is empty to read more bytes from the
  1296. /// input. If <paramref name="mustSucceed"/> is true, RefillBuffer() gurantees that
  1297. /// either there will be at least one byte in the buffer when it returns
  1298. /// or it will throw an exception. If <paramref name="mustSucceed"/> is false,
  1299. /// RefillBuffer() returns false if no more bytes were available.
  1300. /// </summary>
  1301. /// <param name="mustSucceed"></param>
  1302. /// <returns></returns>
  1303. private bool RefillBuffer(bool mustSucceed)
  1304. {
  1305. if (bufferPos < bufferSize)
  1306. {
  1307. throw new InvalidOperationException("RefillBuffer() called when buffer wasn't empty.");
  1308. }
  1309. if (totalBytesRetired + bufferSize == currentLimit)
  1310. {
  1311. // Oops, we hit a limit.
  1312. if (mustSucceed)
  1313. {
  1314. throw InvalidProtocolBufferException.TruncatedMessage();
  1315. }
  1316. else
  1317. {
  1318. return false;
  1319. }
  1320. }
  1321. totalBytesRetired += bufferSize;
  1322. bufferPos = 0;
  1323. bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);
  1324. if (bufferSize < 0)
  1325. {
  1326. throw new InvalidOperationException("Stream.Read returned a negative count");
  1327. }
  1328. if (bufferSize == 0)
  1329. {
  1330. if (mustSucceed)
  1331. {
  1332. throw InvalidProtocolBufferException.TruncatedMessage();
  1333. }
  1334. else
  1335. {
  1336. return false;
  1337. }
  1338. }
  1339. else
  1340. {
  1341. RecomputeBufferSizeAfterLimit();
  1342. int totalBytesRead =
  1343. totalBytesRetired + bufferSize + bufferSizeAfterLimit;
  1344. if (totalBytesRead < 0 || totalBytesRead > sizeLimit)
  1345. {
  1346. throw InvalidProtocolBufferException.SizeLimitExceeded();
  1347. }
  1348. return true;
  1349. }
  1350. }
  1351. /// <summary>
  1352. /// Read one byte from the input.
  1353. /// </summary>
  1354. /// <exception cref="InvalidProtocolBufferException">
  1355. /// the end of the stream or the current limit was reached
  1356. /// </exception>
  1357. internal byte ReadRawByte()
  1358. {
  1359. if (bufferPos == bufferSize)
  1360. {
  1361. RefillBuffer(true);
  1362. }
  1363. return buffer[bufferPos++];
  1364. }
  1365. /// <summary>
  1366. /// Reads a fixed size of bytes from the input.
  1367. /// </summary>
  1368. /// <exception cref="InvalidProtocolBufferException">
  1369. /// the end of the stream or the current limit was reached
  1370. /// </exception>
  1371. internal byte[] ReadRawBytes(int size)
  1372. {
  1373. if (size < 0)
  1374. {
  1375. throw InvalidProtocolBufferException.NegativeSize();
  1376. }
  1377. if (totalBytesRetired + bufferPos + size > currentLimit)
  1378. {
  1379. // Read to the end of the stream (up to the current limit) anyway.
  1380. SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
  1381. // Then fail.
  1382. throw InvalidProtocolBufferException.TruncatedMessage();
  1383. }
  1384. if (size <= bufferSize - bufferPos)
  1385. {
  1386. // We have all the bytes we need already.
  1387. byte[] bytes = new byte[size];
  1388. ByteArray.Copy(buffer, bufferPos, bytes, 0, size);
  1389. bufferPos += size;
  1390. return bytes;
  1391. }
  1392. else if (size < buffer.Length)
  1393. {
  1394. // Reading more bytes than are in the buffer, but not an excessive number
  1395. // of bytes. We can safely allocate the resulting array ahead of time.
  1396. // First copy what we have.
  1397. byte[] bytes = new byte[size];
  1398. int pos = bufferSize - bufferPos;
  1399. ByteArray.Copy(buffer, bufferPos, bytes, 0, pos);
  1400. bufferPos = bufferSize;
  1401. // We want to use RefillBuffer() and then copy from the buffer into our
  1402. // byte array rather than reading directly into our byte array because
  1403. // the input may be unbuffered.
  1404. RefillBuffer(true);
  1405. while (size - pos > bufferSize)
  1406. {
  1407. Buffer.BlockCopy(buffer, 0, bytes, pos, bufferSize);
  1408. pos += bufferSize;
  1409. bufferPos = bufferSize;
  1410. RefillBuffer(true);
  1411. }
  1412. ByteArray.Copy(buffer, 0, bytes, pos, size - pos);
  1413. bufferPos = size - pos;
  1414. return bytes;
  1415. }
  1416. else
  1417. {
  1418. // The size is very large. For security reasons, we can't allocate the
  1419. // entire byte array yet. The size comes directly from the input, so a
  1420. // maliciously-crafted message could provide a bogus very large size in
  1421. // order to trick the app into allocating a lot of memory. We avoid this
  1422. // by allocating and reading only a small chunk at a time, so that the
  1423. // malicious message must actually *be* extremely large to cause
  1424. // problems. Meanwhile, we limit the allowed size of a message elsewhere.
  1425. // Remember the buffer markers since we'll have to copy the bytes out of
  1426. // it later.
  1427. int originalBufferPos = bufferPos;
  1428. int originalBufferSize = bufferSize;
  1429. // Mark the current buffer consumed.
  1430. totalBytesRetired += bufferSize;
  1431. bufferPos = 0;
  1432. bufferSize = 0;
  1433. // Read all the rest of the bytes we need.
  1434. int sizeLeft = size - (originalBufferSize - originalBufferPos);
  1435. List<byte[]> chunks = new List<byte[]>();
  1436. while (sizeLeft > 0)
  1437. {
  1438. byte[] chunk = new byte[Math.Min(sizeLeft, buffer.Length)];
  1439. int pos = 0;
  1440. while (pos < chunk.Length)
  1441. {
  1442. int n = (input == null) ? -1 : input.Read(chunk, pos, chunk.Length - pos);
  1443. if (n <= 0)
  1444. {
  1445. throw InvalidProtocolBufferException.TruncatedMessage();
  1446. }
  1447. totalBytesRetired += n;
  1448. pos += n;
  1449. }
  1450. sizeLeft -= chunk.Length;
  1451. chunks.Add(chunk);
  1452. }
  1453. // OK, got everything. Now concatenate it all into one buffer.
  1454. byte[] bytes = new byte[size];
  1455. // Start by copying the leftover bytes from this.buffer.
  1456. int newPos = originalBufferSize - originalBufferPos;
  1457. ByteArray.Copy(buffer, originalBufferPos, bytes, 0, newPos);
  1458. // And now all the chunks.
  1459. foreach (byte[] chunk in chunks)
  1460. {
  1461. Buffer.BlockCopy(chunk, 0, bytes, newPos, chunk.Length);
  1462. newPos += chunk.Length;
  1463. }
  1464. // Done.
  1465. return bytes;
  1466. }
  1467. }
  1468. /// <summary>
  1469. /// Reads and discards <paramref name="size"/> bytes.
  1470. /// </summary>
  1471. /// <exception cref="InvalidProtocolBufferException">the end of the stream
  1472. /// or the current limit was reached</exception>
  1473. private void SkipRawBytes(int size)
  1474. {
  1475. if (size < 0)
  1476. {
  1477. throw InvalidProtocolBufferException.NegativeSize();
  1478. }
  1479. if (totalBytesRetired + bufferPos + size > currentLimit)
  1480. {
  1481. // Read to the end of the stream anyway.
  1482. SkipRawBytes(currentLimit - totalBytesRetired - bufferPos);
  1483. // Then fail.
  1484. throw InvalidProtocolBufferException.TruncatedMessage();
  1485. }
  1486. if (size <= bufferSize - bufferPos)
  1487. {
  1488. // We have all the bytes we need already.
  1489. bufferPos += size;
  1490. }
  1491. else
  1492. {
  1493. // Skipping more bytes than are in the buffer. First skip what we have.
  1494. int pos = bufferSize - bufferPos;
  1495. // ROK 5/7/2013 Issue #54: should retire all bytes in buffer (bufferSize)
  1496. // totalBytesRetired += pos;
  1497. totalBytesRetired += bufferSize;
  1498. bufferPos = 0;
  1499. bufferSize = 0;
  1500. // Then skip directly from the InputStream for the rest.
  1501. if (pos < size)
  1502. {
  1503. if (input == null)
  1504. {
  1505. throw InvalidProtocolBufferException.TruncatedMessage();
  1506. }
  1507. SkipImpl(size - pos);
  1508. totalBytesRetired += size - pos;
  1509. }
  1510. }
  1511. }
  1512. /// <summary>
  1513. /// Abstraction of skipping to cope with streams which can't really skip.
  1514. /// </summary>
  1515. private void SkipImpl(int amountToSkip)
  1516. {
  1517. if (input.CanSeek)
  1518. {
  1519. long previousPosition = input.Position;
  1520. input.Position += amountToSkip;
  1521. if (input.Position != previousPosition + amountToSkip)
  1522. {
  1523. throw InvalidProtocolBufferException.TruncatedMessage();
  1524. }
  1525. }
  1526. else
  1527. {
  1528. byte[] skipBuffer = new byte[Math.Min(1024, amountToSkip)];
  1529. while (amountToSkip > 0)
  1530. {
  1531. int bytesRead = input.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, amountToSkip));
  1532. if (bytesRead <= 0)
  1533. {
  1534. throw InvalidProtocolBufferException.TruncatedMessage();
  1535. }
  1536. amountToSkip -= bytesRead;
  1537. }
  1538. }
  1539. }
  1540. #endregion
  1541. }
  1542. }