| 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 /// <summary> | 251 // Converted from java/core/src/main/java/com/google/protobuf/Descriptor
s.java |
| 252 /// Camel-case converter with added strictness for field mask formatting
. | 252 internal static string ToJsonName(string name) |
| 253 /// </summary> | |
| 254 /// <exception cref="InvalidOperationException">The field mask is invali
d for JSON representation</exception> | |
| 255 private static string ToCamelCaseForFieldMask(string input) | |
| 256 { | 253 { |
| 257 for (int i = 0; i < input.Length; i++) | 254 StringBuilder result = new StringBuilder(name.Length); |
| 255 bool isNextUpperCase = false; |
| 256 foreach (char ch in name) |
| 258 { | 257 { |
| 259 char c = input[i]; | 258 if (ch == '_') |
| 260 if (c >= 'A' && c <= 'Z') | |
| 261 { | 259 { |
| 262 throw new InvalidOperationException($"Invalid field mask to
be converted to JSON: {input}"); | 260 isNextUpperCase = true; |
| 263 } | 261 } |
| 264 if (c == '_' && i < input.Length - 1) | 262 else if (isNextUpperCase) |
| 265 { | 263 { |
| 266 char next = input[i + 1]; | 264 result.Append(char.ToUpperInvariant(ch)); |
| 267 if (next < 'a' || next > 'z') | 265 isNextUpperCase = false; |
| 268 { | |
| 269 throw new InvalidOperationException($"Invalid field mask
to be converted to JSON: {input}"); | |
| 270 } | |
| 271 } | 266 } |
| 272 } | 267 else |
| 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] == '_') | |
| 290 { | 268 { |
| 291 capitalizeNext = true; | 269 result.Append(ch); |
| 292 if (result.Length != 0) | |
| 293 { | |
| 294 firstWord = false; | |
| 295 } | |
| 296 continue; | |
| 297 } | 270 } |
| 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]); | |
| 325 } | 271 } |
| 326 return result.ToString(); | 272 return result.ToString(); |
| 327 } | 273 } |
| 328 | 274 |
| 329 private static void WriteNull(TextWriter writer) | 275 private static void WriteNull(TextWriter writer) |
| 330 { | 276 { |
| 331 writer.Write("null"); | 277 writer.Write("null"); |
| 332 } | 278 } |
| 333 | 279 |
| 334 private static bool IsDefaultValue(IFieldAccessor accessor, object value
) | 280 private static bool IsDefaultValue(IFieldAccessor accessor, object value
) |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 return (long) value == 0; | 316 return (long) value == 0; |
| 371 case FieldType.Float: | 317 case FieldType.Float: |
| 372 return (float) value == 0f; | 318 return (float) value == 0f; |
| 373 case FieldType.Message: | 319 case FieldType.Message: |
| 374 case FieldType.Group: // Never expect to get this, but... | 320 case FieldType.Group: // Never expect to get this, but... |
| 375 return value == null; | 321 return value == null; |
| 376 default: | 322 default: |
| 377 throw new ArgumentException("Invalid field type"); | 323 throw new ArgumentException("Invalid field type"); |
| 378 } | 324 } |
| 379 } | 325 } |
| 380 | 326 |
| 381 private void WriteValue(TextWriter writer, object value) | 327 /// <summary> |
| 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) |
| 382 { | 336 { |
| 383 if (value == null) | 337 if (value == null) |
| 384 { | 338 { |
| 385 WriteNull(writer); | 339 WriteNull(writer); |
| 386 } | 340 } |
| 387 else if (value is bool) | 341 else if (value is bool) |
| 388 { | 342 { |
| 389 writer.Write((bool)value ? "true" : "false"); | 343 writer.Write((bool)value ? "true" : "false"); |
| 390 } | 344 } |
| 391 else if (value is ByteString) | 345 else if (value is ByteString) |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 writer.Write(text); | 394 writer.Write(text); |
| 441 writer.Write('"'); | 395 writer.Write('"'); |
| 442 } | 396 } |
| 443 else | 397 else |
| 444 { | 398 { |
| 445 writer.Write(text); | 399 writer.Write(text); |
| 446 } | 400 } |
| 447 } | 401 } |
| 448 else if (value is IMessage) | 402 else if (value is IMessage) |
| 449 { | 403 { |
| 450 IMessage message = (IMessage) value; | 404 Format((IMessage)value, writer); |
| 451 if (message.Descriptor.IsWellKnownType) | |
| 452 { | |
| 453 WriteWellKnownTypeValue(writer, message.Descriptor, value); | |
| 454 } | |
| 455 else | |
| 456 { | |
| 457 WriteMessage(writer, (IMessage)value); | |
| 458 } | |
| 459 } | 405 } |
| 460 else | 406 else |
| 461 { | 407 { |
| 462 throw new ArgumentException("Unable to format value of type " +
value.GetType()); | 408 throw new ArgumentException("Unable to format value of type " +
value.GetType()); |
| 463 } | 409 } |
| 464 } | 410 } |
| 465 | 411 |
| 466 /// <summary> | 412 /// <summary> |
| 467 /// Central interception point for well-known type formatting. Any well-
known types which | 413 /// Central interception point for well-known type formatting. Any well-
known types which |
| 468 /// don't need special handling can fall back to WriteMessage. We avoid
assuming that the | 414 /// 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... |
| 717 } | 663 } |
| 718 WriteString(writer, keyText); | 664 WriteString(writer, keyText); |
| 719 writer.Write(NameValueSeparator); | 665 writer.Write(NameValueSeparator); |
| 720 WriteValue(writer, pair.Value); | 666 WriteValue(writer, pair.Value); |
| 721 first = false; | 667 first = false; |
| 722 } | 668 } |
| 723 writer.Write(first ? "}" : " }"); | 669 writer.Write(first ? "}" : " }"); |
| 724 } | 670 } |
| 725 | 671 |
| 726 /// <summary> | 672 /// <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> | |
| 741 /// Writes a string (including leading and trailing double quotes) to a
builder, escaping as required. | 673 /// Writes a string (including leading and trailing double quotes) to a
builder, escaping as required. |
| 742 /// </summary> | 674 /// </summary> |
| 743 /// <remarks> | 675 /// <remarks> |
| 744 /// Other than surrogate pair handling, this code is mostly taken from s
rc/google/protobuf/util/internal/json_escaping.cc. | 676 /// Other than surrogate pair handling, this code is mostly taken from s
rc/google/protobuf/util/internal/json_escaping.cc. |
| 745 /// </remarks> | 677 /// </remarks> |
| 746 internal static void WriteString(TextWriter writer, string text) | 678 internal static void WriteString(TextWriter writer, string text) |
| 747 { | 679 { |
| 748 writer.Write('"'); | 680 writer.Write('"'); |
| 749 for (int i = 0; i < text.Length; i++) | 681 for (int i = 0; i < text.Length; i++) |
| 750 { | 682 { |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 dictionaries[enumType] = nameMapping; | 824 dictionaries[enumType] = nameMapping; |
| 893 } | 825 } |
| 894 } | 826 } |
| 895 | 827 |
| 896 string originalName; | 828 string originalName; |
| 897 // If this returns false, originalName will be null, which is wh
at we want. | 829 // If this returns false, originalName will be null, which is wh
at we want. |
| 898 nameMapping.TryGetValue(value, out originalName); | 830 nameMapping.TryGetValue(value, out originalName); |
| 899 return originalName; | 831 return originalName; |
| 900 } | 832 } |
| 901 | 833 |
| 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 |
| 902 private static Dictionary<object, string> GetNameMapping(System.Type
enumType) => | 844 private static Dictionary<object, string> GetNameMapping(System.Type
enumType) => |
| 903 enumType.GetTypeInfo().DeclaredFields | 845 enumType.GetTypeInfo().DeclaredFields |
| 904 .Where(f => f.IsStatic) | 846 .Where(f => f.IsStatic) |
| 905 .ToDictionary(f => f.GetValue(null), | 847 .ToDictionary(f => f.GetValue(null), |
| 906 f => f.GetCustomAttributes<OriginalNameAttribu
te>() | 848 f => f.GetCustomAttributes<OriginalNameAttribu
te>() |
| 907 .FirstOrDefault() | 849 .FirstOrDefault() |
| 908 // If the attribute hasn't been applied,
fall back to the name of the field. | 850 // If the attribute hasn't been applied,
fall back to the name of the field. |
| 909 ?.Name ?? f.Name); | 851 ?.Name ?? f.Name); |
| 852 #endif |
| 910 } | 853 } |
| 911 } | 854 } |
| 912 } | 855 } |
| OLD | NEW |