CodedInputStream.cs 59 KB

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