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 
31 package com.google.protobuf;
32 
33 import 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  */
47 class 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    */
BoundedByteString(byte[] bytes, int offset, int length)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
byteAt(int index)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
size()106   public int size() {
107     return bytesLength;
108   }
109 
110   @Override
getOffsetIntoBytes()111   protected int getOffsetIntoBytes() {
112     return bytesOffset;
113   }
114 
115   // =================================================================
116   // ByteString -> byte[]
117 
118   @Override
copyToInternal(byte[] target, int sourceOffset, int targetOffset, int numberToCopy)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
iterator()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 
BoundedByteIterator()138     private BoundedByteIterator() {
139       position = getOffsetIntoBytes();
140       limit = position + size();
141     }
142 
hasNext()143     public boolean hasNext() {
144       return (position < limit);
145     }
146 
next()147     public Byte next() {
148       // Boxing calls Byte.valueOf(byte), which does not instantiate.
149       return nextByte();
150     }
151 
nextByte()152     public byte nextByte() {
153       if (position >= limit) {
154         throw new NoSuchElementException();
155       }
156       return bytes[position++];
157     }
158 
remove()159     public void remove() {
160       throw new UnsupportedOperationException();
161     }
162   }
163 }
164