MessageParser.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #region Copyright notice and license
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2015 Google Inc. All rights reserved.
  4. // https://developers.google.com/protocol-buffers/
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. #endregion
  32. using System;
  33. using System.Buffers;
  34. using System.IO;
  35. using System.Security;
  36. namespace Google.Protobuf
  37. {
  38. /// <summary>
  39. /// A general message parser, typically used by reflection-based code as all the methods
  40. /// return simple <see cref="IMessage"/>.
  41. /// </summary>
  42. public class MessageParser
  43. {
  44. private Func<IMessage> factory;
  45. // TODO: When we use a C# 7.1 compiler, make this private protected.
  46. internal bool DiscardUnknownFields { get; }
  47. internal ExtensionRegistry Extensions { get; }
  48. internal MessageParser(Func<IMessage> factory, bool discardUnknownFields, ExtensionRegistry extensions)
  49. {
  50. this.factory = factory;
  51. DiscardUnknownFields = discardUnknownFields;
  52. Extensions = extensions;
  53. }
  54. /// <summary>
  55. /// Creates a template instance ready for population.
  56. /// </summary>
  57. /// <returns>An empty message.</returns>
  58. internal IMessage CreateTemplate()
  59. {
  60. return factory();
  61. }
  62. /// <summary>
  63. /// Parses a message from a byte array.
  64. /// </summary>
  65. /// <param name="data">The byte array containing the message. Must not be null.</param>
  66. /// <returns>The newly parsed message.</returns>
  67. public IMessage ParseFrom(byte[] data)
  68. {
  69. IMessage message = factory();
  70. message.MergeFrom(data, DiscardUnknownFields, Extensions);
  71. return message;
  72. }
  73. /// <summary>
  74. /// Parses a message from a byte array slice.
  75. /// </summary>
  76. /// <param name="data">The byte array containing the message. Must not be null.</param>
  77. /// <param name="offset">The offset of the slice to parse.</param>
  78. /// <param name="length">The length of the slice to parse.</param>
  79. /// <returns>The newly parsed message.</returns>
  80. public IMessage ParseFrom(byte[] data, int offset, int length)
  81. {
  82. IMessage message = factory();
  83. message.MergeFrom(data, offset, length, DiscardUnknownFields, Extensions);
  84. return message;
  85. }
  86. /// <summary>
  87. /// Parses a message from the given byte string.
  88. /// </summary>
  89. /// <param name="data">The data to parse.</param>
  90. /// <returns>The parsed message.</returns>
  91. public IMessage ParseFrom(ByteString data)
  92. {
  93. IMessage message = factory();
  94. message.MergeFrom(data, DiscardUnknownFields, Extensions);
  95. return message;
  96. }
  97. /// <summary>
  98. /// Parses a message from the given stream.
  99. /// </summary>
  100. /// <param name="input">The stream to parse.</param>
  101. /// <returns>The parsed message.</returns>
  102. public IMessage ParseFrom(Stream input)
  103. {
  104. IMessage message = factory();
  105. message.MergeFrom(input, DiscardUnknownFields, Extensions);
  106. return message;
  107. }
  108. /// <summary>
  109. /// Parses a message from the given sequence.
  110. /// </summary>
  111. /// <param name="data">The data to parse.</param>
  112. /// <returns>The parsed message.</returns>
  113. [SecuritySafeCritical]
  114. public IMessage ParseFrom(ReadOnlySequence<byte> data)
  115. {
  116. IMessage message = factory();
  117. message.MergeFrom(data, DiscardUnknownFields, Extensions);
  118. return message;
  119. }
  120. /// <summary>
  121. /// Parses a length-delimited message from the given stream.
  122. /// </summary>
  123. /// <remarks>
  124. /// The stream is expected to contain a length and then the data. Only the amount of data
  125. /// specified by the length will be consumed.
  126. /// </remarks>
  127. /// <param name="input">The stream to parse.</param>
  128. /// <returns>The parsed message.</returns>
  129. public IMessage ParseDelimitedFrom(Stream input)
  130. {
  131. IMessage message = factory();
  132. message.MergeDelimitedFrom(input, DiscardUnknownFields, Extensions);
  133. return message;
  134. }
  135. /// <summary>
  136. /// Parses a message from the given coded input stream.
  137. /// </summary>
  138. /// <param name="input">The stream to parse.</param>
  139. /// <returns>The parsed message.</returns>
  140. public IMessage ParseFrom(CodedInputStream input)
  141. {
  142. IMessage message = factory();
  143. MergeFrom(message, input);
  144. return message;
  145. }
  146. /// <summary>
  147. /// Parses a message from the given JSON.
  148. /// </summary>
  149. /// <param name="json">The JSON to parse.</param>
  150. /// <returns>The parsed message.</returns>
  151. /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
  152. /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
  153. public IMessage ParseJson(string json)
  154. {
  155. IMessage message = factory();
  156. JsonParser.Default.Merge(message, json);
  157. return message;
  158. }
  159. // TODO: When we're using a C# 7.1 compiler, make this private protected.
  160. internal void MergeFrom(IMessage message, CodedInputStream codedInput)
  161. {
  162. bool originalDiscard = codedInput.DiscardUnknownFields;
  163. try
  164. {
  165. codedInput.DiscardUnknownFields = DiscardUnknownFields;
  166. message.MergeFrom(codedInput);
  167. }
  168. finally
  169. {
  170. codedInput.DiscardUnknownFields = originalDiscard;
  171. }
  172. }
  173. /// <summary>
  174. /// Creates a new message parser which optionally discards unknown fields when parsing.
  175. /// </summary>
  176. /// <param name="discardUnknownFields">Whether or not to discard unknown fields when parsing.</param>
  177. /// <returns>A newly configured message parser.</returns>
  178. public MessageParser WithDiscardUnknownFields(bool discardUnknownFields) =>
  179. new MessageParser(factory, discardUnknownFields, Extensions);
  180. /// <summary>
  181. /// Creates a new message parser which registers extensions from the specified registry upon creating the message instance
  182. /// </summary>
  183. /// <param name="registry">The extensions to register</param>
  184. /// <returns>A newly configured message parser.</returns>
  185. public MessageParser WithExtensionRegistry(ExtensionRegistry registry) =>
  186. new MessageParser(factory, DiscardUnknownFields, registry);
  187. }
  188. /// <summary>
  189. /// A parser for a specific message type.
  190. /// </summary>
  191. /// <remarks>
  192. /// <p>
  193. /// This delegates most behavior to the
  194. /// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
  195. /// provides convenient overloads to parse from a variety of sources.
  196. /// </p>
  197. /// <p>
  198. /// Most applications will never need to create their own instances of this type;
  199. /// instead, use the static <c>Parser</c> property of a generated message type to obtain a
  200. /// parser for that type.
  201. /// </p>
  202. /// </remarks>
  203. /// <typeparam name="T">The type of message to be parsed.</typeparam>
  204. public sealed class MessageParser<T> : MessageParser where T : IMessage<T>
  205. {
  206. // Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
  207. // The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
  208. // Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
  209. // The API wouldn't change anyway - just the implementation - so this work can be deferred.
  210. private readonly Func<T> factory;
  211. /// <summary>
  212. /// Creates a new parser.
  213. /// </summary>
  214. /// <remarks>
  215. /// The factory method is effectively an optimization over using a generic constraint
  216. /// to require a parameterless constructor: delegates are significantly faster to execute.
  217. /// </remarks>
  218. /// <param name="factory">Function to invoke when a new, empty message is required.</param>
  219. public MessageParser(Func<T> factory) : this(factory, false, null)
  220. {
  221. }
  222. internal MessageParser(Func<T> factory, bool discardUnknownFields, ExtensionRegistry extensions) : base(() => factory(), discardUnknownFields, extensions)
  223. {
  224. this.factory = factory;
  225. }
  226. /// <summary>
  227. /// Creates a template instance ready for population.
  228. /// </summary>
  229. /// <returns>An empty message.</returns>
  230. internal new T CreateTemplate()
  231. {
  232. return factory();
  233. }
  234. /// <summary>
  235. /// Parses a message from a byte array.
  236. /// </summary>
  237. /// <param name="data">The byte array containing the message. Must not be null.</param>
  238. /// <returns>The newly parsed message.</returns>
  239. public new T ParseFrom(byte[] data)
  240. {
  241. T message = factory();
  242. message.MergeFrom(data, DiscardUnknownFields, Extensions);
  243. return message;
  244. }
  245. /// <summary>
  246. /// Parses a message from a byte array slice.
  247. /// </summary>
  248. /// <param name="data">The byte array containing the message. Must not be null.</param>
  249. /// <param name="offset">The offset of the slice to parse.</param>
  250. /// <param name="length">The length of the slice to parse.</param>
  251. /// <returns>The newly parsed message.</returns>
  252. public new T ParseFrom(byte[] data, int offset, int length)
  253. {
  254. T message = factory();
  255. message.MergeFrom(data, offset, length, DiscardUnknownFields, Extensions);
  256. return message;
  257. }
  258. /// <summary>
  259. /// Parses a message from the given byte string.
  260. /// </summary>
  261. /// <param name="data">The data to parse.</param>
  262. /// <returns>The parsed message.</returns>
  263. public new T ParseFrom(ByteString data)
  264. {
  265. T message = factory();
  266. message.MergeFrom(data, DiscardUnknownFields, Extensions);
  267. return message;
  268. }
  269. /// <summary>
  270. /// Parses a message from the given stream.
  271. /// </summary>
  272. /// <param name="input">The stream to parse.</param>
  273. /// <returns>The parsed message.</returns>
  274. public new T ParseFrom(Stream input)
  275. {
  276. T message = factory();
  277. message.MergeFrom(input, DiscardUnknownFields, Extensions);
  278. return message;
  279. }
  280. /// <summary>
  281. /// Parses a message from the given sequence.
  282. /// </summary>
  283. /// <param name="data">The data to parse.</param>
  284. /// <returns>The parsed message.</returns>
  285. [SecuritySafeCritical]
  286. public new T ParseFrom(ReadOnlySequence<byte> data)
  287. {
  288. T message = factory();
  289. message.MergeFrom(data, DiscardUnknownFields, Extensions);
  290. return message;
  291. }
  292. /// <summary>
  293. /// Parses a length-delimited message from the given stream.
  294. /// </summary>
  295. /// <remarks>
  296. /// The stream is expected to contain a length and then the data. Only the amount of data
  297. /// specified by the length will be consumed.
  298. /// </remarks>
  299. /// <param name="input">The stream to parse.</param>
  300. /// <returns>The parsed message.</returns>
  301. public new T ParseDelimitedFrom(Stream input)
  302. {
  303. T message = factory();
  304. message.MergeDelimitedFrom(input, DiscardUnknownFields, Extensions);
  305. return message;
  306. }
  307. /// <summary>
  308. /// Parses a message from the given coded input stream.
  309. /// </summary>
  310. /// <param name="input">The stream to parse.</param>
  311. /// <returns>The parsed message.</returns>
  312. public new T ParseFrom(CodedInputStream input)
  313. {
  314. T message = factory();
  315. MergeFrom(message, input);
  316. return message;
  317. }
  318. /// <summary>
  319. /// Parses a message from the given JSON.
  320. /// </summary>
  321. /// <param name="json">The JSON to parse.</param>
  322. /// <returns>The parsed message.</returns>
  323. /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
  324. /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
  325. public new T ParseJson(string json)
  326. {
  327. T message = factory();
  328. JsonParser.Default.Merge(message, json);
  329. return message;
  330. }
  331. /// <summary>
  332. /// Creates a new message parser which optionally discards unknown fields when parsing.
  333. /// </summary>
  334. /// <param name="discardUnknownFields">Whether or not to discard unknown fields when parsing.</param>
  335. /// <returns>A newly configured message parser.</returns>
  336. public new MessageParser<T> WithDiscardUnknownFields(bool discardUnknownFields) =>
  337. new MessageParser<T>(factory, discardUnknownFields, Extensions);
  338. /// <summary>
  339. /// Creates a new message parser which registers extensions from the specified registry upon creating the message instance
  340. /// </summary>
  341. /// <param name="registry">The extensions to register</param>
  342. /// <returns>A newly configured message parser.</returns>
  343. public new MessageParser<T> WithExtensionRegistry(ExtensionRegistry registry) =>
  344. new MessageParser<T>(factory, DiscardUnknownFields, registry);
  345. }
  346. }