| OLD | NEW |
| 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 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 | 241 |
| 242 WriteString(writer, accessor.Descriptor.JsonName); | 242 WriteString(writer, accessor.Descriptor.JsonName); |
| 243 writer.Write(NameValueSeparator); | 243 writer.Write(NameValueSeparator); |
| 244 WriteValue(writer, value); | 244 WriteValue(writer, value); |
| 245 | 245 |
| 246 first = false; | 246 first = false; |
| 247 } | 247 } |
| 248 return !first; | 248 return !first; |
| 249 } | 249 } |
| 250 | 250 |
| 251 // Converted from java/core/src/main/java/com/google/protobuf/Descriptor
s.java | 251 /// <summary> |
| 252 internal static string ToJsonName(string name) | 252 /// Camel-case converter with added strictness for field mask formatting
. |
| 253 /// </summary> |
| 254 /// <exception cref="InvalidOperationException">The field mask is invali
d for JSON representation</exception> |
| 255 private static string ToCamelCaseForFieldMask(string input) |
| 253 { | 256 { |
| 254 StringBuilder result = new StringBuilder(name.Length); | 257 for (int i = 0; i < input.Length; i++) |
| 255 bool isNextUpperCase = false; | |
| 256 foreach (char ch in name) | |
| 257 { | 258 { |
| 258 if (ch == '_') | 259 char c = input[i]; |
| 260 if (c >= 'A' && c <= 'Z') |
| 259 { | 261 { |
| 260 isNextUpperCase = true; | 262 throw new InvalidOperationException($"Invalid field mask to
be converted to JSON: {input}"); |
| 261 } | 263 } |
| 262 else if (isNextUpperCase) | 264 if (c == '_' && i < input.Length - 1) |
| 263 { | 265 { |
| 264 result.Append(char.ToUpperInvariant(ch)); | 266 char next = input[i + 1]; |
| 265 isNextUpperCase = false; | 267 if (next < 'a' || next > 'z') |
| 268 { |
| 269 throw new InvalidOperationException($"Invalid field mask
to be converted to JSON: {input}"); |
| 270 } |
| 266 } | 271 } |
| 267 else | 272 } |
| 273 return ToCamelCase(input); |
| 274 } |
| 275 |
| 276 // Converted from src/google/protobuf/util/internal/utility.cc ToCamelCa
se |
| 277 // TODO: Use the new field in FieldDescriptor. |
| 278 internal static string ToCamelCase(string input) |
| 279 { |
| 280 bool capitalizeNext = false; |
| 281 bool wasCap = true; |
| 282 bool isCap = false; |
| 283 bool firstWord = true; |
| 284 StringBuilder result = new StringBuilder(input.Length); |
| 285 |
| 286 for (int i = 0; i < input.Length; i++, wasCap = isCap) |
| 287 { |
| 288 isCap = char.IsUpper(input[i]); |
| 289 if (input[i] == '_') |
| 268 { | 290 { |
| 269 result.Append(ch); | 291 capitalizeNext = true; |
| 292 if (result.Length != 0) |
| 293 { |
| 294 firstWord = false; |
| 295 } |
| 296 continue; |
| 270 } | 297 } |
| 298 else if (firstWord) |
| 299 { |
| 300 // Consider when the current character B is capitalized, |
| 301 // first word ends when: |
| 302 // 1) following a lowercase: "...aB..." |
| 303 // 2) followed by a lowercase: "...ABc..." |
| 304 if (result.Length != 0 && isCap && |
| 305 (!wasCap || (i + 1 < input.Length && char.IsLower(input[
i + 1])))) |
| 306 { |
| 307 firstWord = false; |
| 308 } |
| 309 else |
| 310 { |
| 311 result.Append(char.ToLowerInvariant(input[i])); |
| 312 continue; |
| 313 } |
| 314 } |
| 315 else if (capitalizeNext) |
| 316 { |
| 317 capitalizeNext = false; |
| 318 if (char.IsLower(input[i])) |
| 319 { |
| 320 result.Append(char.ToUpperInvariant(input[i])); |
| 321 continue; |
| 322 } |
| 323 } |
| 324 result.Append(input[i]); |
| 271 } | 325 } |
| 272 return result.ToString(); | 326 return result.ToString(); |
| 273 } | 327 } |
| 274 | 328 |
| 275 private static void WriteNull(TextWriter writer) | 329 private static void WriteNull(TextWriter writer) |
| 276 { | 330 { |
| 277 writer.Write("null"); | 331 writer.Write("null"); |
| 278 } | 332 } |
| 279 | 333 |
| 280 private static bool IsDefaultValue(IFieldAccessor accessor, object value
) | 334 private static bool IsDefaultValue(IFieldAccessor accessor, object value
) |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 return (long) value == 0; | 370 return (long) value == 0; |
| 317 case FieldType.Float: | 371 case FieldType.Float: |
| 318 return (float) value == 0f; | 372 return (float) value == 0f; |
| 319 case FieldType.Message: | 373 case FieldType.Message: |
| 320 case FieldType.Group: // Never expect to get this, but... | 374 case FieldType.Group: // Never expect to get this, but... |
| 321 return value == null; | 375 return value == null; |
| 322 default: | 376 default: |
| 323 throw new ArgumentException("Invalid field type"); | 377 throw new ArgumentException("Invalid field type"); |
| 324 } | 378 } |
| 325 } | 379 } |
| 326 | 380 |
| 327 /// <summary> | 381 private void WriteValue(TextWriter writer, object value) |
| 328 /// Writes a single value to the given writer as JSON. Only types unders
tood by | |
| 329 /// Protocol Buffers can be written in this way. This method is only exp
osed for | |
| 330 /// advanced use cases; most users should be using <see cref="Format(IMe
ssage)"/> | |
| 331 /// or <see cref="Format(IMessage, TextWriter)"/>. | |
| 332 /// </summary> | |
| 333 /// <param name="writer">The writer to write the value to. Must not be n
ull.</param> | |
| 334 /// <param name="value">The value to write. May be null.</param> | |
| 335 public void WriteValue(TextWriter writer, object value) | |
| 336 { | 382 { |
| 337 if (value == null) | 383 if (value == null) |
| 338 { | 384 { |
| 339 WriteNull(writer); | 385 WriteNull(writer); |
| 340 } | 386 } |
| 341 else if (value is bool) | 387 else if (value is bool) |
| 342 { | 388 { |
| 343 writer.Write((bool)value ? "true" : "false"); | 389 writer.Write((bool)value ? "true" : "false"); |
| 344 } | 390 } |
| 345 else if (value is ByteString) | 391 else if (value is ByteString) |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 writer.Write(text); | 440 writer.Write(text); |
| 395 writer.Write('"'); | 441 writer.Write('"'); |
| 396 } | 442 } |
| 397 else | 443 else |
| 398 { | 444 { |
| 399 writer.Write(text); | 445 writer.Write(text); |
| 400 } | 446 } |
| 401 } | 447 } |
| 402 else if (value is IMessage) | 448 else if (value is IMessage) |
| 403 { | 449 { |
| 404 Format((IMessage)value, writer); | 450 IMessage message = (IMessage) value; |
| 451 if (message.Descriptor.IsWellKnownType) |
| 452 { |
| 453 WriteWellKnownTypeValue(writer, message.Descriptor, value); |
| 454 } |
| 455 else |
| 456 { |
| 457 WriteMessage(writer, (IMessage)value); |
| 458 } |
| 405 } | 459 } |
| 406 else | 460 else |
| 407 { | 461 { |
| 408 throw new ArgumentException("Unable to format value of type " +
value.GetType()); | 462 throw new ArgumentException("Unable to format value of type " +
value.GetType()); |
| 409 } | 463 } |
| 410 } | 464 } |
| 411 | 465 |
| 412 /// <summary> | 466 /// <summary> |
| 413 /// Central interception point for well-known type formatting. Any well-
known types which | 467 /// Central interception point for well-known type formatting. Any well-
known types which |
| 414 /// don't need special handling can fall back to WriteMessage. We avoid
assuming that the | 468 /// don't need special handling can fall back to WriteMessage. We avoid
assuming that the |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 } | 717 } |
| 664 WriteString(writer, keyText); | 718 WriteString(writer, keyText); |
| 665 writer.Write(NameValueSeparator); | 719 writer.Write(NameValueSeparator); |
| 666 WriteValue(writer, pair.Value); | 720 WriteValue(writer, pair.Value); |
| 667 first = false; | 721 first = false; |
| 668 } | 722 } |
| 669 writer.Write(first ? "}" : " }"); | 723 writer.Write(first ? "}" : " }"); |
| 670 } | 724 } |
| 671 | 725 |
| 672 /// <summary> | 726 /// <summary> |
| 727 /// Returns whether or not a singular value can be represented in JSON. |
| 728 /// Currently only relevant for enums, where unknown values can't be rep
resented. |
| 729 /// For repeated/map fields, this always returns true. |
| 730 /// </summary> |
| 731 private bool CanWriteSingleValue(object value) |
| 732 { |
| 733 if (value is System.Enum) |
| 734 { |
| 735 return System.Enum.IsDefined(value.GetType(), value); |
| 736 } |
| 737 return true; |
| 738 } |
| 739 |
| 740 /// <summary> |
| 673 /// Writes a string (including leading and trailing double quotes) to a
builder, escaping as required. | 741 /// Writes a string (including leading and trailing double quotes) to a
builder, escaping as required. |
| 674 /// </summary> | 742 /// </summary> |
| 675 /// <remarks> | 743 /// <remarks> |
| 676 /// Other than surrogate pair handling, this code is mostly taken from s
rc/google/protobuf/util/internal/json_escaping.cc. | 744 /// Other than surrogate pair handling, this code is mostly taken from s
rc/google/protobuf/util/internal/json_escaping.cc. |
| 677 /// </remarks> | 745 /// </remarks> |
| 678 internal static void WriteString(TextWriter writer, string text) | 746 internal static void WriteString(TextWriter writer, string text) |
| 679 { | 747 { |
| 680 writer.Write('"'); | 748 writer.Write('"'); |
| 681 for (int i = 0; i < text.Length; i++) | 749 for (int i = 0; i < text.Length; i++) |
| 682 { | 750 { |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 dictionaries[enumType] = nameMapping; | 892 dictionaries[enumType] = nameMapping; |
| 825 } | 893 } |
| 826 } | 894 } |
| 827 | 895 |
| 828 string originalName; | 896 string originalName; |
| 829 // If this returns false, originalName will be null, which is wh
at we want. | 897 // If this returns false, originalName will be null, which is wh
at we want. |
| 830 nameMapping.TryGetValue(value, out originalName); | 898 nameMapping.TryGetValue(value, out originalName); |
| 831 return originalName; | 899 return originalName; |
| 832 } | 900 } |
| 833 | 901 |
| 834 #if DOTNET35 | |
| 835 // TODO: Consider adding functionality to TypeExtensions to avoid th
is difference. | |
| 836 private static Dictionary<object, string> GetNameMapping(System.Type
enumType) => | |
| 837 enumType.GetFields(BindingFlags.NonPublic | BindingFlags.Public
| BindingFlags.Static) | |
| 838 .ToDictionary(f => f.GetValue(null), | |
| 839 f => (f.GetCustomAttributes(typeof(OriginalNam
eAttribute), false) | |
| 840 .FirstOrDefault() as OriginalNameAttribu
te) | |
| 841 // If the attribute hasn't been applied,
fall back to the name of the field. | |
| 842 ?.Name ?? f.Name); | |
| 843 #else | |
| 844 private static Dictionary<object, string> GetNameMapping(System.Type
enumType) => | 902 private static Dictionary<object, string> GetNameMapping(System.Type
enumType) => |
| 845 enumType.GetTypeInfo().DeclaredFields | 903 enumType.GetTypeInfo().DeclaredFields |
| 846 .Where(f => f.IsStatic) | 904 .Where(f => f.IsStatic) |
| 847 .ToDictionary(f => f.GetValue(null), | 905 .ToDictionary(f => f.GetValue(null), |
| 848 f => f.GetCustomAttributes<OriginalNameAttribu
te>() | 906 f => f.GetCustomAttributes<OriginalNameAttribu
te>() |
| 849 .FirstOrDefault() | 907 .FirstOrDefault() |
| 850 // If the attribute hasn't been applied,
fall back to the name of the field. | 908 // If the attribute hasn't been applied,
fall back to the name of the field. |
| 851 ?.Name ?? f.Name); | 909 ?.Name ?? f.Name); |
| 852 #endif | |
| 853 } | 910 } |
| 854 } | 911 } |
| 855 } | 912 } |
| OLD | NEW |