| Index: third_party/protobuf/java/core/src/main/java/com/google/protobuf/ByteString.java
|
| diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/ByteString.java b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/ByteString.java
|
| similarity index 72%
|
| rename from third_party/protobuf/java/src/main/java/com/google/protobuf/ByteString.java
|
| rename to third_party/protobuf/java/core/src/main/java/com/google/protobuf/ByteString.java
|
| index 68f20d5199b61ecd085a16d153e4a2b21fa1a9ca..62c945085f6195c5e8ae5878859c1ed769ca8c9b 100644
|
| --- a/third_party/protobuf/java/src/main/java/com/google/protobuf/ByteString.java
|
| +++ b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/ByteString.java
|
| @@ -30,9 +30,12 @@
|
|
|
| package com.google.protobuf;
|
|
|
| +import java.io.ByteArrayInputStream;
|
| import java.io.ByteArrayOutputStream;
|
| import java.io.IOException;
|
| import java.io.InputStream;
|
| +import java.io.InvalidObjectException;
|
| +import java.io.ObjectInputStream;
|
| import java.io.OutputStream;
|
| import java.io.Serializable;
|
| import java.io.UnsupportedEncodingException;
|
| @@ -40,7 +43,9 @@ import java.nio.ByteBuffer;
|
| import java.nio.charset.Charset;
|
| import java.nio.charset.UnsupportedCharsetException;
|
| import java.util.ArrayList;
|
| +import java.util.Arrays;
|
| import java.util.Collection;
|
| +import java.util.Collections;
|
| import java.util.Iterator;
|
| import java.util.List;
|
| import java.util.NoSuchElementException;
|
| @@ -81,7 +86,55 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| /**
|
| * Empty {@code ByteString}.
|
| */
|
| - public static final ByteString EMPTY = new LiteralByteString(new byte[0]);
|
| + public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY);
|
| +
|
| + /**
|
| + * An interface to efficiently copy {@code byte[]}.
|
| + *
|
| + * <p>One of the noticable costs of copying a byte[] into a new array using
|
| + * {@code System.arraycopy} is nullification of a new buffer before the copy. It has been shown
|
| + * the Hotspot VM is capable to intrisicfy {@code Arrays.copyOfRange} operation to avoid this
|
| + * expensive nullification and provide substantial performance gain. Unfortunately this does not
|
| + * hold on Android runtimes and could make the copy slightly slower due to additional code in
|
| + * the {@code Arrays.copyOfRange}. Thus we provide two different implementation for array copier
|
| + * for Hotspot and Android runtimes.
|
| + */
|
| + private interface ByteArrayCopier {
|
| + /**
|
| + * Copies the specified range of the specified array into a new array
|
| + */
|
| + byte[] copyFrom(byte[] bytes, int offset, int size);
|
| + }
|
| +
|
| + /** Implementation of {@code ByteArrayCopier} which uses {@link System#arraycopy}. */
|
| + private static final class SystemByteArrayCopier implements ByteArrayCopier {
|
| + @Override
|
| + public byte[] copyFrom(byte[] bytes, int offset, int size) {
|
| + byte[] copy = new byte[size];
|
| + System.arraycopy(bytes, offset, copy, 0, size);
|
| + return copy;
|
| + }
|
| + }
|
| +
|
| + /** Implementation of {@code ByteArrayCopier} which uses {@link Arrays#copyOfRange}. */
|
| + private static final class ArraysByteArrayCopier implements ByteArrayCopier {
|
| + @Override
|
| + public byte[] copyFrom(byte[] bytes, int offset, int size) {
|
| + return Arrays.copyOfRange(bytes, offset, offset + size);
|
| + }
|
| + }
|
| +
|
| + private static final ByteArrayCopier byteArrayCopier;
|
| + static {
|
| + boolean isAndroid = true;
|
| + try {
|
| + Class.forName("android.content.Context");
|
| + } catch (ClassNotFoundException e) {
|
| + isAndroid = false;
|
| + }
|
| +
|
| + byteArrayCopier = isAndroid ? new SystemByteArrayCopier() : new ArraysByteArrayCopier();
|
| + }
|
|
|
| /**
|
| * Cached hash value. Intentionally accessed via a data race, which
|
| @@ -101,7 +154,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| *
|
| * @param index index of byte
|
| * @return the value
|
| - * @throws ArrayIndexOutOfBoundsException {@code index < 0 or index >= size}
|
| + * @throws IndexOutOfBoundsException {@code index < 0 or index >= size}
|
| */
|
| public abstract byte byteAt(int index);
|
|
|
| @@ -133,7 +186,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| public byte nextByte() {
|
| try {
|
| return byteAt(position++);
|
| - } catch (ArrayIndexOutOfBoundsException e) {
|
| + } catch (IndexOutOfBoundsException e) {
|
| throw new NoSuchElementException(e.getMessage());
|
| }
|
| }
|
| @@ -244,9 +297,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| * @return new {@code ByteString}
|
| */
|
| public static ByteString copyFrom(byte[] bytes, int offset, int size) {
|
| - byte[] copy = new byte[size];
|
| - System.arraycopy(bytes, offset, copy, 0, size);
|
| - return new LiteralByteString(copy);
|
| + return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size));
|
| }
|
|
|
| /**
|
| @@ -258,6 +309,24 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| public static ByteString copyFrom(byte[] bytes) {
|
| return copyFrom(bytes, 0, bytes.length);
|
| }
|
| +
|
| + /**
|
| + * Wraps the given bytes into a {@code ByteString}. Intended for internal only
|
| + * usage to force a classload of ByteString before LiteralByteString.
|
| + */
|
| + static ByteString wrap(byte[] bytes) {
|
| + // TODO(dweis): Return EMPTY when bytes are empty to reduce allocations?
|
| + return new LiteralByteString(bytes);
|
| + }
|
| +
|
| + /**
|
| + * Wraps the given bytes into a {@code ByteString}. Intended for internal only
|
| + * usage to force a classload of ByteString before BoundedByteString and
|
| + * LiteralByteString.
|
| + */
|
| + static ByteString wrap(byte[] bytes, int offset, int length) {
|
| + return new BoundedByteString(bytes, offset, length);
|
| + }
|
|
|
| /**
|
| * Copies the next {@code size} bytes from a {@code java.nio.ByteBuffer} into
|
| @@ -565,12 +634,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| }
|
|
|
| /**
|
| - * Writes the complete contents of this byte string to
|
| - * the specified output stream argument.
|
| - *
|
| - * <p>It is assumed that the {@link OutputStream} will not modify the contents passed it
|
| - * it. It may be possible for a malicious {@link OutputStream} to corrupt
|
| - * the data underlying the {@link ByteString}.
|
| + * Writes a copy of the contents of this byte string to the specified output stream argument.
|
| *
|
| * @param out the output stream to which to write the data.
|
| * @throws IOException if an I/O error occurs.
|
| @@ -584,8 +648,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| * @param sourceOffset offset within these bytes
|
| * @param numberToWrite number of bytes to write
|
| * @throws IOException if an I/O error occurs.
|
| - * @throws IndexOutOfBoundsException if an offset or size is negative or too
|
| - * large
|
| + * @throws IndexOutOfBoundsException if an offset or size is negative or too large
|
| */
|
| final void writeTo(OutputStream out, int sourceOffset, int numberToWrite)
|
| throws IOException {
|
| @@ -603,6 +666,20 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| throws IOException;
|
|
|
| /**
|
| + * Writes this {@link ByteString} to the provided {@link ByteOutput}. Calling
|
| + * this method may result in multiple operations on the target {@link ByteOutput}.
|
| + *
|
| + * <p>This method may expose internal backing buffers of the {@link ByteString} to the {@link
|
| + * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious
|
| + * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution!
|
| + *
|
| + * @param byteOutput the output target to receive the bytes
|
| + * @throws IOException if an I/O error occurs
|
| + * @see UnsafeByteOperations#unsafeWriteTo(ByteString, ByteOutput)
|
| + */
|
| + abstract void writeTo(ByteOutput byteOutput) throws IOException;
|
| +
|
| + /**
|
| * Constructs a read-only {@code java.nio.ByteBuffer} whose content
|
| * is equal to the contents of this byte string.
|
| * The result uses the same backing array as the byte string, if possible.
|
| @@ -1108,7 +1185,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| *
|
| * @param index the index position to be tested
|
| * @param size the length of the array
|
| - * @throws ArrayIndexOutOfBoundsException if the index does not fall within the array.
|
| + * @throws IndexOutOfBoundsException if the index does not fall within the array.
|
| */
|
| static void checkIndex(int index, int size) {
|
| if ((index | (size - (index + 1))) < 0) {
|
| @@ -1126,7 +1203,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| * @param endIndex the end index of the range (exclusive)
|
| * @param size the size of the array.
|
| * @return the length of the range.
|
| - * @throws ArrayIndexOutOfBoundsException some or all of the range falls outside of the array.
|
| + * @throws IndexOutOfBoundsException some or all of the range falls outside of the array.
|
| */
|
| static int checkRange(int startIndex, int endIndex, int size) {
|
| final int length = endIndex - startIndex;
|
| @@ -1149,4 +1226,319 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
|
| return String.format("<ByteString@%s size=%d>",
|
| Integer.toHexString(System.identityHashCode(this)), size());
|
| }
|
| +
|
| + /**
|
| + * This class implements a {@link com.google.protobuf.ByteString} backed by a
|
| + * single array of bytes, contiguous in memory. It supports substring by
|
| + * pointing to only a sub-range of the underlying byte array, meaning that a
|
| + * substring will reference the full byte-array of the string it's made from,
|
| + * exactly as with {@link String}.
|
| + *
|
| + * @author carlanton@google.com (Carl Haverl)
|
| + */
|
| + // Keep this class private to avoid deadlocks in classloading across threads as ByteString's
|
| + // static initializer loads LiteralByteString and another thread loads LiteralByteString.
|
| + private static class LiteralByteString extends ByteString.LeafByteString {
|
| + private static final long serialVersionUID = 1L;
|
| +
|
| + protected final byte[] bytes;
|
| +
|
| + /**
|
| + * Creates a {@code LiteralByteString} backed by the given array, without
|
| + * copying.
|
| + *
|
| + * @param bytes array to wrap
|
| + */
|
| + LiteralByteString(byte[] bytes) {
|
| + this.bytes = bytes;
|
| + }
|
| +
|
| + @Override
|
| + public byte byteAt(int index) {
|
| + // Unlike most methods in this class, this one is a direct implementation
|
| + // ignoring the potential offset because we need to do range-checking in the
|
| + // substring case anyway.
|
| + return bytes[index];
|
| + }
|
| +
|
| + @Override
|
| + public int size() {
|
| + return bytes.length;
|
| + }
|
| +
|
| + // =================================================================
|
| + // ByteString -> substring
|
| +
|
| + @Override
|
| + public final ByteString substring(int beginIndex, int endIndex) {
|
| + final int length = checkRange(beginIndex, endIndex, size());
|
| +
|
| + if (length == 0) {
|
| + return ByteString.EMPTY;
|
| + }
|
| +
|
| + return new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex, length);
|
| + }
|
| +
|
| + // =================================================================
|
| + // ByteString -> byte[]
|
| +
|
| + @Override
|
| + protected void copyToInternal(
|
| + byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
|
| + // Optimized form, not for subclasses, since we don't call
|
| + // getOffsetIntoBytes() or check the 'numberToCopy' parameter.
|
| + // TODO(nathanmittler): Is not calling getOffsetIntoBytes really saving that much?
|
| + System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
|
| + }
|
| +
|
| + @Override
|
| + public final void copyTo(ByteBuffer target) {
|
| + target.put(bytes, getOffsetIntoBytes(), size()); // Copies bytes
|
| + }
|
| +
|
| + @Override
|
| + public final ByteBuffer asReadOnlyByteBuffer() {
|
| + return ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size()).asReadOnlyBuffer();
|
| + }
|
| +
|
| + @Override
|
| + public final List<ByteBuffer> asReadOnlyByteBufferList() {
|
| + return Collections.singletonList(asReadOnlyByteBuffer());
|
| + }
|
| +
|
| + @Override
|
| + public final void writeTo(OutputStream outputStream) throws IOException {
|
| + outputStream.write(toByteArray());
|
| + }
|
| +
|
| + @Override
|
| + final void writeToInternal(OutputStream outputStream, int sourceOffset, int numberToWrite)
|
| + throws IOException {
|
| + outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset, numberToWrite);
|
| + }
|
| +
|
| + @Override
|
| + final void writeTo(ByteOutput output) throws IOException {
|
| + output.writeLazy(bytes, getOffsetIntoBytes(), size());
|
| + }
|
| +
|
| + @Override
|
| + protected final String toStringInternal(Charset charset) {
|
| + return new String(bytes, getOffsetIntoBytes(), size(), charset);
|
| + }
|
| +
|
| + // =================================================================
|
| + // UTF-8 decoding
|
| +
|
| + @Override
|
| + public final boolean isValidUtf8() {
|
| + int offset = getOffsetIntoBytes();
|
| + return Utf8.isValidUtf8(bytes, offset, offset + size());
|
| + }
|
| +
|
| + @Override
|
| + protected final int partialIsValidUtf8(int state, int offset, int length) {
|
| + int index = getOffsetIntoBytes() + offset;
|
| + return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
|
| + }
|
| +
|
| + // =================================================================
|
| + // equals() and hashCode()
|
| +
|
| + @Override
|
| + public final boolean equals(Object other) {
|
| + if (other == this) {
|
| + return true;
|
| + }
|
| + if (!(other instanceof ByteString)) {
|
| + return false;
|
| + }
|
| +
|
| + if (size() != ((ByteString) other).size()) {
|
| + return false;
|
| + }
|
| + if (size() == 0) {
|
| + return true;
|
| + }
|
| +
|
| + if (other instanceof LiteralByteString) {
|
| + LiteralByteString otherAsLiteral = (LiteralByteString) other;
|
| + // If we know the hash codes and they are not equal, we know the byte
|
| + // strings are not equal.
|
| + int thisHash = peekCachedHashCode();
|
| + int thatHash = otherAsLiteral.peekCachedHashCode();
|
| + if (thisHash != 0 && thatHash != 0 && thisHash != thatHash) {
|
| + return false;
|
| + }
|
| +
|
| + return equalsRange((LiteralByteString) other, 0, size());
|
| + } else {
|
| + // RopeByteString and NioByteString.
|
| + return other.equals(this);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Check equality of the substring of given length of this object starting at
|
| + * zero with another {@code LiteralByteString} substring starting at offset.
|
| + *
|
| + * @param other what to compare a substring in
|
| + * @param offset offset into other
|
| + * @param length number of bytes to compare
|
| + * @return true for equality of substrings, else false.
|
| + */
|
| + @Override
|
| + final boolean equalsRange(ByteString other, int offset, int length) {
|
| + if (length > other.size()) {
|
| + throw new IllegalArgumentException("Length too large: " + length + size());
|
| + }
|
| + if (offset + length > other.size()) {
|
| + throw new IllegalArgumentException(
|
| + "Ran off end of other: " + offset + ", " + length + ", " + other.size());
|
| + }
|
| +
|
| + if (other instanceof LiteralByteString) {
|
| + LiteralByteString lbsOther = (LiteralByteString) other;
|
| + byte[] thisBytes = bytes;
|
| + byte[] otherBytes = lbsOther.bytes;
|
| + int thisLimit = getOffsetIntoBytes() + length;
|
| + for (
|
| + int thisIndex = getOffsetIntoBytes(),
|
| + otherIndex = lbsOther.getOffsetIntoBytes() + offset;
|
| + (thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
|
| + if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + return other.substring(offset, offset + length).equals(substring(0, length));
|
| + }
|
| +
|
| + @Override
|
| + protected final int partialHash(int h, int offset, int length) {
|
| + return Internal.partialHash(h, bytes, getOffsetIntoBytes() + offset, length);
|
| + }
|
| +
|
| + // =================================================================
|
| + // Input stream
|
| +
|
| + @Override
|
| + public final InputStream newInput() {
|
| + return new ByteArrayInputStream(bytes, getOffsetIntoBytes(), size()); // No copy
|
| + }
|
| +
|
| + @Override
|
| + public final CodedInputStream newCodedInput() {
|
| + // We trust CodedInputStream not to modify the bytes, or to give anyone
|
| + // else access to them.
|
| + return CodedInputStream.newInstance(
|
| + bytes, getOffsetIntoBytes(), size(), true /* bufferIsImmutable */);
|
| + }
|
| +
|
| + // =================================================================
|
| + // Internal methods
|
| +
|
| + /**
|
| + * Offset into {@code bytes[]} to use, non-zero for substrings.
|
| + *
|
| + * @return always 0 for this class
|
| + */
|
| + protected int getOffsetIntoBytes() {
|
| + return 0;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * This class is used to represent the substring of a {@link ByteString} over a
|
| + * single byte array. In terms of the public API of {@link ByteString}, you end
|
| + * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link
|
| + * ByteString#substring(int, int)}.
|
| + *
|
| + * <p>This class contains most of the overhead involved in creating a substring
|
| + * from a {@link LiteralByteString}. The overhead involves some range-checking
|
| + * and two extra fields.
|
| + *
|
| + * @author carlanton@google.com (Carl Haverl)
|
| + */
|
| + // Keep this class private to avoid deadlocks in classloading across threads as ByteString's
|
| + // static initializer loads LiteralByteString and another thread loads BoundedByteString.
|
| + private static final class BoundedByteString extends LiteralByteString {
|
| +
|
| + private final int bytesOffset;
|
| + private final int bytesLength;
|
| +
|
| + /**
|
| + * Creates a {@code BoundedByteString} backed by the sub-range of given array,
|
| + * without copying.
|
| + *
|
| + * @param bytes array to wrap
|
| + * @param offset index to first byte to use in bytes
|
| + * @param length number of bytes to use from bytes
|
| + * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0},
|
| + * or if {@code offset + length >
|
| + * bytes.length}.
|
| + */
|
| + BoundedByteString(byte[] bytes, int offset, int length) {
|
| + super(bytes);
|
| + checkRange(offset, offset + length, bytes.length);
|
| +
|
| + this.bytesOffset = offset;
|
| + this.bytesLength = length;
|
| + }
|
| +
|
| + /**
|
| + * Gets the byte at the given index.
|
| + * Throws {@link ArrayIndexOutOfBoundsException}
|
| + * for backwards-compatibility reasons although it would more properly be
|
| + * {@link IndexOutOfBoundsException}.
|
| + *
|
| + * @param index index of byte
|
| + * @return the value
|
| + * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
|
| + */
|
| + @Override
|
| + public byte byteAt(int index) {
|
| + // We must check the index ourselves as we cannot rely on Java array index
|
| + // checking for substrings.
|
| + checkIndex(index, size());
|
| + return bytes[bytesOffset + index];
|
| + }
|
| +
|
| + @Override
|
| + public int size() {
|
| + return bytesLength;
|
| + }
|
| +
|
| + @Override
|
| + protected int getOffsetIntoBytes() {
|
| + return bytesOffset;
|
| + }
|
| +
|
| + // =================================================================
|
| + // ByteString -> byte[]
|
| +
|
| + @Override
|
| + protected void copyToInternal(byte[] target, int sourceOffset, int targetOffset,
|
| + int numberToCopy) {
|
| + System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target,
|
| + targetOffset, numberToCopy);
|
| + }
|
| +
|
| + // =================================================================
|
| + // Serializable
|
| +
|
| + private static final long serialVersionUID = 1L;
|
| +
|
| + Object writeReplace() {
|
| + return ByteString.wrap(toByteArray());
|
| + }
|
| +
|
| + private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException {
|
| + throw new InvalidObjectException(
|
| + "BoundedByteStream instances are not to be serialized directly");
|
| + }
|
| + }
|
| }
|
|
|