Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: third_party/protobuf/csharp/src/Google.Protobuf/JsonParser.cs

Issue 1983203003: Update third_party/protobuf to protobuf-v3.0.0-beta-3 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: owners Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #region Copyright notice and license 1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format 2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc. All rights reserved. 3 // Copyright 2015 Google Inc. All rights reserved.
4 // https://developers.google.com/protocol-buffers/ 4 // https://developers.google.com/protocol-buffers/
5 // 5 //
6 // Redistribution and use in source and binary forms, with or without 6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are 7 // modification, are permitted provided that the following conditions are
8 // met: 8 // met:
9 // 9 //
10 // * Redistributions of source code must retain the above copyright 10 // * Redistributions of source code must retain the above copyright
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 } 161 }
162 // Well-known types with no special handling continue in the nor mal way. 162 // Well-known types with no special handling continue in the nor mal way.
163 } 163 }
164 var token = tokenizer.Next(); 164 var token = tokenizer.Next();
165 if (token.Type != JsonToken.TokenType.StartObject) 165 if (token.Type != JsonToken.TokenType.StartObject)
166 { 166 {
167 throw new InvalidProtocolBufferException("Expected an object"); 167 throw new InvalidProtocolBufferException("Expected an object");
168 } 168 }
169 var descriptor = message.Descriptor; 169 var descriptor = message.Descriptor;
170 var jsonFieldMap = descriptor.Fields.ByJsonName(); 170 var jsonFieldMap = descriptor.Fields.ByJsonName();
171 // All the oneof fields we've already accounted for - we can only se e each of them once.
172 // The set is created lazily to avoid the overhead of creating a set for every message
173 // we parsed, when oneofs are relatively rare.
174 HashSet<OneofDescriptor> seenOneofs = null;
171 while (true) 175 while (true)
172 { 176 {
173 token = tokenizer.Next(); 177 token = tokenizer.Next();
174 if (token.Type == JsonToken.TokenType.EndObject) 178 if (token.Type == JsonToken.TokenType.EndObject)
175 { 179 {
176 return; 180 return;
177 } 181 }
178 if (token.Type != JsonToken.TokenType.Name) 182 if (token.Type != JsonToken.TokenType.Name)
179 { 183 {
180 throw new InvalidOperationException("Unexpected token type " + token.Type); 184 throw new InvalidOperationException("Unexpected token type " + token.Type);
181 } 185 }
182 string name = token.StringValue; 186 string name = token.StringValue;
183 FieldDescriptor field; 187 FieldDescriptor field;
184 if (jsonFieldMap.TryGetValue(name, out field)) 188 if (jsonFieldMap.TryGetValue(name, out field))
185 { 189 {
190 if (field.ContainingOneof != null)
191 {
192 if (seenOneofs == null)
193 {
194 seenOneofs = new HashSet<OneofDescriptor>();
195 }
196 if (!seenOneofs.Add(field.ContainingOneof))
197 {
198 throw new InvalidProtocolBufferException($"Multiple values specified for oneof {field.ContainingOneof.Name}");
199 }
200 }
186 MergeField(message, field, tokenizer); 201 MergeField(message, field, tokenizer);
187 } 202 }
188 else 203 else
189 { 204 {
190 // TODO: Is this what we want to do? If not, we'll need to s kip the value, 205 // TODO: Is this what we want to do? If not, we'll need to s kip the value,
191 // which may be an object or array. (We might want to put co de in the tokenizer 206 // which may be an object or array. (We might want to put co de in the tokenizer
192 // to do that.) 207 // to do that.)
193 throw new InvalidProtocolBufferException("Unknown field: " + name); 208 throw new InvalidProtocolBufferException("Unknown field: " + name);
194 } 209 }
195 } 210 }
196 } 211 }
197 212
198 private void MergeField(IMessage message, FieldDescriptor field, JsonTok enizer tokenizer) 213 private void MergeField(IMessage message, FieldDescriptor field, JsonTok enizer tokenizer)
199 { 214 {
200 var token = tokenizer.Next(); 215 var token = tokenizer.Next();
201 if (token.Type == JsonToken.TokenType.Null) 216 if (token.Type == JsonToken.TokenType.Null)
202 { 217 {
218 // Clear the field if we see a null token, unless it's for a sin gular field of type
219 // google.protobuf.Value.
203 // Note: different from Java API, which just ignores it. 220 // Note: different from Java API, which just ignores it.
204 // TODO: Bring it more in line? Discuss... 221 // TODO: Bring it more in line? Discuss...
205 field.Accessor.Clear(message); 222 if (field.IsMap || field.IsRepeated || !IsGoogleProtobufValueFie ld(field))
206 return; 223 {
224 field.Accessor.Clear(message);
225 return;
226 }
207 } 227 }
208 tokenizer.PushBack(token); 228 tokenizer.PushBack(token);
209 229
210 if (field.IsMap) 230 if (field.IsMap)
211 { 231 {
212 MergeMapField(message, field, tokenizer); 232 MergeMapField(message, field, tokenizer);
213 } 233 }
214 else if (field.IsRepeated) 234 else if (field.IsRepeated)
215 { 235 {
216 MergeRepeatedField(message, field, tokenizer); 236 MergeRepeatedField(message, field, tokenizer);
(...skipping 15 matching lines...) Expand all
232 252
233 IList list = (IList) field.Accessor.GetValue(message); 253 IList list = (IList) field.Accessor.GetValue(message);
234 while (true) 254 while (true)
235 { 255 {
236 token = tokenizer.Next(); 256 token = tokenizer.Next();
237 if (token.Type == JsonToken.TokenType.EndArray) 257 if (token.Type == JsonToken.TokenType.EndArray)
238 { 258 {
239 return; 259 return;
240 } 260 }
241 tokenizer.PushBack(token); 261 tokenizer.PushBack(token);
262 if (token.Type == JsonToken.TokenType.Null)
263 {
264 throw new InvalidProtocolBufferException("Repeated field ele ments cannot be null");
265 }
242 list.Add(ParseSingleValue(field, tokenizer)); 266 list.Add(ParseSingleValue(field, tokenizer));
243 } 267 }
244 } 268 }
245 269
246 private void MergeMapField(IMessage message, FieldDescriptor field, Json Tokenizer tokenizer) 270 private void MergeMapField(IMessage message, FieldDescriptor field, Json Tokenizer tokenizer)
247 { 271 {
248 // Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those. 272 // Map fields are always objects, even if the values are well-known types: ParseSingleValue handles those.
249 var token = tokenizer.Next(); 273 var token = tokenizer.Next();
250 if (token.Type != JsonToken.TokenType.StartObject) 274 if (token.Type != JsonToken.TokenType.StartObject)
251 { 275 {
(...skipping 11 matching lines...) Expand all
263 287
264 while (true) 288 while (true)
265 { 289 {
266 token = tokenizer.Next(); 290 token = tokenizer.Next();
267 if (token.Type == JsonToken.TokenType.EndObject) 291 if (token.Type == JsonToken.TokenType.EndObject)
268 { 292 {
269 return; 293 return;
270 } 294 }
271 object key = ParseMapKey(keyField, token.StringValue); 295 object key = ParseMapKey(keyField, token.StringValue);
272 object value = ParseSingleValue(valueField, tokenizer); 296 object value = ParseSingleValue(valueField, tokenizer);
273 // TODO: Null handling 297 if (value == null)
298 {
299 throw new InvalidProtocolBufferException("Map values must no t be null");
300 }
274 dictionary[key] = value; 301 dictionary[key] = value;
275 } 302 }
276 } 303 }
277 304
305 private static bool IsGoogleProtobufValueField(FieldDescriptor field)
306 {
307 return field.FieldType == FieldType.Message &&
308 field.MessageType.FullName == Value.Descriptor.FullName;
309 }
310
278 private object ParseSingleValue(FieldDescriptor field, JsonTokenizer tok enizer) 311 private object ParseSingleValue(FieldDescriptor field, JsonTokenizer tok enizer)
279 { 312 {
280 var token = tokenizer.Next(); 313 var token = tokenizer.Next();
281 if (token.Type == JsonToken.TokenType.Null) 314 if (token.Type == JsonToken.TokenType.Null)
282 { 315 {
283 if (field.FieldType == FieldType.Message && field.MessageType.Fu llName == Value.Descriptor.FullName) 316 // TODO: In order to support dynamic messages, we should really build this up
317 // dynamically.
318 if (IsGoogleProtobufValueField(field))
284 { 319 {
285 return new Value { NullValue = NullValue.NULL_VALUE }; 320 return Value.ForNull();
286 } 321 }
287 return null; 322 return null;
288 } 323 }
289 324
290 var fieldType = field.FieldType; 325 var fieldType = field.FieldType;
291 if (fieldType == FieldType.Message) 326 if (fieldType == FieldType.Message)
292 { 327 {
293 // Parse wrapper types as their constituent types. 328 // Parse wrapper types as their constituent types.
294 // TODO: What does this mean for null? 329 // TODO: What does this mean for null?
295 if (field.MessageType.IsWrapperType) 330 if (field.MessageType.IsWrapperType)
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 367
333 /// <summary> 368 /// <summary>
334 /// Parses <paramref name="json"/> into a new message. 369 /// Parses <paramref name="json"/> into a new message.
335 /// </summary> 370 /// </summary>
336 /// <typeparam name="T">The type of message to create.</typeparam> 371 /// <typeparam name="T">The type of message to create.</typeparam>
337 /// <param name="json">The JSON to parse.</param> 372 /// <param name="json">The JSON to parse.</param>
338 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception> 373 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
339 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception> 374 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception>
340 public T Parse<T>(string json) where T : IMessage, new() 375 public T Parse<T>(string json) where T : IMessage, new()
341 { 376 {
342 Preconditions.CheckNotNull(json, nameof(json)); 377 ProtoPreconditions.CheckNotNull(json, nameof(json));
343 return Parse<T>(new StringReader(json)); 378 return Parse<T>(new StringReader(json));
344 } 379 }
345 380
346 /// <summary> 381 /// <summary>
347 /// Parses JSON read from <paramref name="jsonReader"/> into a new messa ge. 382 /// Parses JSON read from <paramref name="jsonReader"/> into a new messa ge.
348 /// </summary> 383 /// </summary>
349 /// <typeparam name="T">The type of message to create.</typeparam> 384 /// <typeparam name="T">The type of message to create.</typeparam>
350 /// <param name="jsonReader">Reader providing the JSON to parse.</param> 385 /// <param name="jsonReader">Reader providing the JSON to parse.</param>
351 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception> 386 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
352 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception> 387 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception>
353 public T Parse<T>(TextReader jsonReader) where T : IMessage, new() 388 public T Parse<T>(TextReader jsonReader) where T : IMessage, new()
354 { 389 {
355 Preconditions.CheckNotNull(jsonReader, nameof(jsonReader)); 390 ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
356 T message = new T(); 391 T message = new T();
357 Merge(message, jsonReader); 392 Merge(message, jsonReader);
358 return message; 393 return message;
359 } 394 }
360 395
361 /// <summary> 396 /// <summary>
362 /// Parses <paramref name="json"/> into a new message. 397 /// Parses <paramref name="json"/> into a new message.
363 /// </summary> 398 /// </summary>
364 /// <param name="json">The JSON to parse.</param> 399 /// <param name="json">The JSON to parse.</param>
365 /// <param name="descriptor">Descriptor of message type to parse.</param > 400 /// <param name="descriptor">Descriptor of message type to parse.</param >
366 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception> 401 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
367 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception> 402 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception>
368 public IMessage Parse(string json, MessageDescriptor descriptor) 403 public IMessage Parse(string json, MessageDescriptor descriptor)
369 { 404 {
370 Preconditions.CheckNotNull(json, nameof(json)); 405 ProtoPreconditions.CheckNotNull(json, nameof(json));
371 Preconditions.CheckNotNull(descriptor, nameof(descriptor)); 406 ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
372 return Parse(new StringReader(json), descriptor); 407 return Parse(new StringReader(json), descriptor);
373 } 408 }
374 409
375 /// <summary> 410 /// <summary>
376 /// Parses JSON read from <paramref name="jsonReader"/> into a new messa ge. 411 /// Parses JSON read from <paramref name="jsonReader"/> into a new messa ge.
377 /// </summary> 412 /// </summary>
378 /// <param name="jsonReader">Reader providing the JSON to parse.</param> 413 /// <param name="jsonReader">Reader providing the JSON to parse.</param>
379 /// <param name="descriptor">Descriptor of message type to parse.</param > 414 /// <param name="descriptor">Descriptor of message type to parse.</param >
380 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception> 415 /// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
381 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception> 416 /// <exception cref="InvalidProtocolBufferException">The JSON does not r epresent a Protocol Buffers message correctly</exception>
382 public IMessage Parse(TextReader jsonReader, MessageDescriptor descripto r) 417 public IMessage Parse(TextReader jsonReader, MessageDescriptor descripto r)
383 { 418 {
384 Preconditions.CheckNotNull(jsonReader, nameof(jsonReader)); 419 ProtoPreconditions.CheckNotNull(jsonReader, nameof(jsonReader));
385 Preconditions.CheckNotNull(descriptor, nameof(descriptor)); 420 ProtoPreconditions.CheckNotNull(descriptor, nameof(descriptor));
386 IMessage message = descriptor.Parser.CreateTemplate(); 421 IMessage message = descriptor.Parser.CreateTemplate();
387 Merge(message, jsonReader); 422 Merge(message, jsonReader);
388 return message; 423 return message;
389 } 424 }
390 425
391 private void MergeStructValue(IMessage message, JsonTokenizer tokenizer) 426 private void MergeStructValue(IMessage message, JsonTokenizer tokenizer)
392 { 427 {
393 var firstToken = tokenizer.Next(); 428 var firstToken = tokenizer.Next();
394 var fields = message.Descriptor.Fields; 429 var fields = message.Descriptor.Fields;
395 switch (firstToken.Type) 430 switch (firstToken.Type)
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 int typeUrlObjectDepth = tokenizer.ObjectDepth; 492 int typeUrlObjectDepth = tokenizer.ObjectDepth;
458 493
459 // The check for the property depth protects us from nested Any valu es which occur before the type URL 494 // The check for the property depth protects us from nested Any valu es which occur before the type URL
460 // for *this* Any. 495 // for *this* Any.
461 while (token.Type != JsonToken.TokenType.Name || 496 while (token.Type != JsonToken.TokenType.Name ||
462 token.StringValue != JsonFormatter.AnyTypeUrlField || 497 token.StringValue != JsonFormatter.AnyTypeUrlField ||
463 tokenizer.ObjectDepth != typeUrlObjectDepth) 498 tokenizer.ObjectDepth != typeUrlObjectDepth)
464 { 499 {
465 tokens.Add(token); 500 tokens.Add(token);
466 token = tokenizer.Next(); 501 token = tokenizer.Next();
502
503 if (tokenizer.ObjectDepth < typeUrlObjectDepth)
504 {
505 throw new InvalidProtocolBufferException("Any message with n o @type");
506 }
467 } 507 }
468 508
469 // Don't add the @type property or its value to the recorded token l ist 509 // Don't add the @type property or its value to the recorded token l ist
470 token = tokenizer.Next(); 510 token = tokenizer.Next();
471 if (token.Type != JsonToken.TokenType.StringValue) 511 if (token.Type != JsonToken.TokenType.StringValue)
472 { 512 {
473 throw new InvalidProtocolBufferException("Expected string value for Any.@type"); 513 throw new InvalidProtocolBufferException("Expected string value for Any.@type");
474 } 514 }
475 string typeUrl = token.StringValue; 515 string typeUrl = token.StringValue;
476 string typeName = JsonFormatter.GetTypeName(typeUrl); 516 string typeName = Any.GetTypeName(typeUrl);
477 517
478 MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName); 518 MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
479 if (descriptor == null) 519 if (descriptor == null)
480 { 520 {
481 throw new InvalidOperationException($"Type registry has no descr iptor for type name '{typeName}'"); 521 throw new InvalidOperationException($"Type registry has no descr iptor for type name '{typeName}'");
482 } 522 }
483 523
484 // Now replay the token stream we've already read and anything that remains of the object, just parsing it 524 // Now replay the token stream we've already read and anything that remains of the object, just parsing it
485 // as normal. Our original tokenizer should end up at the end of the object. 525 // as normal. Our original tokenizer should end up at the end of the object.
486 var replay = JsonTokenizer.FromReplayedTokens(tokens, tokenizer); 526 var replay = JsonTokenizer.FromReplayedTokens(tokens, tokenizer);
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 if (keyText == "false") 573 if (keyText == "false")
534 { 574 {
535 return false; 575 return false;
536 } 576 }
537 throw new InvalidProtocolBufferException("Invalid string for bool map key: " + keyText); 577 throw new InvalidProtocolBufferException("Invalid string for bool map key: " + keyText);
538 case FieldType.String: 578 case FieldType.String:
539 return keyText; 579 return keyText;
540 case FieldType.Int32: 580 case FieldType.Int32:
541 case FieldType.SInt32: 581 case FieldType.SInt32:
542 case FieldType.SFixed32: 582 case FieldType.SFixed32:
543 return ParseNumericString(keyText, int.Parse, false); 583 return ParseNumericString(keyText, int.Parse);
544 case FieldType.UInt32: 584 case FieldType.UInt32:
545 case FieldType.Fixed32: 585 case FieldType.Fixed32:
546 return ParseNumericString(keyText, uint.Parse, false); 586 return ParseNumericString(keyText, uint.Parse);
547 case FieldType.Int64: 587 case FieldType.Int64:
548 case FieldType.SInt64: 588 case FieldType.SInt64:
549 case FieldType.SFixed64: 589 case FieldType.SFixed64:
550 return ParseNumericString(keyText, long.Parse, false); 590 return ParseNumericString(keyText, long.Parse);
551 case FieldType.UInt64: 591 case FieldType.UInt64:
552 case FieldType.Fixed64: 592 case FieldType.Fixed64:
553 return ParseNumericString(keyText, ulong.Parse, false); 593 return ParseNumericString(keyText, ulong.Parse);
554 default: 594 default:
555 throw new InvalidProtocolBufferException("Invalid field type for map: " + field.FieldType); 595 throw new InvalidProtocolBufferException("Invalid field type for map: " + field.FieldType);
556 } 596 }
557 } 597 }
558 598
559 private static object ParseSingleNumberValue(FieldDescriptor field, Json Token token) 599 private static object ParseSingleNumberValue(FieldDescriptor field, Json Token token)
560 { 600 {
561 double value = token.NumberValue; 601 double value = token.NumberValue;
562 checked 602 checked
563 { 603 {
564 // TODO: Validate that it's actually an integer, possibly in ter ms of the textual representation?
565 try 604 try
566 { 605 {
567 switch (field.FieldType) 606 switch (field.FieldType)
568 { 607 {
569 case FieldType.Int32: 608 case FieldType.Int32:
570 case FieldType.SInt32: 609 case FieldType.SInt32:
571 case FieldType.SFixed32: 610 case FieldType.SFixed32:
611 CheckInteger(value);
572 return (int) value; 612 return (int) value;
573 case FieldType.UInt32: 613 case FieldType.UInt32:
574 case FieldType.Fixed32: 614 case FieldType.Fixed32:
615 CheckInteger(value);
575 return (uint) value; 616 return (uint) value;
576 case FieldType.Int64: 617 case FieldType.Int64:
577 case FieldType.SInt64: 618 case FieldType.SInt64:
578 case FieldType.SFixed64: 619 case FieldType.SFixed64:
620 CheckInteger(value);
579 return (long) value; 621 return (long) value;
580 case FieldType.UInt64: 622 case FieldType.UInt64:
581 case FieldType.Fixed64: 623 case FieldType.Fixed64:
624 CheckInteger(value);
582 return (ulong) value; 625 return (ulong) value;
583 case FieldType.Double: 626 case FieldType.Double:
584 return value; 627 return value;
585 case FieldType.Float: 628 case FieldType.Float:
586 if (double.IsNaN(value)) 629 if (double.IsNaN(value))
587 { 630 {
588 return float.NaN; 631 return float.NaN;
589 } 632 }
590 if (value > float.MaxValue || value < float.MinValue ) 633 if (value > float.MaxValue || value < float.MinValue )
591 { 634 {
592 if (double.IsPositiveInfinity(value)) 635 if (double.IsPositiveInfinity(value))
593 { 636 {
594 return float.PositiveInfinity; 637 return float.PositiveInfinity;
595 } 638 }
596 if (double.IsNegativeInfinity(value)) 639 if (double.IsNegativeInfinity(value))
597 { 640 {
598 return float.NegativeInfinity; 641 return float.NegativeInfinity;
599 } 642 }
600 throw new InvalidProtocolBufferException("Value out of range: " + value); 643 throw new InvalidProtocolBufferException($"Value out of range: {value}");
601 } 644 }
602 return (float) value; 645 return (float) value;
646 case FieldType.Enum:
647 CheckInteger(value);
648 // Just return it as an int, and let the CLR convert it.
649 // Note that we deliberately don't check that it's a known value.
650 return (int) value;
603 default: 651 default:
604 throw new InvalidProtocolBufferException("Unsupporte d conversion from JSON number for field type " + field.FieldType); 652 throw new InvalidProtocolBufferException($"Unsupport ed conversion from JSON number for field type {field.FieldType}");
605 } 653 }
606 } 654 }
607 catch (OverflowException) 655 catch (OverflowException)
608 { 656 {
609 throw new InvalidProtocolBufferException("Value out of range : " + value); 657 throw new InvalidProtocolBufferException($"Value out of rang e: {value}");
610 } 658 }
611 } 659 }
612 } 660 }
613 661
662 private static void CheckInteger(double value)
663 {
664 if (double.IsInfinity(value) || double.IsNaN(value))
665 {
666 throw new InvalidProtocolBufferException($"Value not an integer: {value}");
667 }
668 if (value != Math.Floor(value))
669 {
670 throw new InvalidProtocolBufferException($"Value not an integer: {value}");
671 }
672 }
673
614 private static object ParseSingleStringValue(FieldDescriptor field, stri ng text) 674 private static object ParseSingleStringValue(FieldDescriptor field, stri ng text)
615 { 675 {
616 switch (field.FieldType) 676 switch (field.FieldType)
617 { 677 {
618 case FieldType.String: 678 case FieldType.String:
619 return text; 679 return text;
620 case FieldType.Bytes: 680 case FieldType.Bytes:
621 return ByteString.FromBase64(text); 681 try
682 {
683 return ByteString.FromBase64(text);
684 }
685 catch (FormatException e)
686 {
687 throw InvalidProtocolBufferException.InvalidBase64(e);
688 }
622 case FieldType.Int32: 689 case FieldType.Int32:
623 case FieldType.SInt32: 690 case FieldType.SInt32:
624 case FieldType.SFixed32: 691 case FieldType.SFixed32:
625 return ParseNumericString(text, int.Parse, false); 692 return ParseNumericString(text, int.Parse);
626 case FieldType.UInt32: 693 case FieldType.UInt32:
627 case FieldType.Fixed32: 694 case FieldType.Fixed32:
628 return ParseNumericString(text, uint.Parse, false); 695 return ParseNumericString(text, uint.Parse);
629 case FieldType.Int64: 696 case FieldType.Int64:
630 case FieldType.SInt64: 697 case FieldType.SInt64:
631 case FieldType.SFixed64: 698 case FieldType.SFixed64:
632 return ParseNumericString(text, long.Parse, false); 699 return ParseNumericString(text, long.Parse);
633 case FieldType.UInt64: 700 case FieldType.UInt64:
634 case FieldType.Fixed64: 701 case FieldType.Fixed64:
635 return ParseNumericString(text, ulong.Parse, false); 702 return ParseNumericString(text, ulong.Parse);
636 case FieldType.Double: 703 case FieldType.Double:
637 double d = ParseNumericString(text, double.Parse, true); 704 double d = ParseNumericString(text, double.Parse);
638 // double.Parse can return +/- infinity on Mono for non-infi nite values which are out of range for double. 705 ValidateInfinityAndNan(text, double.IsPositiveInfinity(d), d ouble.IsNegativeInfinity(d), double.IsNaN(d));
639 if (double.IsInfinity(d) && !text.Contains("Infinity"))
640 {
641 throw new InvalidProtocolBufferException("Invalid numeri c value: " + text);
642 }
643 return d; 706 return d;
644 case FieldType.Float: 707 case FieldType.Float:
645 float f = ParseNumericString(text, float.Parse, true); 708 float f = ParseNumericString(text, float.Parse);
646 // float.Parse can return +/- infinity on Mono for non-infin ite values which are out of range for float. 709 ValidateInfinityAndNan(text, float.IsPositiveInfinity(f), fl oat.IsNegativeInfinity(f), float.IsNaN(f));
647 if (float.IsInfinity(f) && !text.Contains("Infinity"))
648 {
649 throw new InvalidProtocolBufferException("Invalid numeri c value: " + text);
650 }
651 return f; 710 return f;
652 case FieldType.Enum: 711 case FieldType.Enum:
653 var enumValue = field.EnumType.FindValueByName(text); 712 var enumValue = field.EnumType.FindValueByName(text);
654 if (enumValue == null) 713 if (enumValue == null)
655 { 714 {
656 throw new InvalidProtocolBufferException("Invalid enum v alue: " + text + " for enum type: " + field.EnumType.FullName); 715 throw new InvalidProtocolBufferException($"Invalid enum value: {text} for enum type: {field.EnumType.FullName}");
657 } 716 }
658 // Just return it as an int, and let the CLR convert it. 717 // Just return it as an int, and let the CLR convert it.
659 return enumValue.Number; 718 return enumValue.Number;
660 default: 719 default:
661 throw new InvalidProtocolBufferException("Unsupported conver sion from JSON string for field type " + field.FieldType); 720 throw new InvalidProtocolBufferException($"Unsupported conve rsion from JSON string for field type {field.FieldType}");
662 } 721 }
663 } 722 }
664 723
665 /// <summary> 724 /// <summary>
666 /// Creates a new instance of the message type for the given field. 725 /// Creates a new instance of the message type for the given field.
667 /// </summary> 726 /// </summary>
668 private static IMessage NewMessageForField(FieldDescriptor field) 727 private static IMessage NewMessageForField(FieldDescriptor field)
669 { 728 {
670 return field.MessageType.Parser.CreateTemplate(); 729 return field.MessageType.Parser.CreateTemplate();
671 } 730 }
672 731
673 private static T ParseNumericString<T>(string text, Func<string, NumberS tyles, IFormatProvider, T> parser, bool floatingPoint) 732 private static T ParseNumericString<T>(string text, Func<string, NumberS tyles, IFormatProvider, T> parser)
674 { 733 {
675 // TODO: Prohibit leading zeroes (but allow 0!)
676 // TODO: Validate handling of "Infinity" etc. (Should be case sensit ive, no leading whitespace etc)
677 // Can't prohibit this with NumberStyles. 734 // Can't prohibit this with NumberStyles.
678 if (text.StartsWith("+")) 735 if (text.StartsWith("+"))
679 { 736 {
680 throw new InvalidProtocolBufferException("Invalid numeric value: " + text); 737 throw new InvalidProtocolBufferException($"Invalid numeric value : {text}");
681 } 738 }
682 if (text.StartsWith("0") && text.Length > 1) 739 if (text.StartsWith("0") && text.Length > 1)
683 { 740 {
684 if (text[1] >= '0' && text[1] <= '9') 741 if (text[1] >= '0' && text[1] <= '9')
685 { 742 {
686 throw new InvalidProtocolBufferException("Invalid numeric va lue: " + text); 743 throw new InvalidProtocolBufferException($"Invalid numeric v alue: {text}");
687 } 744 }
688 } 745 }
689 else if (text.StartsWith("-0") && text.Length > 2) 746 else if (text.StartsWith("-0") && text.Length > 2)
690 { 747 {
691 if (text[2] >= '0' && text[2] <= '9') 748 if (text[2] >= '0' && text[2] <= '9')
692 { 749 {
693 throw new InvalidProtocolBufferException("Invalid numeric va lue: " + text); 750 throw new InvalidProtocolBufferException($"Invalid numeric v alue: {text}");
694 } 751 }
695 } 752 }
696 try 753 try
697 { 754 {
698 var styles = floatingPoint 755 return parser(text, NumberStyles.AllowLeadingSign | NumberStyles .AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
699 ? NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalP oint | NumberStyles.AllowExponent
700 : NumberStyles.AllowLeadingSign;
701 return parser(text, styles, CultureInfo.InvariantCulture);
702 } 756 }
703 catch (FormatException) 757 catch (FormatException)
704 { 758 {
705 throw new InvalidProtocolBufferException("Invalid numeric value for type: " + text); 759 throw new InvalidProtocolBufferException($"Invalid numeric value for type: {text}");
706 } 760 }
707 catch (OverflowException) 761 catch (OverflowException)
708 { 762 {
709 throw new InvalidProtocolBufferException("Value out of range: " + text); 763 throw new InvalidProtocolBufferException($"Value out of range: { text}");
710 } 764 }
711 } 765 }
712 766
767 /// <summary>
768 /// Checks that any infinite/NaN values originated from the correct text .
769 /// This corrects the lenient whitespace handling of double.Parse/float. Parse, as well as the
770 /// way that Mono parses out-of-range values as infinity.
771 /// </summary>
772 private static void ValidateInfinityAndNan(string text, bool isPositiveI nfinity, bool isNegativeInfinity, bool isNaN)
773 {
774 if ((isPositiveInfinity && text != "Infinity") ||
775 (isNegativeInfinity && text != "-Infinity") ||
776 (isNaN && text != "NaN"))
777 {
778 throw new InvalidProtocolBufferException($"Invalid numeric value : {text}");
779 }
780 }
781
713 private static void MergeTimestamp(IMessage message, JsonToken token) 782 private static void MergeTimestamp(IMessage message, JsonToken token)
714 { 783 {
715 if (token.Type != JsonToken.TokenType.StringValue) 784 if (token.Type != JsonToken.TokenType.StringValue)
716 { 785 {
717 throw new InvalidProtocolBufferException("Expected string value for Timestamp"); 786 throw new InvalidProtocolBufferException("Expected string value for Timestamp");
718 } 787 }
719 var match = TimestampRegex.Match(token.StringValue); 788 var match = TimestampRegex.Match(token.StringValue);
720 if (!match.Success) 789 if (!match.Success)
721 { 790 {
722 throw new InvalidProtocolBufferException("Invalid Timestamp valu e: " + token.StringValue); 791 throw new InvalidProtocolBufferException($"Invalid Timestamp val ue: {token.StringValue}");
723 } 792 }
724 var dateTime = match.Groups["datetime"].Value; 793 var dateTime = match.Groups["datetime"].Value;
725 var subseconds = match.Groups["subseconds"].Value; 794 var subseconds = match.Groups["subseconds"].Value;
726 var offset = match.Groups["offset"].Value; 795 var offset = match.Groups["offset"].Value;
727 796
728 try 797 try
729 { 798 {
730 DateTime parsed = DateTime.ParseExact( 799 DateTime parsed = DateTime.ParseExact(
731 dateTime, 800 dateTime,
732 "yyyy-MM-dd'T'HH:mm:ss", 801 "yyyy-MM-dd'T'HH:mm:ss",
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 // Prohibit leading insignficant zeroes 871 // Prohibit leading insignficant zeroes
803 if (secondsText[0] == '0' && secondsText.Length > 1) 872 if (secondsText[0] == '0' && secondsText.Length > 1)
804 { 873 {
805 throw new InvalidProtocolBufferException("Invalid Duration value : " + token.StringValue); 874 throw new InvalidProtocolBufferException("Invalid Duration value : " + token.StringValue);
806 } 875 }
807 var subseconds = match.Groups["subseconds"].Value; 876 var subseconds = match.Groups["subseconds"].Value;
808 var multiplier = sign == "-" ? -1 : 1; 877 var multiplier = sign == "-" ? -1 : 1;
809 878
810 try 879 try
811 { 880 {
812 long seconds = long.Parse(secondsText, CultureInfo.InvariantCult ure); 881 long seconds = long.Parse(secondsText, CultureInfo.InvariantCult ure) * multiplier;
813 int nanos = 0; 882 int nanos = 0;
814 if (subseconds != "") 883 if (subseconds != "")
815 { 884 {
816 // This should always work, as we've got 1-9 digits. 885 // This should always work, as we've got 1-9 digits.
817 int parsedFraction = int.Parse(subseconds.Substring(1)); 886 int parsedFraction = int.Parse(subseconds.Substring(1));
818 nanos = parsedFraction * SubsecondScalingFactors[subseconds. Length]; 887 nanos = parsedFraction * SubsecondScalingFactors[subseconds. Length] * multiplier;
819 } 888 }
820 if (seconds >= Duration.MaxSeconds) 889 if (!Duration.IsNormalized(seconds, nanos))
821 { 890 {
822 // Allow precisely 315576000000 seconds, but prohibit even 1 ns more. 891 throw new InvalidProtocolBufferException($"Invalid Duration value: {token.StringValue}");
823 if (seconds > Duration.MaxSeconds || nanos > 0)
824 {
825 throw new InvalidProtocolBufferException("Invalid Durati on value: " + token.StringValue);
826 }
827 } 892 }
828 message.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor. SetValue(message, seconds * multiplier); 893 message.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor. SetValue(message, seconds);
829 message.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.Se tValue(message, nanos * multiplier); 894 message.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.Se tValue(message, nanos);
830 } 895 }
831 catch (FormatException) 896 catch (FormatException)
832 { 897 {
833 throw new InvalidProtocolBufferException("Invalid Duration value : " + token.StringValue); 898 throw new InvalidProtocolBufferException($"Invalid Duration valu e: {token.StringValue}");
834 } 899 }
835 } 900 }
836 901
837 private static void MergeFieldMask(IMessage message, JsonToken token) 902 private static void MergeFieldMask(IMessage message, JsonToken token)
838 { 903 {
839 if (token.Type != JsonToken.TokenType.StringValue) 904 if (token.Type != JsonToken.TokenType.StringValue)
840 { 905 {
841 throw new InvalidProtocolBufferException("Expected string value for FieldMask"); 906 throw new InvalidProtocolBufferException("Expected string value for FieldMask");
842 } 907 }
843 // TODO: Do we *want* to remove empty entries? Probably okay to trea t "" as "no paths", but "foo,,bar"? 908 // TODO: Do we *want* to remove empty entries? Probably okay to trea t "" as "no paths", but "foo,,bar"?
844 string[] jsonPaths = token.StringValue.Split(FieldMaskPathSeparators , StringSplitOptions.RemoveEmptyEntries); 909 string[] jsonPaths = token.StringValue.Split(FieldMaskPathSeparators , StringSplitOptions.RemoveEmptyEntries);
845 IList messagePaths = (IList) message.Descriptor.Fields[FieldMask.Pat hsFieldNumber].Accessor.GetValue(message); 910 IList messagePaths = (IList) message.Descriptor.Fields[FieldMask.Pat hsFieldNumber].Accessor.GetValue(message);
846 foreach (var path in jsonPaths) 911 foreach (var path in jsonPaths)
847 { 912 {
848 messagePaths.Add(ToSnakeCase(path)); 913 messagePaths.Add(ToSnakeCase(path));
849 } 914 }
850 } 915 }
851 916
852 // Ported from src/google/protobuf/util/internal/utility.cc 917 // Ported from src/google/protobuf/util/internal/utility.cc
853 private static string ToSnakeCase(string text) 918 private static string ToSnakeCase(string text)
854 { 919 {
855 var builder = new StringBuilder(text.Length * 2); 920 var builder = new StringBuilder(text.Length * 2);
921 // Note: this is probably unnecessary now, but currently retained to be as close as possible to the
922 // C++, whilst still throwing an exception on underscores.
856 bool wasNotUnderscore = false; // Initialize to false for case 1 (b elow) 923 bool wasNotUnderscore = false; // Initialize to false for case 1 (b elow)
857 bool wasNotCap = false; 924 bool wasNotCap = false;
858 925
859 for (int i = 0; i < text.Length; i++) 926 for (int i = 0; i < text.Length; i++)
860 { 927 {
861 char c = text[i]; 928 char c = text[i];
862 if (c >= 'A' && c <= 'Z') // ascii_isupper 929 if (c >= 'A' && c <= 'Z') // ascii_isupper
863 { 930 {
864 // Consider when the current character B is capitalized: 931 // Consider when the current character B is capitalized:
865 // 1) At beginning of input: "B..." => "b..." 932 // 1) At beginning of input: "B..." => "b..."
(...skipping 13 matching lines...) Expand all
879 builder.Append('_'); 946 builder.Append('_');
880 } 947 }
881 // ascii_tolower, but we already know that c *is* an upper c ase ASCII character... 948 // ascii_tolower, but we already know that c *is* an upper c ase ASCII character...
882 builder.Append((char) (c + 'a' - 'A')); 949 builder.Append((char) (c + 'a' - 'A'));
883 wasNotUnderscore = true; 950 wasNotUnderscore = true;
884 wasNotCap = false; 951 wasNotCap = false;
885 } 952 }
886 else 953 else
887 { 954 {
888 builder.Append(c); 955 builder.Append(c);
889 wasNotUnderscore = c != '_'; 956 if (c == '_')
957 {
958 throw new InvalidProtocolBufferException($"Invalid field mask: {text}");
959 }
960 wasNotUnderscore = true;
890 wasNotCap = true; 961 wasNotCap = true;
891 } 962 }
892 } 963 }
893 return builder.ToString(); 964 return builder.ToString();
894 } 965 }
895 #endregion 966 #endregion
896 967
897 /// <summary> 968 /// <summary>
898 /// Settings controlling JSON parsing. 969 /// Settings controlling JSON parsing.
899 /// </summary> 970 /// </summary>
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
933 } 1004 }
934 1005
935 /// <summary> 1006 /// <summary>
936 /// Creates a new <see cref="Settings"/> object with the specified r ecursion limit and type registry. 1007 /// Creates a new <see cref="Settings"/> object with the specified r ecursion limit and type registry.
937 /// </summary> 1008 /// </summary>
938 /// <param name="recursionLimit">The maximum depth of messages to pa rse</param> 1009 /// <param name="recursionLimit">The maximum depth of messages to pa rse</param>
939 /// <param name="typeRegistry">The type registry used to parse <see cref="Any"/> messages</param> 1010 /// <param name="typeRegistry">The type registry used to parse <see cref="Any"/> messages</param>
940 public Settings(int recursionLimit, TypeRegistry typeRegistry) 1011 public Settings(int recursionLimit, TypeRegistry typeRegistry)
941 { 1012 {
942 RecursionLimit = recursionLimit; 1013 RecursionLimit = recursionLimit;
943 TypeRegistry = Preconditions.CheckNotNull(typeRegistry, nameof(t ypeRegistry)); 1014 TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nam eof(typeRegistry));
944 } 1015 }
945 } 1016 }
946 } 1017 }
947 } 1018 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698