| Index: third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java
|
| diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/TextFormat.java b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java
|
| similarity index 95%
|
| rename from third_party/protobuf/java/src/main/java/com/google/protobuf/TextFormat.java
|
| rename to third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java
|
| index c99b52851291e67fc2a1c2ef57a238d3dc47285c..c1c328fc7d8d6ab01fa5521c73e3814ec9c39692 100644
|
| --- a/third_party/protobuf/java/src/main/java/com/google/protobuf/TextFormat.java
|
| +++ b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java
|
| @@ -425,7 +425,7 @@ public final class TextFormat {
|
| case STRING:
|
| generator.print("\"");
|
| generator.print(escapeNonAscii
|
| - ? escapeText((String) value)
|
| + ? TextFormatEscaper.escapeText((String) value)
|
| : escapeDoubleQuotesAndBackslashes((String) value)
|
| .replace("\n", "\\n"));
|
| generator.print("\"");
|
| @@ -661,6 +661,14 @@ public final class TextFormat {
|
| nextToken();
|
| }
|
|
|
| + int getLine() {
|
| + return line;
|
| + }
|
| +
|
| + int getColumn() {
|
| + return column;
|
| + }
|
| +
|
| /** Are we at the end of the input? */
|
| public boolean atEnd() {
|
| return currentToken.length() == 0;
|
| @@ -957,11 +965,13 @@ public final class TextFormat {
|
| */
|
| public boolean consumeBoolean() throws ParseException {
|
| if (currentToken.equals("true")
|
| + || currentToken.equals("True")
|
| || currentToken.equals("t")
|
| || currentToken.equals("1")) {
|
| nextToken();
|
| return true;
|
| } else if (currentToken.equals("false")
|
| + || currentToken.equals("False")
|
| || currentToken.equals("f")
|
| || currentToken.equals("0")) {
|
| nextToken();
|
| @@ -1074,7 +1084,7 @@ public final class TextFormat {
|
| private ParseException floatParseException(final NumberFormatException e) {
|
| return parseException("Couldn't parse number: " + e.getMessage());
|
| }
|
| -
|
| +
|
| /**
|
| * Returns a {@link UnknownFieldParseException} with the line and column
|
| * numbers of the previous token in the description, and the unknown field
|
| @@ -1133,7 +1143,7 @@ public final class TextFormat {
|
| return column;
|
| }
|
| }
|
| -
|
| +
|
| /**
|
| * Thrown when encountering an unknown field while parsing
|
| * a text format message.
|
| @@ -1257,11 +1267,14 @@ public final class TextFormat {
|
|
|
| private final boolean allowUnknownFields;
|
| private final SingularOverwritePolicy singularOverwritePolicy;
|
| + private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
|
|
|
| - private Parser(boolean allowUnknownFields,
|
| - SingularOverwritePolicy singularOverwritePolicy) {
|
| + private Parser(
|
| + boolean allowUnknownFields, SingularOverwritePolicy singularOverwritePolicy,
|
| + TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
|
| this.allowUnknownFields = allowUnknownFields;
|
| this.singularOverwritePolicy = singularOverwritePolicy;
|
| + this.parseInfoTreeBuilder = parseInfoTreeBuilder;
|
| }
|
|
|
| /**
|
| @@ -1278,6 +1291,7 @@ public final class TextFormat {
|
| private boolean allowUnknownFields = false;
|
| private SingularOverwritePolicy singularOverwritePolicy =
|
| SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
|
| + private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
|
|
|
|
|
| /**
|
| @@ -1288,8 +1302,15 @@ public final class TextFormat {
|
| return this;
|
| }
|
|
|
| + public Builder setParseInfoTreeBuilder(
|
| + TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
|
| + this.parseInfoTreeBuilder = parseInfoTreeBuilder;
|
| + return this;
|
| + }
|
| +
|
| public Parser build() {
|
| - return new Parser(allowUnknownFields, singularOverwritePolicy);
|
| + return new Parser(
|
| + allowUnknownFields, singularOverwritePolicy, parseInfoTreeBuilder);
|
| }
|
| }
|
|
|
| @@ -1380,7 +1401,21 @@ public final class TextFormat {
|
| final ExtensionRegistry extensionRegistry,
|
| final MessageReflection.MergeTarget target)
|
| throws ParseException {
|
| + mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder);
|
| + }
|
| +
|
| + /**
|
| + * Parse a single field from {@code tokenizer} and merge it into
|
| + * {@code builder}.
|
| + */
|
| + private void mergeField(final Tokenizer tokenizer,
|
| + final ExtensionRegistry extensionRegistry,
|
| + final MessageReflection.MergeTarget target,
|
| + TextFormatParseInfoTree.Builder parseTreeBuilder)
|
| + throws ParseException {
|
| FieldDescriptor field = null;
|
| + int startLine = tokenizer.getLine();
|
| + int startColumn = tokenizer.getColumn();
|
| final Descriptor type = target.getDescriptorForType();
|
| ExtensionRegistry.ExtensionInfo extension = null;
|
|
|
| @@ -1472,14 +1507,51 @@ public final class TextFormat {
|
| // Handle potential ':'.
|
| if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
| tokenizer.tryConsume(":"); // optional
|
| + if (parseTreeBuilder != null) {
|
| + TextFormatParseInfoTree.Builder childParseTreeBuilder =
|
| + parseTreeBuilder.getBuilderForSubMessageField(field);
|
| + consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
|
| + childParseTreeBuilder);
|
| + } else {
|
| + consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
|
| + parseTreeBuilder);
|
| + }
|
| } else {
|
| tokenizer.consume(":"); // required
|
| + consumeFieldValues(
|
| + tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
|
| }
|
| +
|
| + if (parseTreeBuilder != null) {
|
| + parseTreeBuilder.setLocation(
|
| + field, TextFormatParseLocation.create(startLine, startColumn));
|
| + }
|
| +
|
| + // For historical reasons, fields may optionally be separated by commas or
|
| + // semicolons.
|
| + if (!tokenizer.tryConsume(";")) {
|
| + tokenizer.tryConsume(",");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a one or more field values from {@code tokenizer} and merge it into
|
| + * {@code builder}.
|
| + */
|
| + private void consumeFieldValues(
|
| + final Tokenizer tokenizer,
|
| + final ExtensionRegistry extensionRegistry,
|
| + final MessageReflection.MergeTarget target,
|
| + final FieldDescriptor field,
|
| + final ExtensionRegistry.ExtensionInfo extension,
|
| + final TextFormatParseInfoTree.Builder parseTreeBuilder)
|
| + throws ParseException {
|
| // Support specifying repeated field values as a comma-separated list.
|
| // Ex."foo: [1, 2, 3]"
|
| if (field.isRepeated() && tokenizer.tryConsume("[")) {
|
| while (true) {
|
| - consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
|
| + consumeFieldValue(tokenizer, extensionRegistry, target, field, extension,
|
| + parseTreeBuilder);
|
| if (tokenizer.tryConsume("]")) {
|
| // End of list.
|
| break;
|
| @@ -1487,13 +1559,8 @@ public final class TextFormat {
|
| tokenizer.consume(",");
|
| }
|
| } else {
|
| - consumeFieldValue(tokenizer, extensionRegistry, target, field, extension);
|
| - }
|
| -
|
| - // For historical reasons, fields may optionally be separated by commas or
|
| - // semicolons.
|
| - if (!tokenizer.tryConsume(";")) {
|
| - tokenizer.tryConsume(",");
|
| + consumeFieldValue(
|
| + tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
|
| }
|
| }
|
|
|
| @@ -1506,7 +1573,8 @@ public final class TextFormat {
|
| final ExtensionRegistry extensionRegistry,
|
| final MessageReflection.MergeTarget target,
|
| final FieldDescriptor field,
|
| - final ExtensionRegistry.ExtensionInfo extension)
|
| + final ExtensionRegistry.ExtensionInfo extension,
|
| + final TextFormatParseInfoTree.Builder parseTreeBuilder)
|
| throws ParseException {
|
| Object value = null;
|
|
|
| @@ -1528,7 +1596,7 @@ public final class TextFormat {
|
| throw tokenizer.parseException(
|
| "Expected \"" + endToken + "\".");
|
| }
|
| - mergeField(tokenizer, extensionRegistry, subField);
|
| + mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder);
|
| }
|
|
|
| value = subField.finish();
|
| @@ -1704,52 +1772,6 @@ public final class TextFormat {
|
| // Some of these methods are package-private because Descriptors.java uses
|
| // them.
|
|
|
| - private interface ByteSequence {
|
| - int size();
|
| - byte byteAt(int offset);
|
| - }
|
| -
|
| - /**
|
| - * Escapes bytes in the format used in protocol buffer text format, which
|
| - * is the same as the format used for C string literals. All bytes
|
| - * that are not printable 7-bit ASCII characters are escaped, as well as
|
| - * backslash, single-quote, and double-quote characters. Characters for
|
| - * which no defined short-hand escape sequence is defined will be escaped
|
| - * using 3-digit octal sequences.
|
| - */
|
| - public static String escapeBytes(final ByteSequence input) {
|
| - final StringBuilder builder = new StringBuilder(input.size());
|
| - for (int i = 0; i < input.size(); i++) {
|
| - final byte b = input.byteAt(i);
|
| - switch (b) {
|
| - // Java does not recognize \a or \v, apparently.
|
| - case 0x07: builder.append("\\a"); break;
|
| - case '\b': builder.append("\\b"); break;
|
| - case '\f': builder.append("\\f"); break;
|
| - case '\n': builder.append("\\n"); break;
|
| - case '\r': builder.append("\\r"); break;
|
| - case '\t': builder.append("\\t"); break;
|
| - case 0x0b: builder.append("\\v"); break;
|
| - case '\\': builder.append("\\\\"); break;
|
| - case '\'': builder.append("\\\'"); break;
|
| - case '"' : builder.append("\\\""); break;
|
| - default:
|
| - // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are
|
| - // printable. Other byte values must be escaped.
|
| - if (b >= 0x20 && b <= 0x7e) {
|
| - builder.append((char) b);
|
| - } else {
|
| - builder.append('\\');
|
| - builder.append((char) ('0' + ((b >>> 6) & 3)));
|
| - builder.append((char) ('0' + ((b >>> 3) & 7)));
|
| - builder.append((char) ('0' + (b & 7)));
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - return builder.toString();
|
| - }
|
| -
|
| /**
|
| * Escapes bytes in the format used in protocol buffer text format, which
|
| * is the same as the format used for C string literals. All bytes
|
| @@ -1758,33 +1780,15 @@ public final class TextFormat {
|
| * which no defined short-hand escape sequence is defined will be escaped
|
| * using 3-digit octal sequences.
|
| */
|
| - public static String escapeBytes(final ByteString input) {
|
| - return escapeBytes(new ByteSequence() {
|
| - @Override
|
| - public int size() {
|
| - return input.size();
|
| - }
|
| - @Override
|
| - public byte byteAt(int offset) {
|
| - return input.byteAt(offset);
|
| - }
|
| - });
|
| + public static String escapeBytes(ByteString input) {
|
| + return TextFormatEscaper.escapeBytes(input);
|
| }
|
|
|
| /**
|
| * Like {@link #escapeBytes(ByteString)}, but used for byte array.
|
| */
|
| - public static String escapeBytes(final byte[] input) {
|
| - return escapeBytes(new ByteSequence() {
|
| - @Override
|
| - public int size() {
|
| - return input.length;
|
| - }
|
| - @Override
|
| - public byte byteAt(int offset) {
|
| - return input[offset];
|
| - }
|
| - });
|
| + public static String escapeBytes(byte[] input) {
|
| + return TextFormatEscaper.escapeBytes(input);
|
| }
|
|
|
| /**
|
| @@ -1868,7 +1872,9 @@ public final class TextFormat {
|
| }
|
| }
|
|
|
| - return ByteString.copyFrom(result, 0, pos);
|
| + return result.length == pos
|
| + ? ByteString.wrap(result) // This reference has not been out of our control.
|
| + : ByteString.copyFrom(result, 0, pos);
|
| }
|
|
|
| /**
|
| @@ -1896,7 +1902,7 @@ public final class TextFormat {
|
| * Escape double quotes and backslashes in a String for unicode output of a message.
|
| */
|
| public static String escapeDoubleQuotesAndBackslashes(final String input) {
|
| - return input.replace("\\", "\\\\").replace("\"", "\\\"");
|
| + return TextFormatEscaper.escapeDoubleQuotesAndBackslashes(input);
|
| }
|
|
|
| /**
|
|
|