CodedInputStream.cs 64 KB

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