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 /**
33 * A resizable byte array.
34 *
35 * @since 4.0
36 */
37 public final class ByteArrayBuffer implements Serializable {
38
39 private static final long serialVersionUID = 4359112959524048036L;
40
41 private byte[] buffer;
42 private int len;
43
44 /**
45 * Creates an instance of {@link ByteArrayBuffer} with the given initial
46 * capacity.
47 *
48 * @param capacity the capacity
49 */
50 public ByteArrayBuffer(final int capacity) {
51 super();
52 Args.notNegative(capacity, "Buffer capacity");
53 this.buffer = new byte[capacity];
54 }
55
56 private void expand(final int newlen) {
57 final byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
58 System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
59 this.buffer = newbuffer;
60 }
61
62 /**
63 * Appends {@code len} bytes to this buffer from the given source
64 * array starting at index {@code off}. The capacity of the buffer
65 * is increased, if necessary, to accommodate all {@code len} bytes.
66 *
67 * @param b the bytes to be appended.
68 * @param off the index of the first byte to append.
69 * @param len the number of bytes to append.
70 * @throws IndexOutOfBoundsException if {@code off} if out of
71 * range, {@code len} is negative, or
72 * {@code off} + {@code len} is out of range.
73 */
74 public void append(final byte[] b, final int off, final int len) {
75 if (b == null) {
76 return;
77 }
78 if ((off < 0) || (off > b.length) || (len < 0) ||
79 ((off + len) < 0) || ((off + len) > b.length)) {
80 throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
81 }
82 if (len == 0) {
83 return;
84 }
85 final int newlen = this.len + len;
86 if (newlen > this.buffer.length) {
87 expand(newlen);
88 }
89 System.arraycopy(b, off, this.buffer, this.len, len);
90 this.len = newlen;
91 }
92
93 /**
94 * Appends {@code b} byte to this buffer. The capacity of the buffer
95 * is increased, if necessary, to accommodate the additional byte.
96 *
97 * @param b the byte to be appended.
98 */
99 public void append(final int b) {
100 final int newlen = this.len + 1;
101 if (newlen > this.buffer.length) {
102 expand(newlen);
103 }
104 this.buffer[this.len] = (byte)b;
105 this.len = newlen;
106 }
107
108 /**
109 * Appends {@code len} chars to this buffer from the given source
110 * array starting at index {@code off}. The capacity of the buffer
111 * is increased if necessary to accommodate all {@code len} chars.
112 * <p>
113 * The chars are converted to bytes using simple cast.
114 *
115 * @param b the chars to be appended.
116 * @param off the index of the first char to append.
117 * @param len the number of bytes to append.
118 * @throws IndexOutOfBoundsException if {@code off} if out of
119 * range, {@code len} is negative, or
120 * {@code off} + {@code len} is out of range.
121 */
122 public void append(final char[] b, final int off, final int len) {
123 if (b == null) {
124 return;
125 }
126 if ((off < 0) || (off > b.length) || (len < 0) ||
127 ((off + len) < 0) || ((off + len) > b.length)) {
128 throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
129 }
130 if (len == 0) {
131 return;
132 }
133 final int oldlen = this.len;
134 final int newlen = oldlen + len;
135 if (newlen > this.buffer.length) {
136 expand(newlen);
137 }
138
139 for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
140 final int c = b[i1];
141 if ((c >= 0x20 && c <= 0x7E) || // Visible ASCII
142 (c >= 0xA0 && c <= 0xFF) || // Visible ISO-8859-1
143 c == 0x09) { // TAB
144 this.buffer[i2] = (byte) c;
145 } else {
146 this.buffer[i2] = '?';
147 }
148 }
149 this.len = newlen;
150 }
151
152 /**
153 * Appends {@code len} chars to this buffer from the given source
154 * char array buffer starting at index {@code off}. The capacity
155 * of the buffer is increased if necessary to accommodate all
156 * {@code len} chars.
157 * <p>
158 * The chars are converted to bytes using simple cast.
159 *
160 * @param b the chars to be appended.
161 * @param off the index of the first char to append.
162 * @param len the number of bytes to append.
163 * @throws IndexOutOfBoundsException if {@code off} if out of
164 * range, {@code len} is negative, or
165 * {@code off} + {@code len} is out of range.
166 */
167 public void append(final CharArrayBuffer b, final int off, final int len) {
168 if (b == null) {
169 return;
170 }
171 append(b.buffer(), off, len);
172 }
173
174 /**
175 * Clears content of the buffer. The underlying byte array is not resized.
176 */
177 public void clear() {
178 this.len = 0;
179 }
180
181 /**
182 * Converts the content of this buffer to an array of bytes.
183 *
184 * @return byte array
185 */
186 public byte[] toByteArray() {
187 final byte[] b = new byte[this.len];
188 if (this.len > 0) {
189 System.arraycopy(this.buffer, 0, b, 0, this.len);
190 }
191 return b;
192 }
193
194 /**
195 * Returns the {@code byte} value in this buffer at the specified
196 * index. The index argument must be greater than or equal to
197 * {@code 0}, and less than the length of this buffer.
198 *
199 * @param i the index of the desired byte value.
200 * @return the byte value at the specified index.
201 * @throws IndexOutOfBoundsException if {@code index} is
202 * negative or greater than or equal to {@link #length()}.
203 */
204 public int byteAt(final int i) {
205 return this.buffer[i];
206 }
207
208 /**
209 * Returns the current capacity. The capacity is the amount of storage
210 * available for newly appended bytes, beyond which an allocation
211 * will occur.
212 *
213 * @return the current capacity
214 */
215 public int capacity() {
216 return this.buffer.length;
217 }
218
219 /**
220 * Returns the length of the buffer (byte count).
221 *
222 * @return the length of the buffer
223 */
224 public int length() {
225 return this.len;
226 }
227
228 /**
229 * Ensures that the capacity is at least equal to the specified minimum.
230 * If the current capacity is less than the argument, then a new internal
231 * array is allocated with greater capacity. If the {@code required}
232 * argument is non-positive, this method takes no action.
233 *
234 * @param required the minimum required capacity.
235 *
236 * @since 4.1
237 */
238 public void ensureCapacity(final int required) {
239 if (required <= 0) {
240 return;
241 }
242 final int available = this.buffer.length - this.len;
243 if (required > available) {
244 expand(this.len + required);
245 }
246 }
247
248 /**
249 * Returns reference to the underlying byte array.
250 *
251 * @return the byte array.
252 */
253 public byte[] buffer() {
254 return this.buffer;
255 }
256
257 /**
258 * Sets the length of the buffer. The new length value is expected to be
259 * less than the current capacity and greater than or equal to
260 * {@code 0}.
261 *
262 * @param len the new length
263 * @throws IndexOutOfBoundsException if the
264 * {@code len} argument is greater than the current
265 * capacity of the buffer or less than {@code 0}.
266 */
267 public void setLength(final int len) {
268 if (len < 0 || len > this.buffer.length) {
269 throw new IndexOutOfBoundsException("len: "+len+" < 0 or > buffer len: "+this.buffer.length);
270 }
271 this.len = len;
272 }
273
274 /**
275 * Returns {@code true} if this buffer is empty, that is, its
276 * {@link #length()} is equal to {@code 0}.
277 * @return {@code true} if this buffer is empty, {@code false}
278 * otherwise.
279 */
280 public boolean isEmpty() {
281 return this.len == 0;
282 }
283
284 /**
285 * Returns {@code true} if this buffer is full, that is, its
286 * {@link #length()} is equal to its {@link #capacity()}.
287 * @return {@code true} if this buffer is full, {@code false}
288 * otherwise.
289 */
290 public boolean isFull() {
291 return this.len == this.buffer.length;
292 }
293
294 /**
295 * Returns the index within this buffer of the first occurrence of the
296 * specified byte, starting the search at the specified
297 * {@code beginIndex} and finishing at {@code endIndex}.
298 * If no such byte occurs in this buffer within the specified bounds,
299 * {@code -1} is returned.
300 * <p>
301 * There is no restriction on the value of {@code beginIndex} and
302 * {@code endIndex}. If {@code beginIndex} is negative,
303 * it has the same effect as if it were zero. If {@code endIndex} is
304 * greater than {@link #length()}, it has the same effect as if it were
305 * {@link #length()}. If the {@code beginIndex} is greater than
306 * the {@code endIndex}, {@code -1} is returned.
307 *
308 * @param b the byte to search for.
309 * @param from the index to start the search from.
310 * @param to the index to finish the search at.
311 * @return the index of the first occurrence of the byte in the buffer
312 * within the given bounds, or {@code -1} if the byte does
313 * not occur.
314 *
315 * @since 4.1
316 */
317 public int indexOf(final byte b, final int from, final int to) {
318 int beginIndex = from;
319 if (beginIndex < 0) {
320 beginIndex = 0;
321 }
322 int endIndex = to;
323 if (endIndex > this.len) {
324 endIndex = this.len;
325 }
326 if (beginIndex > endIndex) {
327 return -1;
328 }
329 for (int i = beginIndex; i < endIndex; i++) {
330 if (this.buffer[i] == b) {
331 return i;
332 }
333 }
334 return -1;
335 }
336
337 /**
338 * Returns the index within this buffer of the first occurrence of the
339 * specified byte, starting the search at {@code 0} and finishing
340 * at {@link #length()}. If no such byte occurs in this buffer within
341 * those bounds, {@code -1} is returned.
342 *
343 * @param b the byte to search for.
344 * @return the index of the first occurrence of the byte in the
345 * buffer, or {@code -1} if the byte does not occur.
346 *
347 * @since 4.1
348 */
349 public int indexOf(final byte b) {
350 return indexOf(b, 0, this.len);
351 }
352 }
353