1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31package com.google.protobuf; 32 33import java.util.NoSuchElementException; 34 35/** 36 * This class is used to represent the substring of a {@link ByteString} over a 37 * single byte array. In terms of the public API of {@link ByteString}, you end 38 * up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link 39 * ByteString#substring(int, int)}. 40 * 41 * <p>This class contains most of the overhead involved in creating a substring 42 * from a {@link LiteralByteString}. The overhead involves some range-checking 43 * and two extra fields. 44 * 45 * @author carlanton@google.com (Carl Haverl) 46 */ 47class BoundedByteString extends LiteralByteString { 48 49 private final int bytesOffset; 50 private final int bytesLength; 51 52 /** 53 * Creates a {@code BoundedByteString} backed by the sub-range of given array, 54 * without copying. 55 * 56 * @param bytes array to wrap 57 * @param offset index to first byte to use in bytes 58 * @param length number of bytes to use from bytes 59 * @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0}, 60 * or if {@code offset + length > 61 * bytes.length}. 62 */ 63 BoundedByteString(byte[] bytes, int offset, int length) { 64 super(bytes); 65 if (offset < 0) { 66 throw new IllegalArgumentException("Offset too small: " + offset); 67 } 68 if (length < 0) { 69 throw new IllegalArgumentException("Length too small: " + offset); 70 } 71 if ((long) offset + length > bytes.length) { 72 throw new IllegalArgumentException( 73 "Offset+Length too large: " + offset + "+" + length); 74 } 75 76 this.bytesOffset = offset; 77 this.bytesLength = length; 78 } 79 80 /** 81 * Gets the byte at the given index. 82 * Throws {@link ArrayIndexOutOfBoundsException} 83 * for backwards-compatibility reasons although it would more properly be 84 * {@link IndexOutOfBoundsException}. 85 * 86 * @param index index of byte 87 * @return the value 88 * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size 89 */ 90 @Override 91 public byte byteAt(int index) { 92 // We must check the index ourselves as we cannot rely on Java array index 93 // checking for substrings. 94 if (index < 0) { 95 throw new ArrayIndexOutOfBoundsException("Index too small: " + index); 96 } 97 if (index >= size()) { 98 throw new ArrayIndexOutOfBoundsException( 99 "Index too large: " + index + ", " + size()); 100 } 101 102 return bytes[bytesOffset + index]; 103 } 104 105 @Override 106 public int size() { 107 return bytesLength; 108 } 109 110 @Override 111 protected int getOffsetIntoBytes() { 112 return bytesOffset; 113 } 114 115 // ================================================================= 116 // ByteString -> byte[] 117 118 @Override 119 protected void copyToInternal(byte[] target, int sourceOffset, 120 int targetOffset, int numberToCopy) { 121 System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target, 122 targetOffset, numberToCopy); 123 } 124 125 // ================================================================= 126 // ByteIterator 127 128 @Override 129 public ByteIterator iterator() { 130 return new BoundedByteIterator(); 131 } 132 133 private class BoundedByteIterator implements ByteIterator { 134 135 private int position; 136 private final int limit; 137 138 private BoundedByteIterator() { 139 position = getOffsetIntoBytes(); 140 limit = position + size(); 141 } 142 143 public boolean hasNext() { 144 return (position < limit); 145 } 146 147 public Byte next() { 148 // Boxing calls Byte.valueOf(byte), which does not instantiate. 149 return nextByte(); 150 } 151 152 public byte nextByte() { 153 if (position >= limit) { 154 throw new NoSuchElementException(); 155 } 156 return bytes[position++]; 157 } 158 159 public void remove() { 160 throw new UnsupportedOperationException(); 161 } 162 } 163} 164