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