aboutsummaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorkenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-12-23 01:23:06 +0000
committerkenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-12-23 01:23:06 +0000
commit35d2f017a7a685d700a8899d06d709cbffaaa885 (patch)
tree85112b072a34b483904b94d13720b2a003e69c4c /java
parent6e8b9e4a4a478c99a93925035b004a3829fd1e4f (diff)
downloadprotobuf-35d2f017a7a685d700a8899d06d709cbffaaa885.tar.gz
protobuf-35d2f017a7a685d700a8899d06d709cbffaaa885.tar.bz2
protobuf-35d2f017a7a685d700a8899d06d709cbffaaa885.zip
In Java's TextFormat, correcty concatenate adjacent string literals, as C++ does. Also fix a bug in handling of single-quoted strings.
Diffstat (limited to 'java')
-rw-r--r--java/src/main/java/com/google/protobuf/ByteString.java29
-rw-r--r--java/src/main/java/com/google/protobuf/TextFormat.java20
-rw-r--r--java/src/test/java/com/google/protobuf/TextFormatTest.java10
3 files changed, 52 insertions, 7 deletions
diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java
index c043df8b..5fade03a 100644
--- a/java/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/src/main/java/com/google/protobuf/ByteString.java
@@ -36,6 +36,7 @@ import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
+import java.util.List;
/**
* Immutable array of bytes.
@@ -137,6 +138,34 @@ public final class ByteString {
}
}
+ /**
+ * Concatenates all byte strings in the list and returns the result.
+ *
+ * <p>The returned {@code ByteString} is not necessarily a unique object.
+ * If the list is empty, the returned object is the singleton empty
+ * {@code ByteString}. If the list has only one element, that
+ * {@code ByteString} will be returned without copying.
+ */
+ public static ByteString copyFrom(List<ByteString> list) {
+ if (list.size() == 0) {
+ return EMPTY;
+ } else if (list.size() == 1) {
+ return list.get(0);
+ }
+
+ int size = 0;
+ for (ByteString str : list) {
+ size += str.size();
+ }
+ byte[] bytes = new byte[size];
+ int pos = 0;
+ for (ByteString str : list) {
+ System.arraycopy(str.bytes, 0, bytes, pos, str.size());
+ pos += str.size();
+ }
+ return new ByteString(bytes);
+ }
+
// =================================================================
// ByteString -> byte[]
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
index 698992f0..ed26722d 100644
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -38,6 +38,7 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
import java.io.IOException;
import java.nio.CharBuffer;
import java.math.BigInteger;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -115,7 +116,7 @@ public final class TextFormat {
}
printUnknownFields(message.getUnknownFields(), generator);
}
-
+
public static void printField(final FieldDescriptor field,
final Object value,
final Appendable output)
@@ -133,10 +134,10 @@ public final class TextFormat {
} catch (IOException e) {
throw new RuntimeException(
"Writing to a StringBuilder threw an IOException (should never " +
- "happen).", e);
+ "happen).", e);
}
}
-
+
private static void printField(final FieldDescriptor field,
final Object value,
final TextGenerator generator)
@@ -428,7 +429,7 @@ public final class TextFormat {
"[a-zA-Z_][0-9a-zA-Z_+-]*+|" + // an identifier
"[.]?[0-9+-][0-9a-zA-Z_.+-]*+|" + // a number
"\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" + // a double-quoted string
- "\'([^\"\n\\\\]|\\\\.)*+(\'|\\\\?$)", // a single-quoted string
+ "\'([^\'\n\\\\]|\\\\.)*+(\'|\\\\?$)", // a single-quoted string
Pattern.MULTILINE);
private static final Pattern DOUBLE_INFINITY = Pattern.compile(
@@ -695,6 +696,15 @@ public final class TextFormat {
* {@link ParseException}.
*/
public ByteString consumeByteString() throws ParseException {
+ List<ByteString> list = new ArrayList<ByteString>();
+ consumeByteString(list);
+ while (currentToken.startsWith("'") || currentToken.startsWith("\"")) {
+ consumeByteString(list);
+ }
+ return ByteString.copyFrom(list);
+ }
+
+ public void consumeByteString(List<ByteString> list) throws ParseException {
final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
: '\0';
if (quote != '\"' && quote != '\'') {
@@ -711,7 +721,7 @@ public final class TextFormat {
currentToken.substring(1, currentToken.length() - 1);
final ByteString result = unescapeBytes(escaped);
nextToken();
- return result;
+ list.add(result);
} catch (InvalidEscapeSequenceException e) {
throw parseException(e.getMessage());
}
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java
index 3ea7b2cf..60bd800e 100644
--- a/java/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -196,12 +196,12 @@ public class TextFormatTest extends TestCase {
final FieldDescriptor optionalField =
TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
final Object value = NestedMessage.newBuilder().setBb(42).build();
-
+
assertEquals(
"optional_nested_message {\n bb: 42\n}\n",
TextFormat.printFieldToString(optionalField, value));
}
-
+
/**
* Helper to construct a ByteString from a String containing only 8-bit
* characters. The characters are converted directly to bytes, *not*
@@ -649,4 +649,10 @@ public class TextFormatTest extends TestCase {
TextFormat.merge("optional_string: \"" + longText + "\"", builder);
assertEquals(longText, builder.getOptionalString());
}
+
+ public void testParseAdjacentStringLiterals() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
+ assertEquals("foocorgegrault", builder.getOptionalString());
+ }
}