CodedInputStream.cs 63 KB

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