~ubuntu-branches/debian/stretch/protobuf/stretch

« back to all changes in this revision

Viewing changes to java/src/main/java/com/google/protobuf/TextFormat.java

  • Committer: Package Import Robot
  • Author(s): Robert S. Edmonds
  • Date: 2014-09-11 22:50:10 UTC
  • mfrom: (10.1.9 experimental)
  • Revision ID: package-import@ubuntu.com-20140911225010-wt4yo9dpc1fzuq5g
Tags: 2.6.0-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
package com.google.protobuf;
32
32
 
33
33
import com.google.protobuf.Descriptors.Descriptor;
34
 
import com.google.protobuf.Descriptors.FieldDescriptor;
35
34
import com.google.protobuf.Descriptors.EnumDescriptor;
36
35
import com.google.protobuf.Descriptors.EnumValueDescriptor;
 
36
import com.google.protobuf.Descriptors.FieldDescriptor;
37
37
 
38
38
import java.io.IOException;
 
39
import java.math.BigInteger;
39
40
import java.nio.CharBuffer;
40
 
import java.math.BigInteger;
41
41
import java.util.ArrayList;
42
42
import java.util.List;
43
43
import java.util.Locale;
44
44
import java.util.Map;
 
45
import java.util.logging.Logger;
45
46
import java.util.regex.Matcher;
46
47
import java.util.regex.Pattern;
47
48
 
55
56
public final class TextFormat {
56
57
  private TextFormat() {}
57
58
 
 
59
  private static final Logger logger =
 
60
      Logger.getLogger(TextFormat.class.getName());
 
61
 
58
62
  private static final Printer DEFAULT_PRINTER = new Printer();
59
63
  private static final Printer SINGLE_LINE_PRINTER =
60
64
      (new Printer()).setSingleLineMode(true);
66
70
   * the parameter output. (This representation is the new version of the
67
71
   * classic "ProtocolPrinter" output from the original Protocol Buffer system)
68
72
   */
69
 
  public static void print(final MessageOrBuilder message, final Appendable output)
70
 
                           throws IOException {
 
73
  public static void print(
 
74
      final MessageOrBuilder message, final Appendable output)
 
75
      throws IOException {
71
76
    DEFAULT_PRINTER.print(message, new TextGenerator(output));
72
77
  }
73
78
 
79
84
  }
80
85
 
81
86
  /**
 
87
   * Same as {@code print()}, except that non-ASCII characters are not
 
88
   * escaped.
 
89
   */
 
90
  public static void printUnicode(
 
91
      final MessageOrBuilder message, final Appendable output)
 
92
      throws IOException {
 
93
    UNICODE_PRINTER.print(message, new TextGenerator(output));
 
94
  }
 
95
 
 
96
  /**
 
97
   * Same as {@code print()}, except that non-ASCII characters are not
 
98
   * escaped.
 
99
   */
 
100
  public static void printUnicode(final UnknownFieldSet fields,
 
101
                                  final Appendable output)
 
102
                                  throws IOException {
 
103
    UNICODE_PRINTER.printUnknownFields(fields, new TextGenerator(output));
 
104
  }
 
105
 
 
106
  /**
82
107
   * Generates a human readable form of this message, useful for debugging and
83
108
   * other purposes, with no newline characters.
84
109
   */
266
291
      return this;
267
292
    }
268
293
 
269
 
    private void print(final MessageOrBuilder message, final TextGenerator generator)
 
294
    private void print(
 
295
        final MessageOrBuilder message, final TextGenerator generator)
270
296
        throws IOException {
271
297
      for (Map.Entry<FieldDescriptor, Object> field
272
298
          : message.getAllFields().entrySet()) {
385
411
          generator.print("\"");
386
412
          generator.print(escapeNonAscii ?
387
413
              escapeText((String) value) :
388
 
              (String) value);
 
414
              escapeDoubleQuotesAndBackslashes((String) value));
389
415
          generator.print("\"");
390
416
          break;
391
417
 
392
418
        case BYTES:
393
419
          generator.print("\"");
394
 
          generator.print(escapeBytes((ByteString) value));
 
420
          if (value instanceof ByteString) {
 
421
            generator.print(escapeBytes((ByteString) value));
 
422
          } else {
 
423
            generator.print(escapeBytes((byte[]) value));
 
424
          }
395
425
          generator.print("\"");
396
426
          break;
397
427
 
455
485
  }
456
486
 
457
487
  /** Convert an unsigned 32-bit integer to a string. */
