1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27
28 package org.apache.http.util;
29
30 import java.io.Serializable;
31
32 import org.apache.http.annotation.NotThreadSafe;
33
34 /**
35 * A resizable byte array.
36 *
37 * @since 4.0
38 */
39 @NotThreadSafe
40 public final class ByteArrayBuffer implements Serializable {
41
42 private static final long serialVersionUID = 4359112959524048036L;
43
44 private byte[] buffer;
45 private int len;
46
47 /**
48 * Creates an instance of {@link ByteArrayBuffer} with the given initial
49 * capacity.
50 *
51 * @param capacity the capacity
52 */
53 public ByteArrayBuffer(int capacity) {
54 super();
55 if (capacity < 0) {
56 throw new IllegalArgumentException("Buffer capacity may not be negative");
57 }
58 this.buffer = new byte[capacity];
59 }
60
61 private void expand(int newlen) {
62 byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
63 System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
64 this.buffer = newbuffer;
65 }
66
67 /**
68 * Appends <code>len</code> bytes to this buffer from the given source
69 * array starting at index <code>off</code>. The capacity of the buffer
70 * is increased, if necessary, to accommodate all <code>len</code> bytes.
71 *
72 * @param b the bytes to be appended.
73 * @param off the index of the first byte to append.
74 * @param len the number of bytes to append.
75 * @throws IndexOutOfBoundsException if <code>off</code> if out of
76 * range, <code>len</code> is negative, or
77 * <code>off</code> + <code>len</code> is out of range.
78 */
79 public void append(final byte[] b, int off, int len) {
80 if (b == null) {
81 return;
82 }
83 if ((off < 0) || (off > b.length) || (len < 0) ||
84 ((off + len) < 0) || ((off + len) > b.length)) {
85 throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
86 }
87 if (len == 0) {
88 return;
89 }
90 int newlen = this.len + len;
91 if (newlen > this.buffer.length) {
92 expand(newlen);
93 }
94 System.arraycopy(b, off, this.buffer, this.len, len);
95 this.len = newlen;
96 }
97
98 /**
99 * Appends <code>b</code> byte to this buffer. The capacity of the buffer
100 * is increased, if necessary, to accommodate the additional byte.
101 *
102 * @param b the byte to be appended.
103 */
104 public void append(int b) {
105 int newlen = this.len + 1;
106 if (newlen > this.buffer.length) {
107 expand(newlen);
108 }
109 this.buffer[this.len] = (byte)b;
110 this.len = newlen;
111 }
112
113 /**
114 * Appends <code>len</code> chars to this buffer from the given source
115 * array starting at index <code>off</code>. The capacity of the buffer
116 * is increased if necessary to accommodate all <code>len</code> chars.
117 * <p>
118 * The chars are converted to bytes using simple cast.
119 *
120 * @param b the chars to be appended.
121 * @param off the index of the first char to append.
122 * @param len the number of bytes to append.
123 * @throws IndexOutOfBoundsException if <code>off</code> if out of
124 * range, <code>len</code> is negative, or
125 * <code>off</code> + <code>len</code> is out of range.
126 */
127 public void append(final char[] b, int off, int len) {
128 if (b == null) {
129 return;
130 }
131 if ((off < 0) || (off > b.length) || (len < 0) ||
132 ((off + len) < 0) || ((off + len) > b.length)) {
133 throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
134 }
135 if (len == 0) {
136 return;
137 }
138 int oldlen = this.len;
139 int newlen = oldlen + len;
140 if (newlen > this.buffer.length) {
141 expand(newlen);
142 }
143 for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
144 this.buffer[i2] = (byte) b[i1];
145 }
146 this.len = newlen;
147 }
148
149 /**
150 * Appends <code>len</code> chars to this buffer from the given source
151 * char array buffer starting at index <code>off</code>. The capacity
152 * of the buffer is increased if necessary to accommodate all
153 * <code>len</code> chars.
154 * <p>
155 * The chars are converted to bytes using simple cast.
156 *
157 * @param b the chars to be appended.
158 * @param off the index of the first char to append.
159 * @param len the number of bytes to append.
160 * @throws IndexOutOfBoundsException if <code>off</code> if out of
161 * range, <code>len</code> is negative, or
162 * <code>off</code> + <code>len</code> is out of range.
163 */
164 public void append(final CharArrayBuffer b, int off, int len) {
165 if (b == null) {
166 return;
167 }
168 append(b.buffer(), off, len);
169 }
170
171 /**
172 * Clears content of the buffer. The underlying byte array is not resized.
173 */
174 public void clear() {
175 this.len = 0;
176 }
177
178 /**
179 * Converts the content of this buffer to an array of bytes.
180 *
181 * @return byte array
182 */
183 public byte[] toByteArray() {
184 byte[] b = new byte[this.len];
185 if (this.len > 0) {
186 System.arraycopy(this.buffer, 0, b, 0, this.len);
187 }
188 return b;
189 }
190
191 /**
192 * Returns the <code>byte</code> value in this buffer at the specified
193 * index. The index argument must be greater than or equal to
194 * <code>0</code>, and less than the length of this buffer.
195 *
196 * @param i the index of the desired byte value.
197 * @return the byte value at the specified index.
198 * @throws IndexOutOfBoundsException if <code>index</code> is
199 * negative or greater than or equal to {@link #length()}.
200 */
201 public int byteAt(int i) {
202 return this.buffer[i];
203 }
204
205 /**
206 * Returns the current capacity. The capacity is the amount of storage
207 * available for newly appended bytes, beyond which an allocation
208 * will occur.
209 *
210 * @return the current capacity
211 */
212 public int capacity() {
213 return this.buffer.length;
214 }
215
216 /**
217 * Returns the length of the buffer (byte count).
218 *
219 * @return the length of the buffer
220 */
221 public int length() {
222 return this.len;
223 }
224
225 /**
226 * Ensures that the capacity is at least equal to the specified minimum.
227 * If the current capacity is less than the argument, then a new internal
228 * array is allocated with greater capacity. If the <code>required</code>
229 * argument is non-positive, this method takes no action.
230 *
231 * @param required the minimum required capacity.
232 *
233 * @since 4.1
234 */
235 public void ensureCapacity(int required) {
236 if (required <= 0) {
237 return;
238 }
239 int available = this.buffer.length - this.len;
240 if (required > available) {
241 expand(this.len + required);
242 }
243 }
244
245 /**
246 * Returns reference to the underlying byte array.
247 *
248 * @return the byte array.
249 */
250 public byte[] buffer() {
251 return this.buffer;
252 }
253
254 /**
255 * Sets the length of the buffer. The new length value is expected to be
256 * less than the current capacity and greater than or equal to
257 * <code>0</code>.
258 *
259 * @param len the new length
260 * @throws IndexOutOfBoundsException if the
261 * <code>len</code> argument is greater than the current
262 * capacity of the buffer or less than <code>0</code>.
263 */
264 public void setLength(int len) {
265 if (len < 0 || len > this.buffer.length) {
266 throw new IndexOutOfBoundsException("len: "+len+" < 0 or > buffer len: "+this.buffer.length);
267 }
268 this.len = len;
269 }
270
271 /**
272 * Returns <code>true</code> if this buffer is empty, that is, its
273 * {@link #length()} is equal to <code>0</code>.
274 * @return <code>true</code> if this buffer is empty, <code>false</code>
275 * otherwise.
276 */
277 public boolean isEmpty() {
278 return this.len == 0;
279 }
280
281 /**
282 * Returns <code>true</code> if this buffer is full, that is, its
283 * {@link #length()} is equal to its {@link #capacity()}.
284 * @return <code>true</code> if this buffer is full, <code>false</code>
285 * otherwise.
286 */
287 public boolean isFull() {
288 return this.len == this.buffer.length;
289 }
290
291 /**
292 * Returns the index within this buffer of the first occurrence of the
293 * specified byte, starting the search at the specified
294 * <code>beginIndex</code> and finishing at <code>endIndex</code>.
295 * If no such byte occurs in this buffer within the specified bounds,
296 * <code>-1</code> is returned.
297 * <p>
298 * There is no restriction on the value of <code>beginIndex</code> and
299 * <code>endIndex</code>. If <code>beginIndex</code> is negative,
300 * it has the same effect as if it were zero. If <code>endIndex</code> is
301 * greater than {@link #length()}, it has the same effect as if it were
302 * {@link #length()}. If the <code>beginIndex</code> is greater than
303 * the <code>endIndex</code>, <code>-1</code> is returned.
304 *
305 * @param b the byte to search for.
306 * @param beginIndex the index to start the search from.
307 * @param endIndex the index to finish the search at.
308 * @return the index of the first occurrence of the byte in the buffer
309 * within the given bounds, or <code>-1</code> if the byte does
310 * not occur.
311 *
312 * @since 4.1
313 */
314 public int indexOf(byte b, int beginIndex, int endIndex) {
315 if (beginIndex < 0) {
316 beginIndex = 0;
317 }
318 if (endIndex > this.len) {
319 endIndex = this.len;
320 }
321 if (beginIndex > endIndex) {
322 return -1;
323 }
324 for (int i = beginIndex; i < endIndex; i++) {
325 if (this.buffer[i] == b) {
326 return i;
327 }
328 }
329 return -1;
330 }
331
332 /**
333 * Returns the index within this buffer of the first occurrence of the
334 * specified byte, starting the search at <code>0</code> and finishing
335 * at {@link #length()}. If no such byte occurs in this buffer within
336 * those bounds, <code>-1</code> is returned.
337 *
338 * @param b the byte to search for.
339 * @return the index of the first occurrence of the byte in the
340 * buffer, or <code>-1</code> if the byte does not occur.
341 *
342 * @since 4.1
343 */
344 public int indexOf(byte b) {
345 return indexOf(b, 0, this.len);
346 }
347 }