• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc.  All rights reserved.
4 //
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file or at
7 // https://developers.google.com/open-source/licenses/bsd
8 #endregion
9 
10 using System;
11 using System.Buffers;
12 using System.IO;
13 using System.Security;
14 
15 namespace Google.Protobuf
16 {
17     /// <summary>
18     /// A general message parser, typically used by reflection-based code as all the methods
19     /// return simple <see cref="IMessage"/>.
20     /// </summary>
21     public class MessageParser
22     {
23         private readonly Func<IMessage> factory;
24         private protected bool DiscardUnknownFields { get; }
25 
26         internal ExtensionRegistry Extensions { get; }
27 
MessageParser(Func<IMessage> factory, bool discardUnknownFields, ExtensionRegistry extensions)28         internal MessageParser(Func<IMessage> factory, bool discardUnknownFields, ExtensionRegistry extensions)
29         {
30             this.factory = factory;
31             DiscardUnknownFields = discardUnknownFields;
32             Extensions = extensions;
33         }
34 
35         /// <summary>
36         /// Creates a template instance ready for population.
37         /// </summary>
38         /// <returns>An empty message.</returns>
CreateTemplate()39         internal IMessage CreateTemplate()
40         {
41             return factory();
42         }
43 
44         /// <summary>
45         /// Parses a message from a byte array.
46         /// </summary>
47         /// <param name="data">The byte array containing the message. Must not be null.</param>
48         /// <returns>The newly parsed message.</returns>
ParseFrom(byte[] data)49         public IMessage ParseFrom(byte[] data)
50         {
51             IMessage message = factory();
52             message.MergeFrom(data, DiscardUnknownFields, Extensions);
53             return message;
54         }
55 
56         /// <summary>
57         /// Parses a message from a byte array slice.
58         /// </summary>
59         /// <param name="data">The byte array containing the message. Must not be null.</param>
60         /// <param name="offset">The offset of the slice to parse.</param>
61         /// <param name="length">The length of the slice to parse.</param>
62         /// <returns>The newly parsed message.</returns>
ParseFrom(byte[] data, int offset, int length)63         public IMessage ParseFrom(byte[] data, int offset, int length)
64         {
65             IMessage message = factory();
66             message.MergeFrom(data, offset, length, DiscardUnknownFields, Extensions);
67             return message;
68         }
69 
70         /// <summary>
71         /// Parses a message from the given byte string.
72         /// </summary>
73         /// <param name="data">The data to parse.</param>
74         /// <returns>The parsed message.</returns>
ParseFrom(ByteString data)75         public IMessage ParseFrom(ByteString data)
76         {
77             IMessage message = factory();
78             message.MergeFrom(data, DiscardUnknownFields, Extensions);
79             return message;
80         }
81 
82         /// <summary>
83         /// Parses a message from the given stream.
84         /// </summary>
85         /// <param name="input">The stream to parse.</param>
86         /// <returns>The parsed message.</returns>
ParseFrom(Stream input)87         public IMessage ParseFrom(Stream input)
88         {
89             IMessage message = factory();
90             message.MergeFrom(input, DiscardUnknownFields, Extensions);
91             return message;
92         }
93 
94         /// <summary>
95         /// Parses a message from the given sequence.
96         /// </summary>
97         /// <param name="data">The data to parse.</param>
98         /// <returns>The parsed message.</returns>
99         [SecuritySafeCritical]
ParseFrom(ReadOnlySequence<byte> data)100         public IMessage ParseFrom(ReadOnlySequence<byte> data)
101         {
102             IMessage message = factory();
103             message.MergeFrom(data, DiscardUnknownFields, Extensions);
104             return message;
105         }
106 
107         /// <summary>
108         /// Parses a message from the given span.
109         /// </summary>
110         /// <param name="data">The data to parse.</param>
111         /// <returns>The parsed message.</returns>
112         [SecuritySafeCritical]
ParseFrom(ReadOnlySpan<byte> data)113         public IMessage ParseFrom(ReadOnlySpan<byte> data)
114         {
115             IMessage message = factory();
116             message.MergeFrom(data, DiscardUnknownFields, Extensions);
117             return message;
118         }
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>
ParseDelimitedFrom(Stream input)129         public IMessage ParseDelimitedFrom(Stream input)
130         {
131             IMessage message = factory();
132             message.MergeDelimitedFrom(input, DiscardUnknownFields, Extensions);
133             return message;
134         }
135 
136         /// <summary>
137         /// Parses a message from the given coded input stream.
138         /// </summary>
139         /// <param name="input">The stream to parse.</param>
140         /// <returns>The parsed message.</returns>
ParseFrom(CodedInputStream input)141         public IMessage ParseFrom(CodedInputStream input)
142         {
143             IMessage message = factory();
144             MergeFrom(message, input);
145             return message;
146         }
147 
148         /// <summary>
149         /// Parses a message from the given JSON.
150         /// </summary>
151         /// <remarks>This method always uses the default JSON parser; it is not affected by <see cref="WithDiscardUnknownFields(bool)"/>.
152         /// To ignore unknown fields when parsing JSON, create a <see cref="JsonParser"/> using a <see cref="JsonParser.Settings"/>
153         /// with <see cref="JsonParser.Settings.IgnoreUnknownFields"/> set to true and call <see cref="JsonParser.Parse{T}(string)"/> directly.
154         /// </remarks>
155         /// <param name="json">The JSON to parse.</param>
156         /// <returns>The parsed message.</returns>
157         /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
158         /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
ParseJson(string json)159         public IMessage ParseJson(string json)
160         {
161             IMessage message = factory();
162             JsonParser.Default.Merge(message, json);
163             return message;
164         }
165 
166         // TODO: When we're using a C# 7.1 compiler, make this private protected.
MergeFrom(IMessage message, CodedInputStream codedInput)167         internal void MergeFrom(IMessage message, CodedInputStream codedInput)
168         {
169             bool originalDiscard = codedInput.DiscardUnknownFields;
170             ExtensionRegistry originalRegistry = codedInput.ExtensionRegistry;
171             try
172             {
173                 codedInput.DiscardUnknownFields = DiscardUnknownFields;
174                 codedInput.ExtensionRegistry = Extensions;
175                 message.MergeFrom(codedInput);
176             }
177             finally
178             {
179                 codedInput.DiscardUnknownFields = originalDiscard;
180                 codedInput.ExtensionRegistry = originalRegistry;
181             }
182         }
183 
184         /// <summary>
185         /// Creates a new message parser which optionally discards unknown fields when parsing.
186         /// </summary>
187         /// <remarks>Note that this does not affect the behavior of <see cref="ParseJson(string)"/>
188         /// at all. To ignore unknown fields when parsing JSON, create a <see cref="JsonParser"/> using a <see cref="JsonParser.Settings"/>
189         /// with <see cref="JsonParser.Settings.IgnoreUnknownFields"/> set to true and call <see cref="JsonParser.Parse{T}(string)"/> directly.</remarks>
190         /// <param name="discardUnknownFields">Whether or not to discard unknown fields when parsing.</param>
191         /// <returns>A newly configured message parser.</returns>
192         public MessageParser WithDiscardUnknownFields(bool discardUnknownFields) =>
193             new MessageParser(factory, discardUnknownFields, Extensions);
194 
195         /// <summary>
196         /// Creates a new message parser which registers extensions from the specified registry upon creating the message instance
197         /// </summary>
198         /// <param name="registry">The extensions to register</param>
199         /// <returns>A newly configured message parser.</returns>
200         public MessageParser WithExtensionRegistry(ExtensionRegistry registry) =>
201             new MessageParser(factory, DiscardUnknownFields, registry);
202     }
203 
204     /// <summary>
205     /// A parser for a specific message type.
206     /// </summary>
207     /// <remarks>
208     /// <p>
209     /// This delegates most behavior to the
210     /// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
211     /// provides convenient overloads to parse from a variety of sources.
212     /// </p>
213     /// <p>
214     /// Most applications will never need to create their own instances of this type;
215     /// instead, use the static <c>Parser</c> property of a generated message type to obtain a
216     /// parser for that type.
217     /// </p>
218     /// </remarks>
219     /// <typeparam name="T">The type of message to be parsed.</typeparam>
220     public sealed class MessageParser<T> : MessageParser where T : IMessage<T>
221     {
222         // Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
223         // The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
224         // Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
225         // The API wouldn't change anyway - just the implementation - so this work can be deferred.
226         private readonly Func<T> factory;
227 
228         /// <summary>
229         /// Creates a new parser.
230         /// </summary>
231         /// <remarks>
232         /// The factory method is effectively an optimization over using a generic constraint
233         /// to require a parameterless constructor: delegates are significantly faster to execute.
234         /// </remarks>
235         /// <param name="factory">Function to invoke when a new, empty message is required.</param>
MessageParser(Func<T> factory)236         public MessageParser(Func<T> factory) : this(factory, false, null)
237         {
238         }
239 
MessageParser(Func<T> factory, bool discardUnknownFields, ExtensionRegistry extensions)240         internal MessageParser(Func<T> factory, bool discardUnknownFields, ExtensionRegistry extensions) : base(() => factory(), discardUnknownFields, extensions)
241         {
242             this.factory = factory;
243         }
244 
245         /// <summary>
246         /// Creates a template instance ready for population.
247         /// </summary>
248         /// <returns>An empty message.</returns>
CreateTemplate()249         internal new T CreateTemplate()
250         {
251             return factory();
252         }
253 
254         /// <summary>
255         /// Parses a message from a byte array.
256         /// </summary>
257         /// <param name="data">The byte array containing the message. Must not be null.</param>
258         /// <returns>The newly parsed message.</returns>
ParseFrom(byte[] data)259         public new T ParseFrom(byte[] data)
260         {
261             T message = factory();
262             message.MergeFrom(data, DiscardUnknownFields, Extensions);
263             return message;
264         }
265 
266         /// <summary>
267         /// Parses a message from a byte array slice.
268         /// </summary>
269         /// <param name="data">The byte array containing the message. Must not be null.</param>
270         /// <param name="offset">The offset of the slice to parse.</param>
271         /// <param name="length">The length of the slice to parse.</param>
272         /// <returns>The newly parsed message.</returns>
ParseFrom(byte[] data, int offset, int length)273         public new T ParseFrom(byte[] data, int offset, int length)
274         {
275             T message = factory();
276             message.MergeFrom(data, offset, length, DiscardUnknownFields, Extensions);
277             return message;
278         }
279 
280         /// <summary>
281         /// Parses a message from the given byte string.
282         /// </summary>
283         /// <param name="data">The data to parse.</param>
284         /// <returns>The parsed message.</returns>
ParseFrom(ByteString data)285         public new T ParseFrom(ByteString data)
286         {
287             T message = factory();
288             message.MergeFrom(data, DiscardUnknownFields, Extensions);
289             return message;
290         }
291 
292         /// <summary>
293         /// Parses a message from the given stream.
294         /// </summary>
295         /// <param name="input">The stream to parse.</param>
296         /// <returns>The parsed message.</returns>
ParseFrom(Stream input)297         public new T ParseFrom(Stream input)
298         {
299             T message = factory();
300             message.MergeFrom(input, DiscardUnknownFields, Extensions);
301             return message;
302         }
303 
304         /// <summary>
305         /// Parses a message from the given sequence.
306         /// </summary>
307         /// <param name="data">The data to parse.</param>
308         /// <returns>The parsed message.</returns>
309         [SecuritySafeCritical]
ParseFrom(ReadOnlySequence<byte> data)310         public new T ParseFrom(ReadOnlySequence<byte> data)
311         {
312             T message = factory();
313             message.MergeFrom(data, DiscardUnknownFields, Extensions);
314             return message;
315         }
316 
317         /// <summary>
318         /// Parses a message from the given span.
319         /// </summary>
320         /// <param name="data">The data to parse.</param>
321         /// <returns>The parsed message.</returns>
322         [SecuritySafeCritical]
ParseFrom(ReadOnlySpan<byte> data)323         public new T ParseFrom(ReadOnlySpan<byte> data)
324         {
325             T message = factory();
326             message.MergeFrom(data, DiscardUnknownFields, Extensions);
327             return message;
328         }
329 
330         /// <summary>
331         /// Parses a length-delimited message from the given stream.
332         /// </summary>
333         /// <remarks>
334         /// The stream is expected to contain a length and then the data. Only the amount of data
335         /// specified by the length will be consumed.
336         /// </remarks>
337         /// <param name="input">The stream to parse.</param>
338         /// <returns>The parsed message.</returns>
ParseDelimitedFrom(Stream input)339         public new T ParseDelimitedFrom(Stream input)
340         {
341             T message = factory();
342             message.MergeDelimitedFrom(input, DiscardUnknownFields, Extensions);
343             return message;
344         }
345 
346         /// <summary>
347         /// Parses a message from the given coded input stream.
348         /// </summary>
349         /// <param name="input">The stream to parse.</param>
350         /// <returns>The parsed message.</returns>
ParseFrom(CodedInputStream input)351         public new T ParseFrom(CodedInputStream input)
352         {
353             T message = factory();
354             MergeFrom(message, input);
355             return message;
356         }
357 
358         /// <summary>
359         /// Parses a message from the given JSON.
360         /// </summary>
361         /// <param name="json">The JSON to parse.</param>
362         /// <returns>The parsed message.</returns>
363         /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
364         /// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
ParseJson(string json)365         public new T ParseJson(string json)
366         {
367             T message = factory();
368             JsonParser.Default.Merge(message, json);
369             return message;
370         }
371 
372         /// <summary>
373         /// Creates a new message parser which optionally discards unknown fields when parsing.
374         /// </summary>
375         /// <param name="discardUnknownFields">Whether or not to discard unknown fields when parsing.</param>
376         /// <returns>A newly configured message parser.</returns>
377         public new MessageParser<T> WithDiscardUnknownFields(bool discardUnknownFields) =>
378             new MessageParser<T>(factory, discardUnknownFields, Extensions);
379 
380         /// <summary>
381         /// Creates a new message parser which registers extensions from the specified registry upon creating the message instance
382         /// </summary>
383         /// <param name="registry">The extensions to register</param>
384         /// <returns>A newly configured message parser.</returns>
385         public new MessageParser<T> WithExtensionRegistry(ExtensionRegistry registry) =>
386             new MessageParser<T>(factory, DiscardUnknownFields, registry);
387     }
388 }
389