458
 
  private static String unsignedToString(final int value) {
 
488
  public static String unsignedToString(final int value) {
459
489
    if (value >= 0) {
460
490
      return Integer.toString(value);
461
491
    } else {
462
 
      return Long.toString(((long) value) & 0x00000000FFFFFFFFL);
 
492
      return Long.toString(value & 0x00000000FFFFFFFFL);
463
493
    }
464
494
  }
465
495
 
466
496
  /** Convert an unsigned 64-bit integer to a string. */
467
 
  private static String unsignedToString(final long value) {
 
497
  public static String unsignedToString(final long value) {
468
498
    if (value >= 0) {
469
499
      return Long.toString(value);
470
500
    } else {
518
548
 
519
549
      for (int i = 0; i < size; i++) {
520
550
        if (text.charAt(i) == '\n') {
521
 
          write(text.subSequence(pos, size), i - pos + 1);
 
551
          write(text.subSequence(pos, i + 1));
522
552
          pos = i + 1;
523
553
          atStartOfLine = true;
524
554
        }
525
555
      }
526
 
      write(text.subSequence(pos, size), size - pos);
 
556
      write(text.subSequence(pos, size));
527
557
    }
528
558
 
529
 
    private void write(final CharSequence data, final int size)
530
 
                       throws IOException {
531
 
      if (size == 0) {
 
559
    private void write(final CharSequence data) throws IOException {
 
560
      if (data.length() == 0) {
532
561
        return;
533
562
      }
534
563
      if (atStartOfLine) {
705
734
    }
706
735
 
707
736
    /**
 
737
     * Returns {@code true} if the current token's text is equal to that
 
738
     * specified.
 
739
     */
 
740
    public boolean lookingAt(String text) {
 
741
      return currentToken.equals(text);
 
742
    }
 
743
 
 
744
    /**
708
745
     * If the next token is an identifier, consume it and return its value.
709
746
     * Otherwise, throw a {@link ParseException}.
710
747
     */
717
754
            (c == '_') || (c == '.')) {
718
755
          // OK
719
756
        } else {
720
 
          throw parseException("Expected identifier.");
 
757
          throw parseException(
 
758
              "Expected identifier. Found '" + currentToken + "'");
721
759
        }
722
760
      }
723
761
 
727
765
    }
728
766
 
729
767
    /**
 
768
     * If the next token is an identifier, consume it and return {@code true}.
 
769
     * Otherwise, return {@code false} without doing anything.
 
770
     */
 
771
    public boolean tryConsumeIdentifier() {
 
772
      try {
 
773
        consumeIdentifier();
 
774
        return true;
 
775
      } catch (ParseException e) {
 
776
        return false;
 
777
      }
 
778
    }
 
779
 
 
780
    /**
730
781
     * If the next token is a 32-bit signed integer, consume it and return its
731
782
     * value.  Otherwise, throw a {@link ParseException}.
732
783
     */
769
820
    }
770
821
 
771
822
    /**
 
823
     * If the next token is a 64-bit signed integer, consume it and return
 
824
     * {@code true}.  Otherwise, return {@code false} without doing anything.
 
825
     */
 
826
    public boolean tryConsumeInt64() {
 
827
      try {
 
828
        consumeInt64();
 
829
        return true;
 
830
      } catch (ParseException e) {
 
831
        return false;
 
832
      }
 
833
    }
 
834
 
 
835
    /**
772
836
     * If the next token is a 64-bit unsigned integer, consume it and return its
773
837
     * value.  Otherwise, throw a {@link ParseException}.
774
838
     */
783
847
    }
784
848
 
785
849
    /**
 
850
     * If the next token is a 64-bit unsigned integer, consume it and return
 
851
     * {@code true}.  Otherwise, return {@code false} without doing anything.
 
852
     */
 
853
    public boolean tryConsumeUInt64() {
 
854
      try {
 
855
        consumeUInt64();
 
856
        return true;
 
857
      } catch (ParseException e) {
 
858
        return false;
 
859
      }
 
860
    }
 
861
 
 
862
    /**
786
863
     * If the next token is a double, consume it and return its value.
787
864
     * Otherwise, throw a {@link ParseException}.
788
865
     */
808
885
    }
809
886
 
810
887
    /**
 
888
     * If the next token is a double, consume it and return {@code true}.
 
889
     * Otherwise, return {@code false} without doing anything.
 
890
     */
 
891
    public boolean tryConsumeDouble() {
 
892
      try {
 
893
        consumeDouble();
 
894
        return true;
 
895
      } catch (ParseException e) {
 
896
        return false;
 
897
      }
 
898
    }
 
899
 
 
900
    /**
811
901
     * If the next token is a float, consume it and return its value.
812
902
     * Otherwise, throw a {@link ParseException}.
813
903
     */
833
923
    }
834
924
 
835
925
    /**
 
926
     * If the next token is a float, consume it and return {@code true}.
 
927
     * Otherwise, return {@code false} without doing anything.
 
928
     */
 
929
    public boolean tryConsumeFloat() {
 
930
      try {
 
931
        consumeFloat();
 
932
        return true;
 
933
      } catch (ParseException e) {
 
934
        return false;
 
935
      }
 
936
    }
 
937
 
 
938
    /**
836
939
     * If the next token is a boolean, consume it and return its value.
837
940
     * Otherwise, throw a {@link ParseException}.
838
941
     */
861
964
    }
862
965
 
863
966
    /**
 
967
     * If the next token is a string, consume it and return true.  Otherwise,
 
968
     * return false.
 
969
     */
 
970
    public boolean tryConsumeString() {
 
971
      try {
 
972
        consumeString();
 
973
        return true;
 
974
      } catch (ParseException e) {
 
975
        return false;
 
976
      }
 
977
    }
 
978
 
 
979
    /**
864
980
     * If the next token is a string, consume it, unescape it as a
865
981
     * {@link ByteString}, and return it.  Otherwise, throw a
866
982
     * {@link ParseException}.
880
996
     * multiple adjacent tokens which are automatically concatenated, like in
881
997
     * C or Python.
882
998
     */
