001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.util;
029
030import java.io.Serializable;
031
032/**
033 * A resizable byte array.
034 *
035 * @since 4.0
036 */
037public final class ByteArrayBuffer implements Serializable {
038
039    private static final long serialVersionUID = 4359112959524048036L;
040
041    private byte[] buffer;
042    private int len;
043
044    /**
045     * Creates an instance of {@link ByteArrayBuffer} with the given initial
046     * capacity.
047     *
048     * @param capacity the capacity
049     */
050    public ByteArrayBuffer(final int capacity) {
051        super();
052        Args.notNegative(capacity, "Buffer capacity");
053        this.buffer = new byte[capacity];
054    }
055
056    private void expand(final int newlen) {
057        final byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
058        System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
059        this.buffer = newbuffer;
060    }
061
062    /**
063     * Appends {@code len} bytes to this buffer from the given source
064     * array starting at index {@code off}. The capacity of the buffer
065     * is increased, if necessary, to accommodate all {@code len} bytes.
066     *
067     * @param   b        the bytes to be appended.
068     * @param   off      the index of the first byte to append.
069     * @param   len      the number of bytes to append.
070     * @throws IndexOutOfBoundsException if {@code off} if out of
071     * range, {@code len} is negative, or
072     * {@code off} + {@code len} is out of range.
073     */
074    public void append(final byte[] b, final int off, final int len) {
075        if (b == null) {
076            return;
077        }
078        if ((off < 0) || (off > b.length) || (len < 0) ||
079                ((off + len) < 0) || ((off + len) > b.length)) {
080            throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
081        }
082        if (len == 0) {
083            return;
084        }
085        final int newlen = this.len + len;
086        if (newlen > this.buffer.length) {
087            expand(newlen);
088        }
089        System.arraycopy(b, off, this.buffer, this.len, len);
090        this.len = newlen;
091    }
092
093    /**
094     * Appends {@code b} byte to this buffer. The capacity of the buffer
095     * is increased, if necessary, to accommodate the additional byte.
096     *
097     * @param   b        the byte to be appended.
098     */
099    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        for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
139            this.buffer[i2] = (byte) b[i1];
140        }
141        this.len = newlen;
142    }
143
144    /**
145     * Appends {@code len} chars to this buffer from the given source
146     * char array buffer starting at index {@code off}. The capacity
147     * of the buffer is increased if necessary to accommodate all
148     * {@code len} chars.
149     * <p>
150     * The chars are converted to bytes using simple cast.
151     *
152     * @param   b        the chars to be appended.
153     * @param   off      the index of the first char to append.
154     * @param   len      the number of bytes to append.
155     * @throws IndexOutOfBoundsException if {@code off} if out of
156     * range, {@code len} is negative, or
157     * {@code off} + {@code len} is out of range.
158     */
159    public void append(final CharArrayBuffer b, final int off, final int len) {
160        if (b == null) {
161            return;
162        }
163        append(b.buffer(), off, len);
164    }
165
166    /**
167     * Clears content of the buffer. The underlying byte array is not resized.
168     */
169    public void clear() {
170        this.len = 0;
171    }
172
173    /**
174     * Converts the content of this buffer to an array of bytes.
175     *
176     * @return byte array
177     */
178    public byte[] toByteArray() {
179        final byte[] b = new byte[this.len];
180        if (this.len > 0) {
181            System.arraycopy(this.buffer, 0, b, 0, this.len);
182        }
183        return b;
184    }
185
186    /**
187     * Returns the {@code byte} value in this buffer at the specified
188     * index. The index argument must be greater than or equal to
189     * {@code 0}, and less than the length of this buffer.
190     *
191     * @param      i   the index of the desired byte value.
192     * @return     the byte value at the specified index.
193     * @throws     IndexOutOfBoundsException  if {@code index} is
194     *             negative or greater than or equal to {@link #length()}.
195     */
196    public int byteAt(final int i) {
197        return this.buffer[i];
198    }
199
200    /**
201     * Returns the current capacity. The capacity is the amount of storage
202     * available for newly appended bytes, beyond which an allocation
203     * will occur.
204     *
205     * @return  the current capacity
206     */
207    public int capacity() {
208        return this.buffer.length;
209    }
210
211    /**
212     * Returns the length of the buffer (byte count).
213     *
214     * @return  the length of the buffer
215     */
216    public int length() {
217        return this.len;
218    }
219
220    /**
221     * Ensures that the capacity is at least equal to the specified minimum.
222     * If the current capacity is less than the argument, then a new internal
223     * array is allocated with greater capacity. If the {@code required}
224     * argument is non-positive, this method takes no action.
225     *
226     * @param   required   the minimum required capacity.
227     *
228     * @since 4.1
229     */
230    public void ensureCapacity(final int required) {
231        if (required <= 0) {
232            return;
233        }
234        final int available = this.buffer.length - this.len;
235        if (required > available) {
236            expand(this.len + required);
237        }
238    }
239
240    /**
241     * Returns reference to the underlying byte array.
242     *
243     * @return the byte array.
244     */
245    public byte[] buffer() {
246        return this.buffer;
247    }
248
249    /**
250     * Sets the length of the buffer. The new length value is expected to be
251     * less than the current capacity and greater than or equal to
252     * {@code 0}.
253     *
254     * @param      len   the new length
255     * @throws     IndexOutOfBoundsException  if the
256     *               {@code len} argument is greater than the current
257     *               capacity of the buffer or less than {@code 0}.
258     */
259    public void setLength(final int len) {
260        if (len < 0 || len > this.buffer.length) {
261            throw new IndexOutOfBoundsException("len: "+len+" < 0 or > buffer len: "+this.buffer.length);
262        }
263        this.len = len;
264    }
265
266    /**
267     * Returns {@code true} if this buffer is empty, that is, its
268     * {@link #length()} is equal to {@code 0}.
269     * @return {@code true} if this buffer is empty, {@code false}
270     *   otherwise.
271     */
272    public boolean isEmpty() {
273        return this.len == 0;
274    }
275
276    /**
277     * Returns {@code true} if this buffer is full, that is, its
278     * {@link #length()} is equal to its {@link #capacity()}.
279     * @return {@code true} if this buffer is full, {@code false}
280     *   otherwise.
281     */
282    public boolean isFull() {
283        return this.len == this.buffer.length;
284    }
285
286    /**
287     * Returns the index within this buffer of the first occurrence of the
288     * specified byte, starting the search at the specified
289     * {@code beginIndex} and finishing at {@code endIndex}.
290     * If no such byte occurs in this buffer within the specified bounds,
291     * {@code -1} is returned.
292     * <p>
293     * There is no restriction on the value of {@code beginIndex} and
294     * {@code endIndex}. If {@code beginIndex} is negative,
295     * it has the same effect as if it were zero. If {@code endIndex} is
296     * greater than {@link #length()}, it has the same effect as if it were
297     * {@link #length()}. If the {@code beginIndex} is greater than
298     * the {@code endIndex}, {@code -1} is returned.
299     *
300     * @param   b            the byte to search for.
301     * @param   from         the index to start the search from.
302     * @param   to           the index to finish the search at.
303     * @return  the index of the first occurrence of the byte in the buffer
304     *   within the given bounds, or {@code -1} if the byte does
305     *   not occur.
306     *
307     * @since 4.1
308     */
309    public int indexOf(final byte b, final int from, final int to) {
310        int beginIndex = from;
311        if (beginIndex < 0) {
312            beginIndex = 0;
313        }
314        int endIndex = to;
315        if (endIndex > this.len) {
316            endIndex = this.len;
317        }
318        if (beginIndex > endIndex) {
319            return -1;
320        }
321        for (int i = beginIndex; i < endIndex; i++) {
322            if (this.buffer[i] == b) {
323                return i;
324            }
325        }
326        return -1;
327    }
328
329    /**
330     * Returns the index within this buffer of the first occurrence of the
331     * specified byte, starting the search at {@code 0} and finishing
332     * at {@link #length()}. If no such byte occurs in this buffer within
333     * those bounds, {@code -1} is returned.
334     *
335     * @param   b   the byte to search for.
336     * @return  the index of the first occurrence of the byte in the
337     *   buffer, or {@code -1} if the byte does not occur.
338     *
339     * @since 4.1
340     */
341    public int indexOf(final byte b) {
342        return indexOf(b, 0, this.len);
343    }
344}