AbstractReader.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using Google.ProtocolBuffers.Descriptors;
  5. //Disable CS3011: only CLS-compliant members can be abstract
  6. #pragma warning disable 3011
  7. namespace Google.ProtocolBuffers.Serialization
  8. {
  9. /// <summary>
  10. /// Provides a base-class that provides some basic functionality for handling type dispatching
  11. /// </summary>
  12. public abstract class AbstractReader : ICodedInputStream
  13. {
  14. private const int DefaultMaxDepth = 64;
  15. private int _depth;
  16. /// <summary> Constructs a new reader </summary>
  17. protected AbstractReader() { MaxDepth = DefaultMaxDepth; }
  18. /// <summary> Gets or sets the maximum recursion depth allowed </summary>
  19. public int MaxDepth { get; set; }
  20. /// <summary>
  21. /// Merges the contents of stream into the provided message builder
  22. /// </summary>
  23. public TBuilder Merge<TBuilder>(TBuilder builder) where TBuilder : IBuilderLite
  24. {
  25. return Merge(builder, ExtensionRegistry.Empty);
  26. }
  27. /// <summary>
  28. /// Merges the contents of stream into the provided message builder
  29. /// </summary>
  30. public abstract TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)
  31. where TBuilder : IBuilderLite;
  32. /// <summary>
  33. /// Peeks at the next field in the input stream and returns what information is available.
  34. /// </summary>
  35. /// <remarks>
  36. /// This may be called multiple times without actually reading the field. Only after the field
  37. /// is either read, or skipped, should PeekNext return a different value.
  38. /// </remarks>
  39. protected abstract bool PeekNext(out string field);
  40. /// <summary>
  41. /// Causes the reader to skip past this field
  42. /// </summary>
  43. protected abstract void Skip();
  44. /// <summary>
  45. /// Returns true if it was able to read a Boolean from the input
  46. /// </summary>
  47. protected abstract bool Read(ref bool value);
  48. /// <summary>
  49. /// Returns true if it was able to read a Int32 from the input
  50. /// </summary>
  51. protected abstract bool Read(ref int value);
  52. /// <summary>
  53. /// Returns true if it was able to read a UInt32 from the input
  54. /// </summary>
  55. protected abstract bool Read(ref uint value);
  56. /// <summary>
  57. /// Returns true if it was able to read a Int64 from the input
  58. /// </summary>
  59. protected abstract bool Read(ref long value);
  60. /// <summary>
  61. /// Returns true if it was able to read a UInt64 from the input
  62. /// </summary>
  63. protected abstract bool Read(ref ulong value);
  64. /// <summary>
  65. /// Returns true if it was able to read a Single from the input
  66. /// </summary>
  67. protected abstract bool Read(ref float value);
  68. /// <summary>
  69. /// Returns true if it was able to read a Double from the input
  70. /// </summary>
  71. protected abstract bool Read(ref double value);
  72. /// <summary>
  73. /// Returns true if it was able to read a String from the input
  74. /// </summary>
  75. protected abstract bool Read(ref string value);
  76. /// <summary>
  77. /// Returns true if it was able to read a ByteString from the input
  78. /// </summary>
  79. protected abstract bool Read(ref ByteString value);
  80. /// <summary>
  81. /// returns true if it was able to read a single value into the value reference. The value
  82. /// stored may be of type System.String, System.Int32, or an IEnumLite from the IEnumLiteMap.
  83. /// </summary>
  84. protected abstract bool ReadEnum(ref object value);
  85. /// <summary>
  86. /// Merges the input stream into the provided IBuilderLite
  87. /// </summary>
  88. protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry);
  89. /// <summary>
  90. /// Reads the root-message preamble specific to this formatter
  91. /// </summary>
  92. public abstract void ReadMessageStart();
  93. /// <summary>
  94. /// Reads the root-message close specific to this formatter
  95. /// </summary>
  96. public abstract void ReadMessageEnd();
  97. /// <summary>
  98. /// Merges the input stream into the provided IBuilderLite
  99. /// </summary>
  100. public virtual bool ReadGroup(IBuilderLite value, ExtensionRegistry registry)
  101. {
  102. return ReadMessage(value, registry);
  103. }
  104. /// <summary>
  105. /// Cursors through the array elements and stops at the end of the array
  106. /// </summary>
  107. protected virtual IEnumerable<string> ForeachArrayItem(string field)
  108. {
  109. string next = field;
  110. while (true)
  111. {
  112. yield return next;
  113. if (!PeekNext(out next) || next != field)
  114. {
  115. break;
  116. }
  117. }
  118. }
  119. /// <summary>
  120. /// Reads an array of T messages
  121. /// </summary>
  122. public virtual bool ReadMessageArray<T>(string field, ICollection<T> items, IMessageLite messageType,
  123. ExtensionRegistry registry)
  124. {
  125. bool success = false;
  126. foreach (string next in ForeachArrayItem(field))
  127. {
  128. IBuilderLite builder = messageType.WeakCreateBuilderForType();
  129. if (ReadMessage(builder, registry))
  130. {
  131. items.Add((T) builder.WeakBuild());
  132. success |= true;
  133. }
  134. }
  135. return success;
  136. }
  137. /// <summary>
  138. /// Reads an array of T messages as a proto-buffer group
  139. /// </summary>
  140. public virtual bool ReadGroupArray<T>(string field, ICollection<T> items, IMessageLite messageType,
  141. ExtensionRegistry registry)
  142. {
  143. bool success = false;
  144. foreach (string next in ForeachArrayItem(field))
  145. {
  146. IBuilderLite builder = messageType.WeakCreateBuilderForType();
  147. if (ReadGroup(builder, registry))
  148. {
  149. items.Add((T) builder.WeakBuild());
  150. success |= true;
  151. }
  152. }
  153. return success;
  154. }
  155. /// <summary>
  156. /// Reads an array of System.Enum type T and adds them to the collection
  157. /// </summary>
  158. public virtual bool ReadEnumArray(string field, ICollection<object> items)
  159. {
  160. bool success = false;
  161. foreach (string next in ForeachArrayItem(field))
  162. {
  163. object temp = null;
  164. if (ReadEnum(ref temp))
  165. {
  166. items.Add(temp);
  167. success |= true;
  168. }
  169. }
  170. return success;
  171. }
  172. /// <summary>
  173. /// Reads an array of T, where T is a primitive type defined by FieldType
  174. /// </summary>
  175. public virtual bool ReadArray<T>(FieldType type, string field, ICollection<T> items)
  176. {
  177. bool success = false;
  178. foreach (string next in ForeachArrayItem(field))
  179. {
  180. object temp = null;
  181. if (ReadField(type, ref temp))
  182. {
  183. items.Add((T) temp);
  184. success |= true;
  185. }
  186. }
  187. return success;
  188. }
  189. /// <summary>
  190. /// returns true if it was able to read a single primitive value of FieldType into the value reference
  191. /// </summary>
  192. public virtual bool ReadField(FieldType type, ref object value)
  193. {
  194. switch (type)
  195. {
  196. case FieldType.Bool:
  197. {
  198. bool temp = false;
  199. if (Read(ref temp))
  200. {
  201. value = temp;
  202. }
  203. else
  204. {
  205. return false;
  206. }
  207. break;
  208. }
  209. case FieldType.Int64:
  210. case FieldType.SInt64:
  211. case FieldType.SFixed64:
  212. {
  213. long temp = 0;
  214. if (Read(ref temp))
  215. {
  216. value = temp;
  217. }
  218. else
  219. {
  220. return false;
  221. }
  222. break;
  223. }
  224. case FieldType.UInt64:
  225. case FieldType.Fixed64:
  226. {
  227. ulong temp = 0;
  228. if (Read(ref temp))
  229. {
  230. value = temp;
  231. }
  232. else
  233. {
  234. return false;
  235. }
  236. break;
  237. }
  238. case FieldType.Int32:
  239. case FieldType.SInt32:
  240. case FieldType.SFixed32:
  241. {
  242. int temp = 0;
  243. if (Read(ref temp))
  244. {
  245. value = temp;
  246. }
  247. else
  248. {
  249. return false;
  250. }
  251. break;
  252. }
  253. case FieldType.UInt32:
  254. case FieldType.Fixed32:
  255. {
  256. uint temp = 0;
  257. if (Read(ref temp))
  258. {
  259. value = temp;
  260. }
  261. else
  262. {
  263. return false;
  264. }
  265. break;
  266. }
  267. case FieldType.Float:
  268. {
  269. float temp = float.NaN;
  270. if (Read(ref temp))
  271. {
  272. value = temp;
  273. }
  274. else
  275. {
  276. return false;
  277. }
  278. break;
  279. }
  280. case FieldType.Double:
  281. {
  282. double temp = float.NaN;
  283. if (Read(ref temp))
  284. {
  285. value = temp;
  286. }
  287. else
  288. {
  289. return false;
  290. }
  291. break;
  292. }
  293. case FieldType.String:
  294. {
  295. string temp = null;
  296. if (Read(ref temp))
  297. {
  298. value = temp;
  299. }
  300. else
  301. {
  302. return false;
  303. }
  304. break;
  305. }
  306. case FieldType.Bytes:
  307. {
  308. ByteString temp = null;
  309. if (Read(ref temp))
  310. {
  311. value = temp;
  312. }
  313. else
  314. {
  315. return false;
  316. }
  317. break;
  318. }
  319. default:
  320. throw InvalidProtocolBufferException.InvalidTag();
  321. }
  322. return true;
  323. }
  324. #region ICodedInputStream Members
  325. bool ICodedInputStream.ReadTag(out uint fieldTag, out string fieldName)
  326. {
  327. fieldTag = 0;
  328. if (PeekNext(out fieldName))
  329. {
  330. return true;
  331. }
  332. return false;
  333. }
  334. bool ICodedInputStream.ReadDouble(ref double value)
  335. {
  336. return Read(ref value);
  337. }
  338. bool ICodedInputStream.ReadFloat(ref float value)
  339. {
  340. return Read(ref value);
  341. }
  342. bool ICodedInputStream.ReadUInt64(ref ulong value)
  343. {
  344. return Read(ref value);
  345. }
  346. bool ICodedInputStream.ReadInt64(ref long value)
  347. {
  348. return Read(ref value);
  349. }
  350. bool ICodedInputStream.ReadInt32(ref int value)
  351. {
  352. return Read(ref value);
  353. }
  354. bool ICodedInputStream.ReadFixed64(ref ulong value)
  355. {
  356. return Read(ref value);
  357. }
  358. bool ICodedInputStream.ReadFixed32(ref uint value)
  359. {
  360. return Read(ref value);
  361. }
  362. bool ICodedInputStream.ReadBool(ref bool value)
  363. {
  364. return Read(ref value);
  365. }
  366. bool ICodedInputStream.ReadString(ref string value)
  367. {
  368. return Read(ref value);
  369. }
  370. void ICodedInputStream.ReadGroup(int fieldNumber, IBuilderLite builder, ExtensionRegistry extensionRegistry)
  371. {
  372. if (_depth++ > MaxDepth)
  373. {
  374. throw new RecursionLimitExceededException();
  375. }
  376. ReadGroup(builder, extensionRegistry);
  377. _depth--;
  378. }
  379. void ICodedInputStream.ReadUnknownGroup(int fieldNumber, IBuilderLite builder)
  380. {
  381. throw new NotSupportedException();
  382. }
  383. void ICodedInputStream.ReadMessage(IBuilderLite builder, ExtensionRegistry extensionRegistry)
  384. {
  385. if (_depth++ > MaxDepth)
  386. {
  387. throw new RecursionLimitExceededException();
  388. }
  389. ReadMessage(builder, extensionRegistry);
  390. _depth--;
  391. }
  392. bool ICodedInputStream.ReadBytes(ref ByteString value)
  393. {
  394. return Read(ref value);
  395. }
  396. bool ICodedInputStream.ReadUInt32(ref uint value)
  397. {
  398. return Read(ref value);
  399. }
  400. bool ICodedInputStream.ReadEnum(ref IEnumLite value, out object unknown, IEnumLiteMap mapping)
  401. {
  402. value = null;
  403. unknown = null;
  404. if (ReadEnum(ref unknown))
  405. {
  406. if (unknown is int)
  407. {
  408. value = mapping.FindValueByNumber((int) unknown);
  409. }
  410. else if (unknown is string)
  411. {
  412. value = mapping.FindValueByName((string) unknown);
  413. }
  414. return value != null;
  415. }
  416. return false;
  417. }
  418. bool ICodedInputStream.ReadEnum<T>(ref T value, out object rawValue)
  419. {
  420. rawValue = null;
  421. if (ReadEnum(ref rawValue))
  422. {
  423. if (!EnumParser<T>.TryConvert(rawValue, ref value))
  424. {
  425. value = default(T);
  426. return false;
  427. }
  428. return true;
  429. }
  430. return false;
  431. }
  432. bool ICodedInputStream.ReadSFixed32(ref int value)
  433. {
  434. return Read(ref value);
  435. }
  436. bool ICodedInputStream.ReadSFixed64(ref long value)
  437. {
  438. return Read(ref value);
  439. }
  440. bool ICodedInputStream.ReadSInt32(ref int value)
  441. {
  442. return Read(ref value);
  443. }
  444. bool ICodedInputStream.ReadSInt64(ref long value)
  445. {
  446. return Read(ref value);
  447. }
  448. void ICodedInputStream.ReadPrimitiveArray(FieldType fieldType, uint fieldTag, string fieldName,
  449. ICollection<object> list)
  450. {
  451. ReadArray(fieldType, fieldName, list);
  452. }
  453. void ICodedInputStream.ReadEnumArray(uint fieldTag, string fieldName, ICollection<IEnumLite> list,
  454. out ICollection<object> unknown, IEnumLiteMap mapping)
  455. {
  456. unknown = null;
  457. List<object> array = new List<object>();
  458. if (ReadEnumArray(fieldName, array))
  459. {
  460. foreach (object rawValue in array)
  461. {
  462. IEnumLite item = null;
  463. if (rawValue is int)
  464. {
  465. item = mapping.FindValueByNumber((int) rawValue);
  466. }
  467. else if (rawValue is string)
  468. {
  469. item = mapping.FindValueByName((string) rawValue);
  470. }
  471. if (item != null)
  472. {
  473. list.Add(item);
  474. }
  475. else
  476. {
  477. if (unknown == null)
  478. {
  479. unknown = new List<object>();
  480. }
  481. unknown.Add(rawValue);
  482. }
  483. }
  484. }
  485. }
  486. void ICodedInputStream.ReadEnumArray<T>(uint fieldTag, string fieldName, ICollection<T> list,
  487. out ICollection<object> unknown)
  488. {
  489. unknown = null;
  490. List<object> array = new List<object>();
  491. if (ReadEnumArray(fieldName, array))
  492. {
  493. foreach (object rawValue in array)
  494. {
  495. T val = default(T);
  496. if (EnumParser<T>.TryConvert(rawValue, ref val))
  497. {
  498. list.Add(val);
  499. }
  500. else
  501. {
  502. if (unknown == null)
  503. {
  504. unknown = new List<object>();
  505. }
  506. unknown.Add(rawValue);
  507. }
  508. }
  509. }
  510. }
  511. void ICodedInputStream.ReadMessageArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType,
  512. ExtensionRegistry registry)
  513. {
  514. if (_depth++ > MaxDepth)
  515. {
  516. throw new RecursionLimitExceededException();
  517. }
  518. ReadMessageArray(fieldName, list, messageType, registry);
  519. _depth--;
  520. }
  521. void ICodedInputStream.ReadGroupArray<T>(uint fieldTag, string fieldName, ICollection<T> list, T messageType,
  522. ExtensionRegistry registry)
  523. {
  524. if (_depth++ > MaxDepth)
  525. {
  526. throw new RecursionLimitExceededException();
  527. }
  528. ReadGroupArray(fieldName, list, messageType, registry);
  529. _depth--;
  530. }
  531. bool ICodedInputStream.ReadPrimitiveField(FieldType fieldType, ref object value)
  532. {
  533. return ReadField(fieldType, ref value);
  534. }
  535. bool ICodedInputStream.IsAtEnd
  536. {
  537. get
  538. {
  539. string next;
  540. return PeekNext(out next) == false;
  541. }
  542. }
  543. bool ICodedInputStream.SkipField()
  544. {
  545. Skip();
  546. return true;
  547. }
  548. void ICodedInputStream.ReadStringArray(uint fieldTag, string fieldName, ICollection<string> list)
  549. {
  550. ReadArray(FieldType.String, fieldName, list);
  551. }
  552. void ICodedInputStream.ReadBytesArray(uint fieldTag, string fieldName, ICollection<ByteString> list)
  553. {
  554. ReadArray(FieldType.Bytes, fieldName, list);
  555. }
  556. void ICodedInputStream.ReadBoolArray(uint fieldTag, string fieldName, ICollection<bool> list)
  557. {
  558. ReadArray(FieldType.Bool, fieldName, list);
  559. }
  560. void ICodedInputStream.ReadInt32Array(uint fieldTag, string fieldName, ICollection<int> list)
  561. {
  562. ReadArray(FieldType.Int32, fieldName, list);
  563. }
  564. void ICodedInputStream.ReadSInt32Array(uint fieldTag, string fieldName, ICollection<int> list)
  565. {
  566. ReadArray(FieldType.SInt32, fieldName, list);
  567. }
  568. void ICodedInputStream.ReadUInt32Array(uint fieldTag, string fieldName, ICollection<uint> list)
  569. {
  570. ReadArray(FieldType.UInt32, fieldName, list);
  571. }
  572. void ICodedInputStream.ReadFixed32Array(uint fieldTag, string fieldName, ICollection<uint> list)
  573. {
  574. ReadArray(FieldType.Fixed32, fieldName, list);
  575. }
  576. void ICodedInputStream.ReadSFixed32Array(uint fieldTag, string fieldName, ICollection<int> list)
  577. {
  578. ReadArray(FieldType.SFixed32, fieldName, list);
  579. }
  580. void ICodedInputStream.ReadInt64Array(uint fieldTag, string fieldName, ICollection<long> list)
  581. {
  582. ReadArray(FieldType.Int64, fieldName, list);
  583. }
  584. void ICodedInputStream.ReadSInt64Array(uint fieldTag, string fieldName, ICollection<long> list)
  585. {
  586. ReadArray(FieldType.SInt64, fieldName, list);
  587. }
  588. void ICodedInputStream.ReadUInt64Array(uint fieldTag, string fieldName, ICollection<ulong> list)
  589. {
  590. ReadArray(FieldType.UInt64, fieldName, list);
  591. }
  592. void ICodedInputStream.ReadFixed64Array(uint fieldTag, string fieldName, ICollection<ulong> list)
  593. {
  594. ReadArray(FieldType.Fixed64, fieldName, list);
  595. }
  596. void ICodedInputStream.ReadSFixed64Array(uint fieldTag, string fieldName, ICollection<long> list)
  597. {
  598. ReadArray(FieldType.SFixed64, fieldName, list);
  599. }
  600. void ICodedInputStream.ReadDoubleArray(uint fieldTag, string fieldName, ICollection<double> list)
  601. {
  602. ReadArray(FieldType.Double, fieldName, list);
  603. }
  604. void ICodedInputStream.ReadFloatArray(uint fieldTag, string fieldName, ICollection<float> list)
  605. {
  606. ReadArray(FieldType.Float, fieldName, list);
  607. }
  608. #endregion
  609. }
  610. }