1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Protocol Buffers - Google's data interchange format 2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Copyright 2008 Google Inc. All rights reserved. 3afb4b72037e3f13db208590fc782c4bc8e27f862Jeff Davidson// https://developers.google.com/protocol-buffers/ 4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// 5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Redistribution and use in source and binary forms, with or without 6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// modification, are permitted provided that the following conditions are 7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// met: 8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// 9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// * Redistributions of source code must retain the above copyright 10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// notice, this list of conditions and the following disclaimer. 11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// * Redistributions in binary form must reproduce the above 12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// copyright notice, this list of conditions and the following disclaimer 13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// in the documentation and/or other materials provided with the 14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// distribution. 15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// * Neither the name of Google Inc. nor the names of its 16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// contributors may be used to endorse or promote products derived from 17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// this software without specific prior written permission. 18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// 19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 31fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillepackage com.google.protobuf; 32fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.io.ByteArrayInputStream; 34fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.io.ByteArrayOutputStream; 35a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.io.IOException; 36a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.io.InputStream; 37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.io.InvalidObjectException; 38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.io.ObjectInputStream; 39a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.io.OutputStream; 40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.io.Serializable; 41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.io.UnsupportedEncodingException; 42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport java.nio.ByteBuffer; 43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.nio.charset.Charset; 44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.nio.charset.UnsupportedCharsetException; 45a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.util.ArrayList; 46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.Arrays; 47a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.util.Collection; 48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerimport java.util.Collections; 49a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.util.Iterator; 50d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savilleimport java.util.List; 51a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonimport java.util.NoSuchElementException; 52fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 53fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville/** 54a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Immutable sequence of bytes. Substring is supported by sharing the reference 55a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * to the immutable underlying bytes, as with {@link String}. Concatenation is 56a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * likewise supported without copying (long strings) by building a tree of 57a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * pieces in {@link RopeByteString}. 58a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p> 59a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Like {@link String}, the contents of a {@link ByteString} can never be 60a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * observed to change, not even in the presence of a data race or incorrect 61a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * API usage in the client code. 62fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 63fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @author crazybob@google.com Bob Lee 64fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @author kenton@google.com Kenton Varda 65a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @author carlanton@google.com Carl Haverl 66a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @author martinrb@google.com Martin Buchholz 67fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerpublic abstract class ByteString implements Iterable<Byte>, Serializable { 69fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 70a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 71a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * When two strings to be concatenated have a combined length shorter than 72a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * this, we just copy their bytes on {@link #concat(ByteString)}. 73a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * The trade-off is copy size versus the overhead of creating tree nodes 74a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * in {@link RopeByteString}. 75a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 76a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson static final int CONCATENATE_BY_COPY_SIZE = 128; 77a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 78a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 79a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * When copying an InputStream into a ByteString with .readFrom(), 80a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * the chunks in the underlying rope start at 256 bytes, but double 81a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * each iteration up to 8192 bytes. 82a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 83a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson static final int MIN_READ_FROM_CHUNK_SIZE = 0x100; // 256b 84a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson static final int MAX_READ_FROM_CHUNK_SIZE = 0x2000; // 8k 85fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 86fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 87a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Empty {@code ByteString}. 88a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY); 90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * An interface to efficiently copy {@code byte[]}. 93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>One of the noticable costs of copying a byte[] into a new array using 95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@code System.arraycopy} is nullification of a new buffer before the copy. It has been shown 96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * the Hotspot VM is capable to intrisicfy {@code Arrays.copyOfRange} operation to avoid this 97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * expensive nullification and provide substantial performance gain. Unfortunately this does not 98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * hold on Android runtimes and could make the copy slightly slower due to additional code in 99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * the {@code Arrays.copyOfRange}. Thus we provide two different implementation for array copier 100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * for Hotspot and Android runtimes. 101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private interface ByteArrayCopier { 103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Copies the specified range of the specified array into a new array 105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer byte[] copyFrom(byte[] bytes, int offset, int size); 107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** Implementation of {@code ByteArrayCopier} which uses {@link System#arraycopy}. */ 110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static final class SystemByteArrayCopier implements ByteArrayCopier { 111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public byte[] copyFrom(byte[] bytes, int offset, int size) { 113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer byte[] copy = new byte[size]; 114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer System.arraycopy(bytes, offset, copy, 0, size); 115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return copy; 116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** Implementation of {@code ByteArrayCopier} which uses {@link Arrays#copyOfRange}. */ 120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static final class ArraysByteArrayCopier implements ByteArrayCopier { 121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public byte[] copyFrom(byte[] bytes, int offset, int size) { 123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return Arrays.copyOfRange(bytes, offset, offset + size); 124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static final ByteArrayCopier byteArrayCopier; 128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer static { 129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer boolean isAndroid = true; 130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer try { 131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer Class.forName("android.content.Context"); 132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } catch (ClassNotFoundException e) { 133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer isAndroid = false; 134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer byteArrayCopier = isAndroid ? new SystemByteArrayCopier() : new ArraysByteArrayCopier(); 137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Cached hash value. Intentionally accessed via a data race, which 141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * is safe because of the Java Memory Model's "no out-of-thin-air values" 142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * guarantees for ints. A value of 0 implies that the hash has not been set. 143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private int hash = 0; 145a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 146a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // This constructor is here to prevent subclassing outside of this package, 147a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteString() {} 148a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 149a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 150a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Gets the byte at the given index. This method should be used only for 151a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * random access to individual bytes. To access bytes sequentially, use the 152a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@link ByteIterator} returned by {@link #iterator()}, and call {@link 153a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * #substring(int, int)} first if necessary. 154fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 155a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param index index of byte 156a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return the value 157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @throws IndexOutOfBoundsException {@code index < 0 or index >= size} 158fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 159a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract byte byteAt(int index); 160a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 161a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 162a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Return a {@link ByteString.ByteIterator} over the bytes in the ByteString. 163a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * To avoid auto-boxing, you may get the iterator manually and call 164a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@link ByteIterator#nextByte()}. 165a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 166a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return the iterator 167a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final ByteIterator iterator() { 170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new ByteIterator() { 171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private int position = 0; 172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private final int limit = size(); 173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public boolean hasNext() { 176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return position < limit; 177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public Byte next() { 181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Boxing calls Byte.valueOf(byte), which does not instantiate. 182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return nextByte(); 183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public byte nextByte() { 187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer try { 188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return byteAt(position++); 189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } catch (IndexOutOfBoundsException e) { 190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new NoSuchElementException(e.getMessage()); 191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public void remove() { 196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new UnsupportedOperationException(); 197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer }; 199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 200a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 201a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 202a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * This interface extends {@code Iterator<Byte>}, so that we can return an 203a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * unboxed {@code byte}. 204a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 205a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public interface ByteIterator extends Iterator<Byte> { 206a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 207a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * An alternative to {@link Iterator#next()} that returns an 208a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * unboxed primitive {@code byte}. 209a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 210a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return the next {@code byte} in the iteration 211a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws NoSuchElementException if the iteration has no more elements 212a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 213a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byte nextByte(); 214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 216fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 217fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Gets the number of bytes. 218a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 219a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return size in bytes 220fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 221a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract int size(); 222fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 223fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 224fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Returns {@code true} if the size is {@code 0}, {@code false} otherwise. 225a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 226a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return true if this is zero bytes long 227fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final boolean isEmpty() { 229a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return size() == 0; 230fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 231fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 232fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ================================================================= 233a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // ByteString -> substring 234a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 235a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 236a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Return the substring from {@code beginIndex}, inclusive, to the end of the 237a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * string. 238a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 239a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param beginIndex start at this index 240a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return substring sharing underlying data 241a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IndexOutOfBoundsException if {@code beginIndex < 0} or 242a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@code beginIndex > size()}. 243a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final ByteString substring(int beginIndex) { 245a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return substring(beginIndex, size()); 246a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 247a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 248a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 249a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Return the substring from {@code beginIndex}, inclusive, to {@code 250a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * endIndex}, exclusive. 251a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 252a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param beginIndex start at this index 253a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param endIndex the last character is the one before this index 254a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return substring sharing underlying data 255a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IndexOutOfBoundsException if {@code beginIndex < 0}, 256a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@code endIndex > size()}, or {@code beginIndex > endIndex}. 257a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 258a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract ByteString substring(int beginIndex, int endIndex); 259fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 260fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 261a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Tests if this bytestring starts with the specified prefix. 262a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Similar to {@link String#startsWith(String)} 263a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 264a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param prefix the prefix. 265a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return <code>true</code> if the byte sequence represented by the 266a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * argument is a prefix of the byte sequence represented by 267a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * this string; <code>false</code> otherwise. 268fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final boolean startsWith(ByteString prefix) { 270a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return size() >= prefix.size() && 271a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson substring(0, prefix.size()).equals(prefix); 272a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 273a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 274a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 275a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Tests if this bytestring ends with the specified suffix. 276a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Similar to {@link String#endsWith(String)} 277a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 278a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param suffix the suffix. 279a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return <code>true</code> if the byte sequence represented by the 280a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * argument is a suffix of the byte sequence represented by 281a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * this string; <code>false</code> otherwise. 282a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final boolean endsWith(ByteString suffix) { 284a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return size() >= suffix.size() && 285a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson substring(size() - suffix.size()).equals(suffix); 286a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 287a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 288a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // ================================================================= 289a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // byte[] -> ByteString 290fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 291fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 292fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Copies the given bytes into a {@code ByteString}. 293a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 294a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param bytes source array 295a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param offset offset in source array 296a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param size number of bytes to copy 297a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new {@code ByteString} 298fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 299a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString copyFrom(byte[] bytes, int offset, int size) { 300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size)); 301fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 302fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 303fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 304fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Copies the given bytes into a {@code ByteString}. 305a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 306a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param bytes to copy 307a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new {@code ByteString} 308fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 309a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString copyFrom(byte[] bytes) { 310fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return copyFrom(bytes, 0, bytes.length); 311fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Wraps the given bytes into a {@code ByteString}. Intended for internal only 315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * usage to force a classload of ByteString before LiteralByteString. 316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer static ByteString wrap(byte[] bytes) { 318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // TODO(dweis): Return EMPTY when bytes are empty to reduce allocations? 319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new LiteralByteString(bytes); 320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Wraps the given bytes into a {@code ByteString}. Intended for internal only 324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * usage to force a classload of ByteString before BoundedByteString and 325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * LiteralByteString. 326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer static ByteString wrap(byte[] bytes, int offset, int length) { 328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new BoundedByteString(bytes, offset, length); 329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 330fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 331fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 332a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Copies the next {@code size} bytes from a {@code java.nio.ByteBuffer} into 333d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * a {@code ByteString}. 334a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 335a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param bytes source buffer 336a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param size number of bytes to copy 337a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new {@code ByteString} 338d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville */ 339a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString copyFrom(ByteBuffer bytes, int size) { 340a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byte[] copy = new byte[size]; 341d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville bytes.get(copy); 342a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new LiteralByteString(copy); 343d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 344d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville 345d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville /** 346d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * Copies the remaining bytes from a {@code java.nio.ByteBuffer} into 347d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * a {@code ByteString}. 348a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 349a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param bytes sourceBuffer 350a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new {@code ByteString} 351d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville */ 352a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString copyFrom(ByteBuffer bytes) { 353d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville return copyFrom(bytes, bytes.remaining()); 354d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 355d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville 356d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville /** 357fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Encodes {@code text} into a sequence of bytes using the named charset 358fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * and returns the result as a {@code ByteString}. 359a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 360a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param text source string 361a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param charsetName encoding to use 362a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new {@code ByteString} 363a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws UnsupportedEncodingException if the encoding isn't found 364fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 365a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString copyFrom(String text, String charsetName) 366fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville throws UnsupportedEncodingException { 367a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new LiteralByteString(text.getBytes(charsetName)); 368fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 369fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 370fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Encodes {@code text} into a sequence of bytes using the named charset 372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * and returns the result as a {@code ByteString}. 373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param text source string 375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param charset encode using this charset 376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return new {@code ByteString} 377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public static ByteString copyFrom(String text, Charset charset) { 379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new LiteralByteString(text.getBytes(charset)); 380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 383fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Encodes {@code text} into a sequence of UTF-8 bytes and returns the 384fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * result as a {@code ByteString}. 385a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 386a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param text source string 387a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new {@code ByteString} 388fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 389a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString copyFromUtf8(String text) { 390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new LiteralByteString(text.getBytes(Internal.UTF_8)); 391fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 392fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 393a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // ================================================================= 394a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // InputStream -> ByteString 395a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 396a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 397a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Completely reads the given stream's bytes into a 398a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@code ByteString}, blocking if necessary until all bytes are 399a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * read through to the end of the stream. 400a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 401a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <b>Performance notes:</b> The returned {@code ByteString} is an 402a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * immutable tree of byte arrays ("chunks") of the stream data. The 403a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * first chunk is small, with subsequent chunks each being double 404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * the size, up to 8K. 405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>Each byte read from the input stream will be copied twice to ensure 407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * that the resulting ByteString is truly immutable. 408a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 409a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param streamToDrain The source stream, which is read completely 410a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * but not closed. 411a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return A new {@code ByteString} which is made up of chunks of 412a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * various sizes, depending on the behavior of the underlying 413a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * stream. 414a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IOException IOException is thrown if there is a problem 415a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * reading the underlying stream. 416a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 417a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString readFrom(InputStream streamToDrain) 418a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throws IOException { 419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return readFrom(streamToDrain, MIN_READ_FROM_CHUNK_SIZE, MAX_READ_FROM_CHUNK_SIZE); 420a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 421a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 422a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 423a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Completely reads the given stream's bytes into a 424a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@code ByteString}, blocking if necessary until all bytes are 425a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * read through to the end of the stream. 426a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 427a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <b>Performance notes:</b> The returned {@code ByteString} is an 428a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * immutable tree of byte arrays ("chunks") of the stream data. The 429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * chunkSize parameter sets the size of these byte arrays. 430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>Each byte read from the input stream will be copied twice to ensure 432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * that the resulting ByteString is truly immutable. 433a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 434a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param streamToDrain The source stream, which is read completely 435a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * but not closed. 436a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param chunkSize The size of the chunks in which to read the 437a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * stream. 438a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return A new {@code ByteString} which is made up of chunks of 439a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * the given size. 440a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IOException IOException is thrown if there is a problem 441a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * reading the underlying stream. 442a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 443a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString readFrom(InputStream streamToDrain, int chunkSize) 444a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throws IOException { 445a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return readFrom(streamToDrain, chunkSize, chunkSize); 446a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 447a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 448a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Helper method that takes the chunk size range as a parameter. 449a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString readFrom(InputStream streamToDrain, int minChunkSize, 450a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int maxChunkSize) throws IOException { 451a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Collection<ByteString> results = new ArrayList<ByteString>(); 452a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 453a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // copy the inbound bytes into a list of chunks; the chunk size 454a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // grows exponentially to support both short and long streams. 455a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int chunkSize = minChunkSize; 456a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson while (true) { 457a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteString chunk = readChunk(streamToDrain, chunkSize); 458a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (chunk == null) { 459a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break; 460a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 461a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson results.add(chunk); 462a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson chunkSize = Math.min(chunkSize * 2, maxChunkSize); 463a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 464a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 465a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ByteString.copyFrom(results); 466a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 467a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 468a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 469a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Blocks until a chunk of the given size can be made from the 470a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * stream, or EOF is reached. Calls read() repeatedly in case the 471a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * given stream implementation doesn't completely fill the given 472a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * buffer in one read() call. 473a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 474a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return A chunk of the desired size, or else a chunk as large as 475a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * was available when end of stream was reached. Returns null if the 476a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * given stream had no more data in it. 477a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 478a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private static ByteString readChunk(InputStream in, final int chunkSize) 479a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throws IOException { 480a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final byte[] buf = new byte[chunkSize]; 481a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int bytesRead = 0; 482a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson while (bytesRead < chunkSize) { 483a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson final int count = in.read(buf, bytesRead, chunkSize - bytesRead); 484a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (count == -1) { 485a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson break; 486a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 487a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bytesRead += count; 488a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 489a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 490a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bytesRead == 0) { 491a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return null; 492a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Always make a copy since InputStream could steal a reference to buf. 495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return ByteString.copyFrom(buf, 0, bytesRead); 496a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 497a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 498a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // ================================================================= 499a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Multiple ByteStrings -> One ByteString 500a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 501a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 502a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Concatenate the given {@code ByteString} to this one. Short concatenations, 503a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * of total size smaller than {@link ByteString#CONCATENATE_BY_COPY_SIZE}, are 504a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * produced by copying the underlying bytes (as per Rope.java, <a 505a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf"> 506a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * BAP95 </a>. In general, the concatenate involves no copying. 507a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 508a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param other string to concatenate 509a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return a new {@code ByteString} instance 510a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final ByteString concat(ByteString other) { 512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (Integer.MAX_VALUE - size() < other.size()) { 513a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw new IllegalArgumentException("ByteString would be too long: " + 514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer size() + "+" + other.size()); 515a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 516a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 517a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return RopeByteString.concatenate(this, other); 518a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 519a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 520d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville /** 521a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Concatenates all byte strings in the iterable and returns the result. 522a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * This is designed to run in O(list size), not O(total bytes). 523d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * 524d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * <p>The returned {@code ByteString} is not necessarily a unique object. 525d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * If the list is empty, the returned object is the singleton empty 526d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * {@code ByteString}. If the list has only one element, that 527d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville * {@code ByteString} will be returned without copying. 528a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 529a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param byteStrings strings to be concatenated 530a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new {@code ByteString} 531d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville */ 532a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static ByteString copyFrom(Iterable<ByteString> byteStrings) { 533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Determine the size; 534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final int size; 535a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (!(byteStrings instanceof Collection)) { 536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int tempSize = 0; 537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer for (Iterator<ByteString> iter = byteStrings.iterator(); iter.hasNext(); 538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer iter.next(), ++tempSize) { 539a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer size = tempSize; 541a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer size = ((Collection<ByteString>) byteStrings).size(); 543d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (size == 0) { 546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return EMPTY; 547d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 548b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 549b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return balancedConcat(byteStrings.iterator(), size); 550a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 551a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 552a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Internal function used by copyFrom(Iterable<ByteString>). 553a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Create a balanced concatenation of the next "length" elements from the 554a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // iterable. 555b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static ByteString balancedConcat(Iterator<ByteString> iterator, int length) { 556a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson assert length >= 1; 557a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteString result; 558a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (length == 1) { 559a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result = iterator.next(); 560a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 561a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int halfLength = length >>> 1; 562a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteString left = balancedConcat(iterator, halfLength); 563a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteString right = balancedConcat(iterator, length - halfLength); 564a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson result = left.concat(right); 565d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 566a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 567d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville } 568d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville 569fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ================================================================= 570fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ByteString -> byte[] 571fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 572fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 573fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Copies bytes into a buffer at the given offset. 574fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 575fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @param target buffer to copy into 576fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @param offset in the target buffer 577a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IndexOutOfBoundsException if the offset is negative or too large 578fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 579a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public void copyTo(byte[] target, int offset) { 580a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson copyTo(target, 0, offset, size()); 581fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 582fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 583fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 584fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Copies bytes into a buffer. 585fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 586a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param target buffer to copy into 587fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @param sourceOffset offset within these bytes 588fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * @param targetOffset offset within the target buffer 589a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param numberToCopy number of bytes to copy 590a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IndexOutOfBoundsException if an offset or size is negative or too 591a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * large 592fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 593b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final void copyTo(byte[] target, int sourceOffset, int targetOffset, 594a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int numberToCopy) { 595b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer checkRange(sourceOffset, sourceOffset + numberToCopy, size()); 596b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer checkRange(targetOffset, targetOffset + numberToCopy, target.length); 597a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (numberToCopy > 0) { 598a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson copyToInternal(target, sourceOffset, targetOffset, numberToCopy); 599a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 600fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 601fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 602fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 603a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Internal (package private) implementation of 604b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@link #copyTo(byte[],int,int,int)}. 605b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * It assumes that all error checking has already been performed and that 606b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@code numberToCopy > 0}. 607a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 608a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson protected abstract void copyToInternal(byte[] target, int sourceOffset, 609a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int targetOffset, int numberToCopy); 610a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 611a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 612a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Copies bytes into a ByteBuffer. 613a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 614a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param target ByteBuffer to copy into. 615a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only 616a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws java.nio.BufferOverflowException if the {@code target}'s 617a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * remaining() space is not large enough to hold the data. 618a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 619a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract void copyTo(ByteBuffer target); 620a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 621a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 622fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Copies bytes to a {@code byte[]}. 623a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 624a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return copied bytes 625fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 626b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final byte[] toByteArray() { 627b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final int size = size(); 628a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (size == 0) { 629a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return Internal.EMPTY_BYTE_ARRAY; 630a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 631a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byte[] result = new byte[size]; 632a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson copyToInternal(result, 0, 0, size); 633a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 634fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 635fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 636fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 637b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Writes a copy of the contents of this byte string to the specified output stream argument. 638a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 639a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param out the output stream to which to write the data. 640a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IOException if an I/O error occurs. 641fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 642a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract void writeTo(OutputStream out) throws IOException; 643b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 644a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 645a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Writes a specified part of this byte string to an output stream. 646a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 647a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param out the output stream to which to write the data. 648a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param sourceOffset offset within these bytes 649a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param numberToWrite number of bytes to write 650a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IOException if an I/O error occurs. 651b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @throws IndexOutOfBoundsException if an offset or size is negative or too large 652a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 653b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final void writeTo(OutputStream out, int sourceOffset, int numberToWrite) 654a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throws IOException { 655b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer checkRange(sourceOffset, sourceOffset + numberToWrite, size()); 656a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (numberToWrite > 0) { 657a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson writeToInternal(out, sourceOffset, numberToWrite); 658a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 659fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 660fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 661fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 662a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Internal version of {@link #writeTo(OutputStream,int,int)} that assumes 663a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * all error checking has already been done. 664a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 665b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer abstract void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite) 666b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throws IOException; 667b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 668b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 669b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Writes this {@link ByteString} to the provided {@link ByteOutput}. Calling 670b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * this method may result in multiple operations on the target {@link ByteOutput}. 671b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 672b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>This method may expose internal backing buffers of the {@link ByteString} to the {@link 673b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious 674b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution! 675b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 676b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param byteOutput the output target to receive the bytes 677b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @throws IOException if an I/O error occurs 678b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @see UnsafeByteOperations#unsafeWriteTo(ByteString, ByteOutput) 679b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 680b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer abstract void writeTo(ByteOutput byteOutput) throws IOException; 681a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 682a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 683a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Constructs a read-only {@code java.nio.ByteBuffer} whose content 684a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * is equal to the contents of this byte string. 685a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * The result uses the same backing array as the byte string, if possible. 686a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 687a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return wrapped bytes 688a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 689a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract ByteBuffer asReadOnlyByteBuffer(); 690a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 691a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 692a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Constructs a list of read-only {@code java.nio.ByteBuffer} objects 693a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * such that the concatenation of their contents is equal to the contents 694a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * of this byte string. The result uses the same backing arrays as the 695a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * byte string. 696a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p> 697a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * By returning a list, implementations of this method may be able to avoid 698a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * copying even when there are multiple backing arrays. 699b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 700a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return a list of wrapped bytes 701a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 702a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract List<ByteBuffer> asReadOnlyByteBufferList(); 703a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 704a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 705fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Constructs a new {@code String} by decoding the bytes using the 706fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * specified charset. 707a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 708a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param charsetName encode using this charset 709a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new string 710a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws UnsupportedEncodingException if charset isn't recognized 711fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 712b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final String toString(String charsetName) 713b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throws UnsupportedEncodingException { 714b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer try { 715b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return toString(Charset.forName(charsetName)); 716b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } catch (UnsupportedCharsetException e) { 717b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer UnsupportedEncodingException exception = new UnsupportedEncodingException(charsetName); 718b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer exception.initCause(e); 719b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw exception; 720b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 721b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 722b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 723b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 724b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Constructs a new {@code String} by decoding the bytes using the 725b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * specified charset. Returns the same empty String if empty. 726b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 727b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param charset encode using this charset 728b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return new string 729b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 730b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final String toString(Charset charset) { 731b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return size() == 0 ? "" : toStringInternal(charset); 732b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 733b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 734b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 735b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Constructs a new {@code String} by decoding the bytes using the 736b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * specified charset. 737b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 738b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param charset encode using this charset 739b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return new string 740b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 741b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected abstract String toStringInternal(Charset charset); 742a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 743a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // ================================================================= 744a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // UTF-8 decoding 745fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 746fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 747fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Constructs a new {@code String} by decoding the bytes as UTF-8. 748a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 749a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return new string using UTF-8 encoding 750fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 751b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final String toStringUtf8() { 752b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return toString(Internal.UTF_8); 753fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 754fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 755a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 756a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Tells whether this {@code ByteString} represents a well-formed UTF-8 757a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * byte sequence, such that the original bytes can be converted to a 758a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * String object and then round tripped back to bytes without loss. 759a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 760a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p>More precisely, returns {@code true} whenever: <pre> {@code 761a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Arrays.equals(byteString.toByteArray(), 762a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8")) 763a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * }</pre> 764a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 765a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p>This method returns {@code false} for "overlong" byte sequences, 766a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * as well as for 3-byte sequences that would map to a surrogate 767a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * character, in accordance with the restricted definition of UTF-8 768a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * introduced in Unicode 3.1. Note that the UTF-8 decoder included in 769a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Oracle's JDK has been modified to also reject "overlong" byte 770a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * sequences, but (as of 2011) still accepts 3-byte surrogate 771a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * character byte sequences. 772a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 773b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>See the Unicode Standard,<br> 774b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Table 3-6. <em>UTF-8 Bit Distribution</em>,<br> 775a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>. 776a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 777a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return whether the bytes in this {@code ByteString} are a 778a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * well-formed UTF-8 byte sequence 779a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 780a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract boolean isValidUtf8(); 781a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 782a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 783a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Tells whether the given byte sequence is a well-formed, malformed, or 784a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * incomplete UTF-8 byte sequence. This method accepts and returns a partial 785a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * state result, allowing the bytes for a complete UTF-8 byte sequence to be 786a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * composed from multiple {@code ByteString} segments. 787a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 788a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param state either {@code 0} (if this is the initial decoding operation) 789a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * or the value returned from a call to a partial decoding method for the 790a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * previous bytes 791a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param offset offset of the first byte to check 792a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param length number of bytes to check 793a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 794a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return {@code -1} if the partial byte sequence is definitely malformed, 795a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@code 0} if it is well-formed (no additional input needed), or, if the 796a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * byte sequence is "incomplete", i.e. apparently terminated in the middle of 797a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * a character, an opaque integer "state" value containing enough information 798a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * to decode the character when passed to a subsequent invocation of a 799a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * partial decoding method. 800a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 801a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson protected abstract int partialIsValidUtf8(int state, int offset, int length); 802a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 803fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ================================================================= 804fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // equals() and hashCode() 805fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 806fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville @Override 807a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract boolean equals(Object o); 808fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 809a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 810b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Base class for leaf {@link ByteString}s (i.e. non-ropes). 811b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 812b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer abstract static class LeafByteString extends ByteString { 813b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 814b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected final int getTreeDepth() { 815b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return 0; 816b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 817b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 818b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 819b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected final boolean isBalanced() { 820b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return true; 821b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 822b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 823b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 824b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Check equality of the substring of given length of this object starting at 825b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * zero with another {@code ByteString} substring starting at offset. 826b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 827b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param other what to compare a substring in 828b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param offset offset into other 829b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param length number of bytes to compare 830b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return true for equality of substrings, else false. 831b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 832b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer abstract boolean equalsRange(ByteString other, int offset, int length); 833b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 834b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 835b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 836b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Compute the hashCode using the traditional algorithm from {@link 837b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * ByteString}. 838a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 839b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return hashCode value 840a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 841fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville @Override 842b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final int hashCode() { 843b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int h = hash; 844b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 845b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (h == 0) { 846b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int size = size(); 847b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer h = partialHash(size, 0, size); 848b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (h == 0) { 849b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer h = 1; 850b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 851b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer hash = h; 852b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 853b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return h; 854b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 855fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 856fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ================================================================= 857fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Input stream 858fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 859fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 860fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Creates an {@code InputStream} which can be used to read the bytes. 861a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p> 862a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * The {@link InputStream} returned by this method is guaranteed to be 863a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * completely non-blocking. The method {@link InputStream#available()} 864a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * returns the number of bytes remaining in the stream. The methods 865b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@link InputStream#read(byte[])}, {@link InputStream#read(byte[],int,int)} 866a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * and {@link InputStream#skip(long)} will read/skip as many bytes as are 867b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * available. The method {@link InputStream#markSupported()} returns 868b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@code true}. 869a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p> 870a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * The methods in the returned {@link InputStream} might <b>not</b> be 871a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * thread safe. 872a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 873a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return an input stream that returns the bytes of this byte string. 874fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 875a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract InputStream newInput(); 876fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 877fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 878fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Creates a {@link CodedInputStream} which can be used to read the bytes. 879a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Using this is often more efficient than creating a {@link CodedInputStream} 880a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * that wraps the result of {@link #newInput()}. 881a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 882a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return stream based on wrapped data 883fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 884a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public abstract CodedInputStream newCodedInput(); 885fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 886fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // ================================================================= 887fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // Output stream 888fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 889fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 890a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Creates a new {@link Output} with the given initial capacity. Call {@link 891a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Output#toByteString()} to create the {@code ByteString} instance. 892a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p> 893a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * A {@link ByteString.Output} offers the same functionality as a 894a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString} 895a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * rather than a {@code byte} array. 896a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 897a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param initialCapacity estimate of number of bytes to be written 898a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return {@code OutputStream} for building a {@code ByteString} 899fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 900a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static Output newOutput(int initialCapacity) { 901a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new Output(initialCapacity); 902fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 903fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 904fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 905a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Creates a new {@link Output}. Call {@link Output#toByteString()} to create 906a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * the {@code ByteString} instance. 907a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * <p> 908a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * A {@link ByteString.Output} offers the same functionality as a 909a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * {@link ByteArrayOutputStream}, except that it returns a {@link ByteString} 910a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * rather than a {@code byte array}. 911a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 912a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return {@code OutputStream} for building a {@code ByteString} 913fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 914fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public static Output newOutput() { 915a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new Output(CONCATENATE_BY_COPY_SIZE); 916fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 917fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 918fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 919fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to 920fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * create the {@code ByteString} instance. 921fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 922a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public static final class Output extends OutputStream { 923a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Implementation note. 924a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // The public methods of this class must be synchronized. ByteStrings 925a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // are guaranteed to be immutable. Without some sort of locking, it could 926a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // be possible for one thread to call toByteSring(), while another thread 927a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // is still modifying the underlying byte array. 928a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 929a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; 930a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // argument passed by user, indicating initial capacity. 931a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private final int initialCapacity; 932a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // ByteStrings to be concatenated to create the result 933a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private final ArrayList<ByteString> flushedBuffers; 934a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Total number of bytes in the ByteStrings of flushedBuffers 935a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private int flushedBuffersTotalBytes; 936a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Current buffer to which we are writing 937a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private byte[] buffer; 938a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Location in buffer[] to which we write the next byte. 939a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private int bufferPos; 940fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 941fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 942a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Creates a new ByteString output stream with the specified 943a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * initial capacity. 944a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 945a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param initialCapacity the initial capacity of the output stream. 946fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 947a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Output(int initialCapacity) { 948a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (initialCapacity < 0) { 949a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson throw new IllegalArgumentException("Buffer size < 0"); 950a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 951a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson this.initialCapacity = initialCapacity; 952a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson this.flushedBuffers = new ArrayList<ByteString>(); 953a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson this.buffer = new byte[initialCapacity]; 954a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 955a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 956a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson @Override 957a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public synchronized void write(int b) { 958a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferPos == buffer.length) { 959a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushFullBuffer(1); 960a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 961a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer[bufferPos++] = (byte)b; 962a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 963a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 964a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson @Override 965a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public synchronized void write(byte[] b, int offset, int length) { 966a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (length <= buffer.length - bufferPos) { 967a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // The bytes can fit into the current buffer. 968a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson System.arraycopy(b, offset, buffer, bufferPos, length); 969a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos += length; 970a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 971a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Use up the current buffer 972a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int copySize = buffer.length - bufferPos; 973a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson System.arraycopy(b, offset, buffer, bufferPos, copySize); 974a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson offset += copySize; 975a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson length -= copySize; 976a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Flush the buffer, and get a new buffer at least big enough to cover 977a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // what we still need to output 978a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushFullBuffer(length); 979a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson System.arraycopy(b, offset, buffer, 0 /* count */, length); 980a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = length; 981a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 982fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 983fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 984fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 985a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Creates a byte string. Its size is the current size of this output 986a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * stream and its output has been copied to it. 987a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 988a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return the current contents of this output stream, as a byte string. 989fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 990a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public synchronized ByteString toByteString() { 991a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushLastBuffer(); 992a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return ByteString.copyFrom(flushedBuffers); 993a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 994b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 995a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 996a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Implement java.util.Arrays.copyOf() for jdk 1.5. 997a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 998a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private byte[] copyArray(byte[] buffer, int length) { 999a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byte[] result = new byte[length]; 1000a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson System.arraycopy(buffer, 0, result, 0, Math.min(buffer.length, length)); 1001a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return result; 1002a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1003a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1004a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1005a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Writes the complete contents of this byte array output stream to 1006a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * the specified output stream argument. 1007a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1008a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param out the output stream to which to write the data. 1009a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @throws IOException if an I/O error occurs. 1010a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1011a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public void writeTo(OutputStream out) throws IOException { 1012a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson ByteString[] cachedFlushBuffers; 1013a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byte[] cachedBuffer; 1014a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int cachedBufferPos; 1015a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson synchronized (this) { 1016a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Copy the information we need into local variables so as to hold 1017a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // the lock for as short a time as possible. 1018a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson cachedFlushBuffers = 1019a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffers.toArray(new ByteString[flushedBuffers.size()]); 1020a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson cachedBuffer = buffer; 1021a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson cachedBufferPos = bufferPos; 1022a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1023a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson for (ByteString byteString : cachedFlushBuffers) { 1024a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byteString.writeTo(out); 1025a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1026a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1027a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson out.write(copyArray(cachedBuffer, cachedBufferPos)); 1028a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1029a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1030a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1031a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Returns the current size of the output stream. 1032a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1033a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return the current size of the output stream 1034a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1035a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public synchronized int size() { 1036a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return flushedBuffersTotalBytes + bufferPos; 1037a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1038a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1039a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1040a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Resets this stream, so that all currently accumulated output in the 1041a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * output stream is discarded. The output stream can be used again, 1042a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * reusing the already allocated buffer space. 1043a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1044a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public synchronized void reset() { 1045a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffers.clear(); 1046a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffersTotalBytes = 0; 1047a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = 0; 1048a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1049a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1050a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson @Override 1051a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public String toString() { 1052a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return String.format("<ByteString.Output@%s size=%d>", 1053a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Integer.toHexString(System.identityHashCode(this)), size()); 1054a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1055a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1056a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1057a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Internal function used by writers. The current buffer is full, and the 1058a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * writer needs a new buffer whose size is at least the specified minimum 1059a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * size. 1060a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1061a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private void flushFullBuffer(int minSize) { 1062a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffers.add(new LiteralByteString(buffer)); 1063a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffersTotalBytes += buffer.length; 1064a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // We want to increase our total capacity by 50%, but as a minimum, 1065a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // the new buffer should also at least be >= minSize and 1066a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // >= initial Capacity. 1067a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int newSize = Math.max(initialCapacity, 1068a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Math.max(minSize, flushedBuffersTotalBytes >>> 1)); 1069a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer = new byte[newSize]; 1070a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = 0; 1071a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1072a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1073a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1074a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Internal function used by {@link #toByteString()}. The current buffer may 1075a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * or may not be full, but it needs to be flushed. 1076a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1077a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private void flushLastBuffer() { 1078a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferPos < buffer.length) { 1079a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (bufferPos > 0) { 1080a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson byte[] bufferCopy = copyArray(buffer, bufferPos); 1081a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffers.add(new LiteralByteString(bufferCopy)); 1082a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1083a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // We reuse this buffer for further writes. 1084a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 1085a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Buffer is completely full. Huzzah. 1086a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffers.add(new LiteralByteString(buffer)); 1087a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // 99% of the time, we're not going to use this OutputStream again. 1088a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // We set buffer to an empty byte stream so that we're handling this 1089a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // case without wasting space. In the rare case that more writes 1090a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // *do* occur, this empty buffer will be flushed and an appropriately 1091a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // sized new buffer will be created. 1092a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson buffer = EMPTY_BYTE_ARRAY; 1093a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1094a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson flushedBuffersTotalBytes += bufferPos; 1095a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson bufferPos = 0; 1096fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1097fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1098fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1099fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** 1100a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Constructs a new {@code ByteString} builder, which allows you to 1101a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * efficiently construct a {@code ByteString} by writing to a {@link 1102a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * CodedOutputStream}. Using this is much more efficient than calling {@code 1103a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * newOutput()} and wrapping that in a {@code CodedOutputStream}. 1104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 1105fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * <p>This is package-private because it's a somewhat confusing interface. 1106fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * Users can call {@link Message#toByteString()} instead of calling this 1107fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * directly. 1108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville * 1109a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param size The target byte size of the {@code ByteString}. You must write 1110a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * exactly this many bytes before building the result. 1111a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return the builder 1112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville */ 1113a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson static CodedBuilder newCodedBuilder(int size) { 1114fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return new CodedBuilder(size); 1115fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1116fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1117fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville /** See {@link ByteString#newCodedBuilder(int)}. */ 1118fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville static final class CodedBuilder { 1119fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private final CodedOutputStream output; 1120fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville private final byte[] buffer; 1121fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1122a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson private CodedBuilder(int size) { 1123fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville buffer = new byte[size]; 1124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville output = CodedOutputStream.newInstance(buffer); 1125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1127fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public ByteString build() { 1128fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville output.checkNoSpaceLeft(); 1129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1130fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // We can be confident that the CodedOutputStream will not modify the 1131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // underlying bytes anymore because it already wrote all of them. So, 1132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville // no need to make a copy. 1133a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return new LiteralByteString(buffer); 1134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville 1136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public CodedOutputStream getCodedOutput() { 1137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville return output; 1138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville } 1140a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1141a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // ================================================================= 1142a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Methods {@link RopeByteString} needs on instances, which aren't part of the 1143a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // public API. 1144a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1145a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1146a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Return the depth of the tree representing this {@code ByteString}, if any, 1147a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * whose root is this node. If this is a leaf node, return 0. 1148a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1149a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return tree depth or zero 1150a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1151a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson protected abstract int getTreeDepth(); 1152a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1153a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1154a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Return {@code true} if this ByteString is literal (a leaf node) or a 1155a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * flat-enough tree in the sense of {@link RopeByteString}. 1156a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1157a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return true if the tree is flat enough 1158a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1159a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson protected abstract boolean isBalanced(); 1160a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1161a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1162a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Return the cached hash code if available. 1163a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1164a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return value of cached hash code or 0 if not computed yet 1165a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected final int peekCachedHashCode() { 1167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return hash; 1168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1169a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1170a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson /** 1171a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * Compute the hash across the value bytes starting with the given hash, and 1172a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * return the result. This is used to compute the hash across strings 1173a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * represented as a set of pieces by allowing the hash computation to be 1174a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * continued from piece to piece. 1175a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * 1176a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param h starting hash value 1177a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param offset offset into this value to start looking at data values 1178a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @param length number of data values to include in the hash computation 1179a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson * @return ending hash value 1180a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson */ 1181a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson protected abstract int partialHash(int h, int offset, int length); 1182a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 1183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Checks that the given index falls within the specified array size. 1185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param index the index position to be tested 1187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param size the length of the array 1188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @throws IndexOutOfBoundsException if the index does not fall within the array. 1189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer static void checkIndex(int index, int size) { 1191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if ((index | (size - (index + 1))) < 0) { 1192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (index < 0) { 1193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new ArrayIndexOutOfBoundsException("Index < 0: " + index); 1194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new ArrayIndexOutOfBoundsException("Index > length: " + index + ", " + size); 1196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Checks that the given range falls within the bounds of an array 1201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param startIndex the start index of the range (inclusive) 1203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param endIndex the end index of the range (exclusive) 1204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param size the size of the array. 1205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return the length of the range. 1206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @throws IndexOutOfBoundsException some or all of the range falls outside of the array. 1207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer static int checkRange(int startIndex, int endIndex, int size) { 1209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final int length = endIndex - startIndex; 1210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if ((startIndex | endIndex | length | (size - endIndex)) < 0) { 1211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (startIndex < 0) { 1212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new IndexOutOfBoundsException("Beginning index: " + startIndex + " < 0"); 1213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (endIndex < startIndex) { 1215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new IndexOutOfBoundsException( 1216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer "Beginning index larger than ending index: " + startIndex + ", " + endIndex); 1217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // endIndex >= size 1219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new IndexOutOfBoundsException("End index: " + endIndex + " >= " + size); 1220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return length; 1222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1224a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson @Override 1225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final String toString() { 1226a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson return String.format("<ByteString@%s size=%d>", 1227a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson Integer.toHexString(System.identityHashCode(this)), size()); 1228a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 1229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * This class implements a {@link com.google.protobuf.ByteString} backed by a 1232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * single array of bytes, contiguous in memory. It supports substring by 1233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * pointing to only a sub-range of the underlying byte array, meaning that a 1234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * substring will reference the full byte-array of the string it's made from, 1235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * exactly as with {@link String}. 1236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @author carlanton@google.com (Carl Haverl) 1238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Keep this class private to avoid deadlocks in classloading across threads as ByteString's 1240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // static initializer loads LiteralByteString and another thread loads LiteralByteString. 1241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static class LiteralByteString extends ByteString.LeafByteString { 1242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static final long serialVersionUID = 1L; 1243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected final byte[] bytes; 1245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Creates a {@code LiteralByteString} backed by the given array, without 1248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * copying. 1249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param bytes array to wrap 1251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer LiteralByteString(byte[] bytes) { 1253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer this.bytes = bytes; 1254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public byte byteAt(int index) { 1258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Unlike most methods in this class, this one is a direct implementation 1259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ignoring the potential offset because we need to do range-checking in the 1260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // substring case anyway. 1261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return bytes[index]; 1262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public int size() { 1266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return bytes.length; 1267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ByteString -> substring 1271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final ByteString substring(int beginIndex, int endIndex) { 1274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final int length = checkRange(beginIndex, endIndex, size()); 1275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (length == 0) { 1277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return ByteString.EMPTY; 1278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex, length); 1281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ByteString -> byte[] 1285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected void copyToInternal( 1288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer byte[] target, int sourceOffset, int targetOffset, int numberToCopy) { 1289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Optimized form, not for subclasses, since we don't call 1290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // getOffsetIntoBytes() or check the 'numberToCopy' parameter. 1291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // TODO(nathanmittler): Is not calling getOffsetIntoBytes really saving that much? 1292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy); 1293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final void copyTo(ByteBuffer target) { 1297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer target.put(bytes, getOffsetIntoBytes(), size()); // Copies bytes 1298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final ByteBuffer asReadOnlyByteBuffer() { 1302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size()).asReadOnlyBuffer(); 1303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final List<ByteBuffer> asReadOnlyByteBufferList() { 1307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return Collections.singletonList(asReadOnlyByteBuffer()); 1308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final void writeTo(OutputStream outputStream) throws IOException { 1312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer outputStream.write(toByteArray()); 1313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final void writeToInternal(OutputStream outputStream, int sourceOffset, int numberToWrite) 1317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throws IOException { 1318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset, numberToWrite); 1319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final void writeTo(ByteOutput output) throws IOException { 1323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer output.writeLazy(bytes, getOffsetIntoBytes(), size()); 1324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected final String toStringInternal(Charset charset) { 1328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new String(bytes, getOffsetIntoBytes(), size(), charset); 1329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // UTF-8 decoding 1333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final boolean isValidUtf8() { 1336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int offset = getOffsetIntoBytes(); 1337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return Utf8.isValidUtf8(bytes, offset, offset + size()); 1338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected final int partialIsValidUtf8(int state, int offset, int length) { 1342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int index = getOffsetIntoBytes() + offset; 1343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return Utf8.partialIsValidUtf8(state, bytes, index, index + length); 1344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // equals() and hashCode() 1348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final boolean equals(Object other) { 1351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (other == this) { 1352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return true; 1353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (!(other instanceof ByteString)) { 1355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return false; 1356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (size() != ((ByteString) other).size()) { 1359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return false; 1360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (size() == 0) { 1362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return true; 1363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (other instanceof LiteralByteString) { 1366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer LiteralByteString otherAsLiteral = (LiteralByteString) other; 1367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // If we know the hash codes and they are not equal, we know the byte 1368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // strings are not equal. 1369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int thisHash = peekCachedHashCode(); 1370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int thatHash = otherAsLiteral.peekCachedHashCode(); 1371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (thisHash != 0 && thatHash != 0 && thisHash != thatHash) { 1372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return false; 1373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return equalsRange((LiteralByteString) other, 0, size()); 1376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } else { 1377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // RopeByteString and NioByteString. 1378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return other.equals(this); 1379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Check equality of the substring of given length of this object starting at 1384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * zero with another {@code LiteralByteString} substring starting at offset. 1385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param other what to compare a substring in 1387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param offset offset into other 1388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param length number of bytes to compare 1389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return true for equality of substrings, else false. 1390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer final boolean equalsRange(ByteString other, int offset, int length) { 1393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (length > other.size()) { 1394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new IllegalArgumentException("Length too large: " + length + size()); 1395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (offset + length > other.size()) { 1397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new IllegalArgumentException( 1398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer "Ran off end of other: " + offset + ", " + length + ", " + other.size()); 1399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (other instanceof LiteralByteString) { 1402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer LiteralByteString lbsOther = (LiteralByteString) other; 1403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer byte[] thisBytes = bytes; 1404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer byte[] otherBytes = lbsOther.bytes; 1405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int thisLimit = getOffsetIntoBytes() + length; 1406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer for ( 1407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int thisIndex = getOffsetIntoBytes(), 1408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer otherIndex = lbsOther.getOffsetIntoBytes() + offset; 1409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer (thisIndex < thisLimit); ++thisIndex, ++otherIndex) { 1410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer if (thisBytes[thisIndex] != otherBytes[otherIndex]) { 1411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return false; 1412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return true; 1415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return other.substring(offset, offset + length).equals(substring(0, length)); 1418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected final int partialHash(int h, int offset, int length) { 1422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return Internal.partialHash(h, bytes, getOffsetIntoBytes() + offset, length); 1423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Input stream 1427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final InputStream newInput() { 1430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return new ByteArrayInputStream(bytes, getOffsetIntoBytes(), size()); // No copy 1431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public final CodedInputStream newCodedInput() { 1435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // We trust CodedInputStream not to modify the bytes, or to give anyone 1436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // else access to them. 1437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return CodedInputStream.newInstance( 1438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer bytes, getOffsetIntoBytes(), size(), true /* bufferIsImmutable */); 1439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Internal methods 1443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Offset into {@code bytes[]} to use, non-zero for substrings. 1446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return always 0 for this class 1448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected int getOffsetIntoBytes() { 1450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return 0; 1451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * This class is used to represent the substring of a {@link ByteString} over a 1456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * single byte array. In terms of the public API of {@link ByteString}, you end 1457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link 1458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * ByteString#substring(int, int)}. 1459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * <p>This class contains most of the overhead involved in creating a substring 1461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * from a {@link LiteralByteString}. The overhead involves some range-checking 1462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * and two extra fields. 1463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @author carlanton@google.com (Carl Haverl) 1465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Keep this class private to avoid deadlocks in classloading across threads as ByteString's 1467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // static initializer loads LiteralByteString and another thread loads BoundedByteString. 1468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static final class BoundedByteString extends LiteralByteString { 1469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private final int bytesOffset; 1471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private final int bytesLength; 1472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Creates a {@code BoundedByteString} backed by the sub-range of given array, 1475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * without copying. 1476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param bytes array to wrap 1478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param offset index to first byte to use in bytes 1479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param length number of bytes to use from bytes 1480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0}, 1481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * or if {@code offset + length > 1482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * bytes.length}. 1483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer BoundedByteString(byte[] bytes, int offset, int length) { 1485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer super(bytes); 1486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer checkRange(offset, offset + length, bytes.length); 1487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer this.bytesOffset = offset; 1489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer this.bytesLength = length; 1490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer /** 1493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Gets the byte at the given index. 1494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * Throws {@link ArrayIndexOutOfBoundsException} 1495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * for backwards-compatibility reasons although it would more properly be 1496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * {@link IndexOutOfBoundsException}. 1497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * 1498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @param index index of byte 1499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @return the value 1500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size 1501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer */ 1502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public byte byteAt(int index) { 1504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // We must check the index ourselves as we cannot rely on Java array index 1505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // checking for substrings. 1506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer checkIndex(index, size()); 1507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return bytes[bytesOffset + index]; 1508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer public int size() { 1512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return bytesLength; 1513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected int getOffsetIntoBytes() { 1517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return bytesOffset; 1518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ByteString -> byte[] 1522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer @Override 1524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer protected void copyToInternal(byte[] target, int sourceOffset, int targetOffset, 1525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer int numberToCopy) { 1526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target, 1527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer targetOffset, numberToCopy); 1528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // ================================================================= 1531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer // Serializable 1532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private static final long serialVersionUID = 1L; 1534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer Object writeReplace() { 1536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer return ByteString.wrap(toByteArray()); 1537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer 1539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer private void readObject(@SuppressWarnings("unused") ObjectInputStream in) throws IOException { 1540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer throw new InvalidObjectException( 1541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer "BoundedByteStream instances are not to be serialized directly"); 1542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer } 1544fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville} 1545