883
 
    private void consumeByteString(List<ByteString> list) throws ParseException {
 
999
    private void consumeByteString(List<ByteString> list)
 
1000
        throws ParseException {
884
1001
      final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
885
1002
                                                   : '\0';
886
1003
      if (quote != '\"' && quote != '\'') {
988
1105
    }
989
1106
  }
990
1107
 
991
 
  /**
992
 
   * Parse a text-format message from {@code input} and merge the contents
993
 
   * into {@code builder}.
994
 
   */
995
 
  public static void merge(final Readable input,
996
 
                           final Message.Builder builder)
997
 
                           throws IOException {
998
 
    merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
999
 
  }
1000
 
 
1001
 
  /**
1002
 
   * Parse a text-format message from {@code input} and merge the contents
1003
 
   * into {@code builder}.
1004
 
   */
1005
 
  public static void merge(final CharSequence input,
1006
 
                           final Message.Builder builder)
1007
 
                           throws ParseException {
1008
 
    merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
1009
 
  }
1010
 
 
1011
 
  /**
1012
 
   * Parse a text-format message from {@code input} and merge the contents
1013
 
   * into {@code builder}.  Extensions will be recognized if they are
1014
 
   * registered in {@code extensionRegistry}.
1015
 
   */
1016
 
  public static void merge(final Readable input,
1017
 
                           final ExtensionRegistry extensionRegistry,
1018
 
                           final Message.Builder builder)
1019
 
                           throws IOException {
1020
 
    // Read the entire input to a String then parse that.
1021
 
 
1022
 
    // If StreamTokenizer were not quite so crippled, or if there were a kind
1023
 
    // of Reader that could read in chunks that match some particular regex,
1024
 
    // or if we wanted to write a custom Reader to tokenize our stream, then
1025
 
    // we would not have to read to one big String.  Alas, none of these is
1026
 
    // the case.  Oh well.
1027
 
 
1028
 
    merge(toStringBuilder(input), extensionRegistry, builder);
1029
 
  }
1030
 
 
1031
 
  private static final int BUFFER_SIZE = 4096;
1032
 
 
1033
 
  // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
1034
 
  // overhead is worthwhile
1035
 
  private static StringBuilder toStringBuilder(final Readable input)
1036
 
      throws IOException {
1037
 
    final StringBuilder text = new StringBuilder();
1038
 
    final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
1039
 
    while (true) {
1040
 
      final int n = input.read(buffer);
1041
 
      if (n == -1) {
1042
 
        break;
1043
 
      }
1044
 
      buffer.flip();
1045
 
      text.append(buffer, 0, n);
1046
 
    }
1047
 
    return text;
1048
 
  }
1049
 
 
1050
 
  /**
1051
 
   * Parse a text-format message from {@code input} and merge the contents
1052
 
   * into {@code builder}.  Extensions will be recognized if they are
1053
 
   * registered in {@code extensionRegistry}.
1054
 
   */
1055
 
  public static void merge(final CharSequence input,
1056
 
                           final ExtensionRegistry extensionRegistry,
1057
 
                           final Message.Builder builder)
1058
 
                           throws ParseException {
1059
 
    final Tokenizer tokenizer = new Tokenizer(input);
1060
 
 
1061
 
    while (!tokenizer.atEnd()) {
1062
 
      mergeField(tokenizer, extensionRegistry, builder);
1063
 
    }
1064
 
  }
1065
 
 
1066
 
  /**
1067
 
   * Parse a single field from {@code tokenizer} and merge it into
1068
 
   * {@code builder}.
1069
 
   */
1070
 
  private static void mergeField(final Tokenizer tokenizer,
1071
 
                                 final ExtensionRegistry extensionRegistry,
1072
 
                                 final Message.Builder builder)
1073
 
                                 throws ParseException {
1074
 
    FieldDescriptor field;
1075
 
    final Descriptor type = builder.getDescriptorForType();
1076
 
    ExtensionRegistry.ExtensionInfo extension = null;
1077
 
 
1078
 
    if (tokenizer.tryConsume("[")) {
1079
 
      // An extension.
1080
 
      final StringBuilder name =
1081
 
          new StringBuilder(tokenizer.consumeIdentifier());
1082
 
      while (tokenizer.tryConsume(".")) {
1083
 
        name.append('.');
1084
 
        name.append(tokenizer.consumeIdentifier());
1085
 
      }
1086
 
 
1087
 
      extension = extensionRegistry.findExtensionByName(name.toString());
1088
 
 
1089
 
      if (extension == null) {
1090
 
        throw tokenizer.parseExceptionPreviousToken(
1091
 
          "Extension \"" + name + "\" not found in the ExtensionRegistry.");
1092
 
      } else if (extension.descriptor.getContainingType() != type) {
1093
 
        throw tokenizer.parseExceptionPreviousToken(
1094
 
          "Extension \"" + name + "\" does not extend message type \"" +
1095
 
          type.getFullName() + "\".");
1096
 
      }
1097
 
 
1098
 
      tokenizer.consume("]");
1099
 
 
1100
 
      field = extension.descriptor;
1101
 
    } else {
1102
 
      final String name = tokenizer.consumeIdentifier();
1103
 
      field = type.findFieldByName(name);
1104
 
 
1105
 
      // Group names are expected to be capitalized as they appear in the
1106
 
      // .proto file, which actually matches their type names, not their field
1107
 
      // names.
1108
 
      if (field == null) {
1109
 
        // Explicitly specify US locale so that this code does not break when
1110
 
        // executing in Turkey.
1111
 
        final String lowerName = name.toLowerCase(Locale.US);
1112
 
        field = type.findFieldByName(lowerName);
1113
 
        // If the case-insensitive match worked but the field is NOT a group,
1114
 
        if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
 
1108
  private static final Parser PARSER = Parser.newBuilder().build();
 
1109
 
 
1110
  /**
 
1111
   * Return a {@link Parser} instance which can parse text-format
 
1112
   * messages. The returned instance is thread-safe.
 
1113
   */
 
1114
  public static Parser getParser() {
 
1115
    return PARSER;
 
1116
  }
 
1117
 
 
1118
  /**
 
1119
   * Parse a text-format message from {@code input} and merge the contents
 
1120
   * into {@code builder}.
 
1121
   */
 
1122
  public static void merge(final Readable input,
 
1123
                           final Message.Builder builder)
 
1124
                           throws IOException {
 
1125
    PARSER.merge(input, builder);
 
1126
  }
 
1127
 
 
1128
  /**
 
1129
   * Parse a text-format message from {@code input} and merge the contents
 
1130
   * into {@code builder}.
 
1131
   */
 
1132
  public static void merge(final CharSequence input,
 
1133
                           final Message.Builder builder)
 
1134
                           throws ParseException {
 
1135
    PARSER.merge(input, builder);
 
1136
  }
 
1137
 
 
1138
  /**
 
1139
   * Parse a text-format message from {@code input} and merge the contents
 
1140
   * into {@code builder}.  Extensions will be recognized if they are
 
1141
   * registered in {@code extensionRegistry}.
 
1142
   */
 
1143
  public static void merge(final Readable input,
 
1144
                           final ExtensionRegistry extensionRegistry,
 
1145
                           final Message.Builder builder)
 
1146
                           throws IOException {
 
1147
    PARSER.merge(input, extensionRegistry, builder);
 
1148
  }
 
1149
 
 
1150
 
 
1151
  /**
 
1152
   * Parse a text-format message from {@code input} and merge the contents
 
1153
   * into {@code builder}.  Extensions will be recognized if they are
 
1154
   * registered in {@code extensionRegistry}.
 
1155
   */
 
1156
  public static void merge(final CharSequence input,
 
1157
                           final ExtensionRegistry extensionRegistry,
 
1158
                           final Message.Builder builder)
 
1159
                           throws ParseException {
 
1160
    PARSER.merge(input, extensionRegistry, builder);
 
1161
  }
 
1162
 
 
1163
 
 
1164
  /**
 
1165
   * Parser for text-format proto2 instances. This class is thread-safe.
 
1166
   * The implementation largely follows google/protobuf/text_format.cc.
 
1167
   *
 
1168
   * <p>Use {@link TextFormat#getParser()} to obtain the default parser, or
 
1169
   * {@link Builder} to control the parser behavior.
 
1170
   */
 
1171
  public static class Parser {
 
1172
    /**
 
1173
     * Determines if repeated values for non-repeated fields and
 
1174
     * oneofs are permitted. For example, given required/optional field "foo"
 
1175
     * and a oneof containing "baz" and "qux":
 
1176
     * <li>
 
1177
     * <ul>"foo: 1 foo: 2"
 
1178
     * <ul>"baz: 1 qux: 2"
 
1179
     * <ul>merging "foo: 2" into a proto in which foo is already set, or
 
1180
     * <ul>merging "qux: 2" into a proto in which baz is already set.
 
1181
     * </li>
 
1182
     */
 
1183
    public enum SingularOverwritePolicy {
 
1184
      /** The last value is retained. */
 
1185
      ALLOW_SINGULAR_OVERWRITES,
 
1186
      /** An error is issued. */
 
1187
      FORBID_SINGULAR_OVERWRITES
 
1188
    }
 
1189
 
 
1190
    private final boolean allowUnknownFields;
 
1191
    private final SingularOverwritePolicy singularOverwritePolicy;
 
1192
 
 
1193
    private Parser(boolean allowUnknownFields,
 
1194
        SingularOverwritePolicy singularOverwritePolicy) {
 
1195
      this.allowUnknownFields = allowUnknownFields;
 
1196
      this.singularOverwritePolicy = singularOverwritePolicy;
 
1197
    }
 
1198
 
 
1199
    /**
 
1200
     * Returns a new instance of {@link Builder}.
 
1201
     */
 
1202
    public static Builder newBuilder() {
 
1203
      return new Builder();
 
1204
    }
 
1205
 
 
1206
    /**
 
1207
     * Builder that can be used to obtain new instances of {@link Parser}.
 
1208
     */
 
1209
    public static class Builder {
 
1210
      private boolean allowUnknownFields = false;
 
1211
      private SingularOverwritePolicy singularOverwritePolicy =
 
1212
          SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
 
1213
 
 
1214
      /**
 
1215
       * Sets parser behavior when a non-repeated field appears more than once.
 
1216
       */
 
1217
      public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) {
 
1218
        this.singularOverwritePolicy = p;
 
1219
        return this;
 
1220
      }
 
1221
 
 
1222
      public Parser build() {
 
1223
        return new Parser(allowUnknownFields, singularOverwritePolicy);
 
1224
      }
 
1225
    }
 
1226
 
 
1227
    /**
 
1228
     * Parse a text-format message from {@code input} and merge the contents
 
1229
     * into {@code builder}.
 
1230
     */
 
1231
    public void merge(final Readable input,
 
1232
                      final Message.Builder builder)
 
1233
                      throws IOException {
 
1234
      merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
 
1235
    }
 
1236
 
 
1237
    /**
 
1238
     * Parse a text-format message from {@code input} and merge the contents
 
1239
     * into {@code builder}.
 
1240
     */
 
1241
    public void merge(final CharSequence input,
 
1242
                      final Message.Builder builder)
 
1243
                      throws ParseException {
 
1244
      merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
 
1245
    }
 
1246
 
 
1247
    /**
 
1248
     * Parse a text-format message from {@code input} and merge the contents
 
1249
     * into {@code builder}.  Extensions will be recognized if they are
 
1250
     * registered in {@code extensionRegistry}.
 
1251
     */
 
1252
    public void merge(final Readable input,
 
1253
                      final ExtensionRegistry extensionRegistry,
 
1254
                      final Message.Builder builder)
 
1255
                      throws IOException {
 
1256
      // Read the entire input to a String then parse that.
 
1257
 
 
1258
      // If StreamTokenizer were not quite so crippled, or if there were a kind
 
1259
      // of Reader that could read in chunks that match some particular regex,
 
1260
      // or if we wanted to write a custom Reader to tokenize our stream, then
 
1261
      // we would not have to read to one big String.  Alas, none of these is
 
1262
      // the case.  Oh well.
 
1263
 
 
1264
      merge(toStringBuilder(input), extensionRegistry, builder);
 
1265
    }
 
1266
 
 
1267
 
 
1268
    private static final int BUFFER_SIZE = 4096;
 
1269
 
 
1270
    // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
 
1271
    // overhead is worthwhile
 
1272
    private static StringBuilder toStringBuilder(final Readable input)
 
1273
        throws IOException {
 
1274
      final StringBuilder text = new StringBuilder();
 
1275
      final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
 
1276
      while (true) {
 
1277
        final int n = input.read(buffer);
 
1278
        if (n == -1) {
 
1279
          break;
 
1280
        }
 
1281
        buffer.flip();
 
1282
        text.append(buffer, 0, n);
 
1283
      }
 
1284
      return text;
 
1285
    }
 
1286
 
 
1287
    /**
 
1288
     * Parse a text-format message from {@code input} and merge the contents
 
1289
     * into {@code builder}.  Extensions will be recognized if they are
 
1290
     * registered in {@code extensionRegistry}.
 
1291
     */
 
1292
    public void merge(final CharSequence input,
 
1293
                      final ExtensionRegistry extensionRegistry,
 
1294
                      final Message.Builder builder)
 
1295
                      throws ParseException {
 
1296
      final Tokenizer tokenizer = new Tokenizer(input);
 
1297
      MessageReflection.BuilderAdapter target =
 
1298
          new MessageReflection.BuilderAdapter(builder);
 
1299
 
 
1300
      while (!tokenizer.atEnd()) {
 
1301
        mergeField(tokenizer, extensionRegistry, target);
 
1302
      }
 
1303
    }
 
1304
 
 
1305
 
 
1306
    /**
 
1307
     * Parse a single field from {@code tokenizer} and merge it into
 
1308
     * {@code builder}.
 
1309
     */
 
1310
    private void mergeField(final Tokenizer tokenizer,
 
1311
                            final ExtensionRegistry extensionRegistry,
 
1312
                            final MessageReflection.MergeTarget target)
 
1313
                            throws ParseException {
 
1314
      FieldDescriptor field = null;
 
1315
      final Descriptor type = target.getDescriptorForType();
 
1316
      ExtensionRegistry.ExtensionInfo extension = null;
 
1317
 
 
1318
      if (tokenizer.tryConsume("[")) {
 
1319
        // An extension.
 
1320
        final StringBuilder name =
 
1321
            new StringBuilder(tokenizer.consumeIdentifier());
 
1322
        while (tokenizer.tryConsume(".")) {
 
1323
          name.append('.');
 
1324
          name.append(tokenizer.consumeIdentifier());
 
1325
        }
 
1326
 
 
1327
        extension = target.findExtensionByName(
 
1328
            extensionRegistry, name.toString());
 
1329
 
 
1330
        if (extension == null) {
 
1331
          if (!allowUnknownFields) {
 
1332
            throw tokenizer.parseExceptionPreviousToken(
 
1333
              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
 
1334
          } else {
 
1335
            logger.warning(
 
1336
              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
 
1337
          }
 
1338
        } else {
 
1339
          if (extension.descriptor.getContainingType() != type) {
 
1340
            throw tokenizer.parseExceptionPreviousToken(
 
1341
              "Extension \"" + name + "\" does not extend message type \"" +
 
1342
              type.getFullName() + "\".");
 
1343
          }
 
1344
          field = extension.descriptor;
 
1345
        }
 
1346
 
 
1347
        tokenizer.consume("]");
 
1348
      } else {
 
1349
        final String name = tokenizer.consumeIdentifier();
 
1350
        field = type.findFieldByName(name);
 
1351
 
 
1352
        // Group names are expected to be capitalized as they appear in the
 
1353
        // .proto file, which actually matches their type names, not their field
 
1354
        // names.
 
1355
        if (field == null) {
 
1356
          // Explicitly specify US locale so that this code does not break when
 
1357
          // executing in Turkey.
 
1358
          final String lowerName = name.toLowerCase(Locale.US);
 
1359
          field = type.findFieldByName(lowerName);
 
1360
          // If the case-insensitive match worked but the field is NOT a group,
 
1361
          if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
 
1362
            field = null;
 
1363
          }
 
1364
        }
 
1365
        // Again, special-case group names as described above.
 
1366
        if (field != null && field.getType() == FieldDescriptor.Type.GROUP &&
 
1367
            !field.getMessageType().getName().equals(name)) {
1115
1368
          field = null;
1116
1369
        }
1117
 
      }
1118
 
      // Again, special-case group names as described above.
1119
 
      if (field != null && field.getType() == FieldDescriptor.Type.GROUP &&
1120
 
          !field.getMessageType().getName().equals(name)) {
1121
 
        field = null;
1122
 
      }
1123
 
 
 
1370
 
 
1371
        if (field == null) {
 
1372
          if (!allowUnknownFields) {
 
1373
            throw tokenizer.parseExceptionPreviousToken(
 
1374
              "Message type \"" + type.getFullName() +
 
1375
              "\" has no field named \"" + name + "\".");
 
1376
          } else {
 
1377
            logger.warning(
 
1378
              "Message type \"" + type.getFullName() +
 
1379
              "\" has no field named \"" + name + "\".");
 
1380
          }
 
1381
        }
 
1382
      }
 
1383
 
 
1384
      // Skips unknown fields.
1124
1385
      if (field == null) {
1125
 
        throw tokenizer.parseExceptionPreviousToken(
1126
 
          "Message type \"" + type.getFullName() +
1127
 
          "\" has no field named \"" + name + "\".");
1128
 
      }
1129
 
    }
1130
 
 
1131
 
    Object value = null;
1132
 
 
1133
 
    if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
1134
 
      tokenizer.tryConsume(":");  // optional
1135
 
 
1136
 
      final String endToken;
 
1386
        // Try to guess the type of this field.
 
1387
        // If this field is not a message, there should be a ":" between the
 
1388
        // field name and the field value and also the field value should not
 
1389
        // start with "{" or "<" which indicates the begining of a message body.
 
1390
        // If there is no ":" or there is a "{" or "<" after ":", this field has
 
1391
        // to be a message or the input is ill-formed.
 
1392
        if (tokenizer.tryConsume(":") && !tokenizer.lookingAt("{") &&
 
1393
            !tokenizer.lookingAt("<")) {
 
1394
          skipFieldValue(tokenizer);
 
1395
        } else {
 
1396
          skipFieldMessage(tokenizer);
 
1397
        }
 
1398
        return;
 
1399
      }
 
1400
 
 
1401
      // Handle potential ':'.
 
1402
      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
 
1403
        tokenizer.tryConsume(":");  // optional
 
1404
      } else {
 
1405
        tokenizer.consume(":");  // required
 
1406
      }
 
1407
      // Support specifying repeated field values as a comma-separated list.
 
1408
      // Ex."foo: [1, 2, 3]"
 
1409
      if (field.isRepeated() && tokenizer.tryConsume("[")) {
 
1410
        while (true) {
 
1411
          consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
 
1412
          if (tokenizer.tryConsume("]")) {
 
1413
            // End of list.
 
1414
            break;
 
1415
          }
 
1416
          tokenizer.consume(",");
 
1417
        }
 
1418
      } else {
 
1419
        consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
 
1420
      }
 
1421
    }
 
1422
 
 
1423
    /**
 
1424
     * Parse a single field value from {@code tokenizer} and merge it into
 
1425
     * {@code builder}.
 
1426
     */
 
1427
    private void consumeFieldValue(
 
1428
        final Tokenizer tokenizer,
 
1429
        final ExtensionRegistry extensionRegistry,
 
1430
        final MessageReflection.MergeTarget target,
 
1431
        final FieldDescriptor field,
 
1432
        final ExtensionRegistry.ExtensionInfo extension)
 
1433
        throws ParseException {
 
1434
      Object value = null;
 
1435
 
 
1436
      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
 
1437
        final String endToken;
 
1438
        if (tokenizer.tryConsume("<")) {
 
1439
          endToken = ">";
 
1440
        } else {
 
1441
          tokenizer.consume("{");
 
1442
          endToken = "}";
 
1443
        }
 
1444
 
 
1445
        final MessageReflection.MergeTarget subField;
 
1446
        subField = target.newMergeTargetForField(field,
 
1447
            (extension == null) ? null : extension.defaultInstance);
 
1448
 
 
1449
        while (!tokenizer.tryConsume(endToken)) {
 
1450
          if (tokenizer.atEnd()) {
 
1451
            throw tokenizer.parseException(
 
1452
              "Expected \"" + endToken + "\".");
 
1453
          }
 
1454
          mergeField(tokenizer, extensionRegistry, subField);
 
1455
        }
 
1456
 
 
1457
        value = subField.finish();
 
1458
 
 
1459
      } else {
 
1460
        switch (field.getType()) {
 
1461
          case INT32:
 
1462
          case SINT32:
 
1463
          case SFIXED32:
 
1464
            value = tokenizer.consumeInt32();
 
1465
            break;
 
1466
 
 
1467
          case INT64:
 
1468
          case SINT64:
 
1469
          case SFIXED64:
 
1470
            value = tokenizer.consumeInt64();
 
1471
            break;
 
1472
 
 
1473
          case UINT32:
 
1474
          case FIXED32:
 
1475
            value = tokenizer.consumeUInt32();
 
1476
            break;
 
1477
 
 
1478
          case UINT64:
 
1479
          case FIXED64:
 
1480
            value = tokenizer.consumeUInt64();
 
1481
            break;
 
1482
 
 
1483
          case FLOAT:
 
1484
            value = tokenizer.consumeFloat();
 
1485
            break;
 
1486
 
 
1487
          case DOUBLE:
 
1488
            value = tokenizer.consumeDouble();
 
1489
            break;
 
1490
 
 
1491
          case BOOL:
 
1492
            value = tokenizer.consumeBoolean();
 
1493
            break;
 
1494
 
 
1495
          case STRING:
 
1496
            value = tokenizer.consumeString();
 
1497
            break;
 
1498
 
 
1499
          case BYTES:
 
1500
            value = tokenizer.consumeByteString();
 
1501
            break;
 
1502
 
 
1503
          case ENUM:
 
1504
            final EnumDescriptor enumType = field.getEnumType();
 
1505
 
 
1506
            if (tokenizer.lookingAtInteger()) {
 
1507
              final int number = tokenizer.consumeInt32();
 
1508
              value = enumType.findValueByNumber(number);
 
1509
              if (value == null) {
 
1510
                throw tokenizer.parseExceptionPreviousToken(
 
1511
                  "Enum type \"" + enumType.getFullName() +
 
1512
                  "\" has no value with number " + number + '.');
 
1513
              }
 
1514
            } else {
 
1515
              final String id = tokenizer.consumeIdentifier();
 
1516
              value = enumType.findValueByName(id);
 
1517
              if (value == null) {
 
1518
                throw tokenizer.parseExceptionPreviousToken(
 
1519
                  "Enum type \"" + enumType.getFullName() +
 
1520
                  "\" has no value named \"" + id + "\".");
 
1521
              }
 
1522
            }
 
1523
 
 
1524
            break;
 
1525
 
 
1526
          case MESSAGE:
 
1527
          case GROUP:
 
1528
            throw new RuntimeException("Can't get here.");
 
1529
        }
 
1530
      }
 
1531
 
 
1532
      if (field.isRepeated()) {
 
1533
        target.addRepeatedField(field, value);
 
1534
      } else if ((singularOverwritePolicy
 
1535
              == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
 
1536
          && target.hasField(field)) {
 
1537
        throw tokenizer.parseExceptionPreviousToken("Non-repeated field \""
 
1538
            + field.getFullName() + "\" cannot be overwritten.");
 
1539
      } else if ((singularOverwritePolicy
 
1540
              == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
 
1541
          && field.getContainingOneof() != null
 
1542
          && target.hasOneof(field.getContainingOneof())) {
 
1543
        Descriptors.OneofDescriptor oneof = field.getContainingOneof();
 
1544
        throw tokenizer.parseExceptionPreviousToken("Field \""
 
1545
            + field.getFullName() + "\" is specified along with field \""
 
1546
            + target.getOneofFieldDescriptor(oneof).getFullName()
 
1547
            + "\", another member of oneof \"" + oneof.getName() + "\".");
 
1548
      } else {
 
1549
        target.setField(field, value);
 
1550
      }
 
1551
    }
 
1552
 
 
1553
    /**
 
1554
     * Skips the next field including the field's name and value.
 
1555
     */
 
1556
    private void skipField(Tokenizer tokenizer) throws ParseException {
 
1557
      if (tokenizer.tryConsume("[")) {
 
1558
        // Extension name.
 
1559
        do {
 
1560
          tokenizer.consumeIdentifier();
 
1561
        } while (tokenizer.tryConsume("."));
 
1562
        tokenizer.consume("]");
 
1563
      } else {
 
1564
        tokenizer.consumeIdentifier();
 
1565
      }
 
1566
 
 
1567
      // Try to guess the type of this field.
 
1568
      // If this field is not a message, there should be a ":" between the
 
1569
      // field name and the field value and also the field value should not
 
1570
      // start with "{" or "<" which indicates the begining of a message body.
 
1571
      // If there is no ":" or there is a "{" or "<" after ":", this field has
 
1572
      // to be a message or the input is ill-formed.
 
1573
      if (tokenizer.tryConsume(":") && !tokenizer.lookingAt("<") &&
 
1574
          !tokenizer.lookingAt("{")) {
 
1575
        skipFieldValue(tokenizer);
 
1576
      } else {
 
1577
        skipFieldMessage(tokenizer);
 
1578
      }
 
1579
      // For historical reasons, fields may optionally be separated by commas or
 
1580
      // semicolons.
 
1581
      if (!tokenizer.tryConsume(";")) {
 
1582
        tokenizer.tryConsume(",");
 
1583
      }
 
1584
    }
 
1585
 
 
1586
    /**
 
1587
     * Skips the whole body of a message including the beginning delimeter and
 
1588
     * the ending delimeter.
 
1589
     */
 
1590
    private void skipFieldMessage(Tokenizer tokenizer) throws ParseException {
 
1591
      final String delimiter;
1137
1592
      if (tokenizer.tryConsume("<")) {
1138
 
        endToken = ">";
 
1593
        delimiter = ">";
1139
1594
      } else {
1140
1595
        tokenizer.consume("{");
1141
 
        endToken = "}";
1142
 
      }
1143
 
 
1144
 
      final Message.Builder subBuilder;
1145
 
      if (extension == null) {
1146
 
        subBuilder = builder.newBuilderForField(field);
1147
 
      } else {
1148
 
        subBuilder = extension.defaultInstance.newBuilderForType();
1149
 
      }
1150
 
 
1151
 
      while (!tokenizer.tryConsume(endToken)) {
1152
 
        if (tokenizer.atEnd()) {
1153
 
          throw tokenizer.parseException(
1154
 
            "Expected \"" + endToken + "\".");
1155
 
        }
1156
 
        mergeField(tokenizer, extensionRegistry, subBuilder);
1157
 
      }
1158
 
 
1159
 
      value = subBuilder.buildPartial();
1160
 
 
1161
 
    } else {
1162
 
      tokenizer.consume(":");
1163
 
 
1164
 
      switch (field.getType()) {
1165
 
        case INT32:
1166
 
        case SINT32:
1167
 
        case SFIXED32:
1168
 
          value = tokenizer.consumeInt32();
1169
 
          break;
1170
 
 
1171
 
        case INT64:
1172
 
        case SINT64:
1173
 
        case SFIXED64:
1174
 
          value = tokenizer.consumeInt64();
1175
 
          break;
1176
 
 
1177
 
        case UINT32:
1178
 
        case FIXED32:
1179
 
          value = tokenizer.consumeUInt32();
1180
 
          break;
1181
 
 
1182
 
        case UINT64:
1183
 
        case FIXED64:
1184
 
          value = tokenizer.consumeUInt64();
1185
 
          break;
1186
 
 
1187
 
        case FLOAT:
1188
 
          value = tokenizer.consumeFloat();
1189
 
          break;
1190
 
 
1191
 
        case DOUBLE:
1192
 
          value = tokenizer.consumeDouble();
1193
 
          break;
1194
 
 
1195
 
        case BOOL:
1196
 
          value = tokenizer.consumeBoolean();
1197
 
          break;
1198
 
 
1199
 
        case STRING:
1200
 
          value = tokenizer.consumeString();
1201
 
          break;
1202
 
 
1203
 
        case BYTES:
1204
 
          value = tokenizer.consumeByteString();
1205
 
          break;
1206
 
 
1207
 
        case ENUM:
1208
 
          final EnumDescriptor enumType = field.getEnumType();
1209
 
 
1210
 
          if (tokenizer.lookingAtInteger()) {
1211
 
            final int number = tokenizer.consumeInt32();
1212
 
            value = enumType.findValueByNumber(number);
1213
 
            if (value == null) {
1214
 
              throw tokenizer.parseExceptionPreviousToken(
1215
 
                "Enum type \"" + enumType.getFullName() +
1216
 
                "\" has no value with number " + number + '.');
1217
 
            }
1218
 
          } else {
1219
 
            final String id = tokenizer.consumeIdentifier();
1220
 
            value = enumType.findValueByName(id);
1221
 
            if (value == null) {
1222
 
              throw tokenizer.parseExceptionPreviousToken(
1223
 
                "Enum type \"" + enumType.getFullName() +
1224
 
                "\" has no value named \"" + id + "\".");
1225
 
            }
1226
 
          }
1227
 
 
1228
 
          break;
1229
 
 
1230
 
        case MESSAGE:
1231
 
        case GROUP:
1232
 
          throw new RuntimeException("Can't get here.");
1233
 
      }
 
1596
        delimiter = "}";
 
1597
      }
 
1598
      while (!tokenizer.lookingAt(">") && !tokenizer.lookingAt("}")) {
 
1599
        skipField(tokenizer);
 
1600
      }
 
1601
      tokenizer.consume(delimiter);
1234
1602
    }
1235
1603
 
1236
 
    if (field.isRepeated()) {
1237
 
      builder.addRepeatedField(field, value);
1238
 
    } else {
1239
 
      builder.setField(field, value);
 
1604
    /**
 
1605
     * Skips a field value.
 
1606
     */
 
1607
    private void skipFieldValue(Tokenizer tokenizer) throws ParseException {
 
1608
      if (tokenizer.tryConsumeString()) {
 
1609
        while (tokenizer.tryConsumeString()) {}
 
1610
        return;
 
1611
      }
 
1612
      if (!tokenizer.tryConsumeIdentifier() &&  // includes enum & boolean
 
1613
          !tokenizer.tryConsumeInt64() &&       // includes int32
 
1614
          !tokenizer.tryConsumeUInt64() &&      // includes uint32
 
1615
          !tokenizer.tryConsumeDouble() &&
 
1616
          !tokenizer.tryConsumeFloat()) {
 
1617
        throw tokenizer.parseException(
 
1618
            "Invalid field value: " + tokenizer.currentToken);
 
1619
      }
1240
1620
    }
1241
1621
  }
1242
1622
 
1246
1626
  // Some of these methods are package-private because Descriptors.java uses
1247
1627
  // them.
1248
1628
 
 
1629
  private interface ByteSequence {
 
1630
    int size();
 
1631
    byte byteAt(int offset);
 
1632
  }
 
1633
 
1249
1634
  /**
1250
1635
   * Escapes bytes in the format used in protocol buffer text format, which
1251
1636
   * is the same as the format used for C string literals.  All bytes
1254
1639
   * which no defined short-hand escape sequence is defined will be escaped
1255
1640
   * using 3-digit octal sequences.
1256
1641
   */
1257
 
  static String escapeBytes(final ByteString input) {
 
1642
  private static String escapeBytes(final ByteSequence input) {
1258
1643
    final StringBuilder builder = new StringBuilder(input.size());
1259
1644
    for (int i = 0; i < input.size(); i++) {
1260
1645
      final byte b = input.byteAt(i);
1289
1674
  }
1290
1675
 
1291
1676
  /**
 
1677
   * Escapes bytes in the format used in protocol buffer text format, which
 
1678
   * is the same as the format used for C string literals.  All bytes
 
1679
   * that are not printable 7-bit ASCII characters are escaped, as well as
 
1680
   * backslash, single-quote, and double-quote characters.  Characters for
 
1681
   * which no defined short-hand escape sequence is defined will be escaped
 
1682
   * using 3-digit octal sequences.
 
1683
   */
 
1684
  static String escapeBytes(final ByteString input) {
 
1685
    return escapeBytes(new ByteSequence() {
 
1686
      public int size() {
 
1687
        return input.size();
 
1688
      }
 
1689
      public byte byteAt(int offset) {
 
1690
        return input.byteAt(offset);
 
1691
      }
 
1692
    });
 
1693
  }
 
1694
 
 
1695
  /**
 
1696
   * Like {@link #escapeBytes(ByteString)}, but used for byte array.
 
1697
   */
 
1698
  static String escapeBytes(final byte[] input) {
 
1699
    return escapeBytes(new ByteSequence() {
 
1700
      public int size() {
 
1701
        return input.length;
 
1702
      }
 
1703
      public byte byteAt(int offset) {
 
1704
        return input[offset];
 
1705
      }
 
1706
    });
 
1707
  }
 
1708
 
 
1709
  /**
1292
1710
   * Un-escape a byte sequence as escaped using
1293
1711
   * {@link #escapeBytes(ByteString)}.  Two-digit hex escapes (starting with
1294
1712
   * "\x") are also recognized.
1394
1812
  }
1395
1813
 
1396
1814
  /**
 
1815
   * Escape double quotes and backslashes in a String for unicode output of a message.
 
1816
   */
 
1817
  public static String escapeDoubleQuotesAndBackslashes(final String input) {
 
1818
    return input.replace("\\", "\\\\").replace("\"", "\\\"");
 
1819
  }
 
1820
 
 
1821
  /**
1397
1822
   * Un-escape a text string as escaped using {@link #escapeText(String)}.
1398
1823
   * Two-digit hex escapes (starting with "\x") are also recognized.
1399
1824
   */