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 33 using System; 34 using System.Buffers; 35 using System.IO; 36 using System.Security; 37 38 namespace 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 MessageParser(Func<IMessage> factory, bool discardUnknownFields, ExtensionRegistry extensions)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> CreateTemplate()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> ParseFrom(byte[] data)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> ParseFrom(byte[] data, int offset, int length)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> ParseFrom(ByteString data)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> ParseFrom(Stream input)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] ParseFrom(ReadOnlySequence<byte> data)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> ParseDelimitedFrom(Stream input)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> ParseFrom(CodedInputStream input)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> ParseJson(string json)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. MergeFrom(IMessage message, CodedInputStream codedInput)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> MessageParser(Func<T> factory)237 public MessageParser(Func<T> factory) : this(factory, false, null) 238 { 239 } 240 MessageParser(Func<T> factory, bool discardUnknownFields, ExtensionRegistry extensions)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> CreateTemplate()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> ParseFrom(byte[] data)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> ParseFrom(byte[] data, int offset, int length)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> ParseFrom(ByteString data)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> ParseFrom(Stream input)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] ParseFrom(ReadOnlySequence<byte> data)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> ParseDelimitedFrom(Stream input)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> ParseFrom(CodedInputStream input)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> ParseJson(string json)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