michael@0: /* michael@0: * ==================================================================== michael@0: * Licensed to the Apache Software Foundation (ASF) under one michael@0: * or more contributor license agreements. See the NOTICE file michael@0: * distributed with this work for additional information michael@0: * regarding copyright ownership. The ASF licenses this file michael@0: * to you under the Apache License, Version 2.0 (the michael@0: * "License"); you may not use this file except in compliance michael@0: * with the License. You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, michael@0: * software distributed under the License is distributed on an michael@0: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY michael@0: * KIND, either express or implied. See the License for the michael@0: * specific language governing permissions and limitations michael@0: * under the License. michael@0: * ==================================================================== michael@0: * michael@0: * This software consists of voluntary contributions made by many michael@0: * individuals on behalf of the Apache Software Foundation. For more michael@0: * information on the Apache Software Foundation, please see michael@0: * . michael@0: * michael@0: */ michael@0: michael@0: package ch.boye.httpclientandroidlib.util; michael@0: michael@0: import java.io.Serializable; michael@0: michael@0: /** michael@0: * A resizable byte array. michael@0: * michael@0: * @since 4.0 michael@0: */ michael@0: public final class ByteArrayBuffer implements Serializable { michael@0: michael@0: private static final long serialVersionUID = 4359112959524048036L; michael@0: michael@0: private byte[] buffer; michael@0: private int len; michael@0: michael@0: /** michael@0: * Creates an instance of {@link ByteArrayBuffer} with the given initial michael@0: * capacity. michael@0: * michael@0: * @param capacity the capacity michael@0: */ michael@0: public ByteArrayBuffer(int capacity) { michael@0: super(); michael@0: if (capacity < 0) { michael@0: throw new IllegalArgumentException("Buffer capacity may not be negative"); michael@0: } michael@0: this.buffer = new byte[capacity]; michael@0: } michael@0: michael@0: private void expand(int newlen) { michael@0: byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)]; michael@0: System.arraycopy(this.buffer, 0, newbuffer, 0, this.len); michael@0: this.buffer = newbuffer; michael@0: } michael@0: michael@0: /** michael@0: * Appends len bytes to this buffer from the given source michael@0: * array starting at index off. The capacity of the buffer michael@0: * is increased, if necessary, to accommodate all len bytes. michael@0: * michael@0: * @param b the bytes to be appended. michael@0: * @param off the index of the first byte to append. michael@0: * @param len the number of bytes to append. michael@0: * @throws IndexOutOfBoundsException if off if out of michael@0: * range, len is negative, or michael@0: * off + len is out of range. michael@0: */ michael@0: public void append(final byte[] b, int off, int len) { michael@0: if (b == null) { michael@0: return; michael@0: } michael@0: if ((off < 0) || (off > b.length) || (len < 0) || michael@0: ((off + len) < 0) || ((off + len) > b.length)) { michael@0: throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length); michael@0: } michael@0: if (len == 0) { michael@0: return; michael@0: } michael@0: int newlen = this.len + len; michael@0: if (newlen > this.buffer.length) { michael@0: expand(newlen); michael@0: } michael@0: System.arraycopy(b, off, this.buffer, this.len, len); michael@0: this.len = newlen; michael@0: } michael@0: michael@0: /** michael@0: * Appends b byte to this buffer. The capacity of the buffer michael@0: * is increased, if necessary, to accommodate the additional byte. michael@0: * michael@0: * @param b the byte to be appended. michael@0: */ michael@0: public void append(int b) { michael@0: int newlen = this.len + 1; michael@0: if (newlen > this.buffer.length) { michael@0: expand(newlen); michael@0: } michael@0: this.buffer[this.len] = (byte)b; michael@0: this.len = newlen; michael@0: } michael@0: michael@0: /** michael@0: * Appends len chars to this buffer from the given source michael@0: * array starting at index off. The capacity of the buffer michael@0: * is increased if necessary to accommodate all len chars. michael@0: *

michael@0: * The chars are converted to bytes using simple cast. michael@0: * michael@0: * @param b the chars to be appended. michael@0: * @param off the index of the first char to append. michael@0: * @param len the number of bytes to append. michael@0: * @throws IndexOutOfBoundsException if off if out of michael@0: * range, len is negative, or michael@0: * off + len is out of range. michael@0: */ michael@0: public void append(final char[] b, int off, int len) { michael@0: if (b == null) { michael@0: return; michael@0: } michael@0: if ((off < 0) || (off > b.length) || (len < 0) || michael@0: ((off + len) < 0) || ((off + len) > b.length)) { michael@0: throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length); michael@0: } michael@0: if (len == 0) { michael@0: return; michael@0: } michael@0: int oldlen = this.len; michael@0: int newlen = oldlen + len; michael@0: if (newlen > this.buffer.length) { michael@0: expand(newlen); michael@0: } michael@0: for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) { michael@0: this.buffer[i2] = (byte) b[i1]; michael@0: } michael@0: this.len = newlen; michael@0: } michael@0: michael@0: /** michael@0: * Appends len chars to this buffer from the given source michael@0: * char array buffer starting at index off. The capacity michael@0: * of the buffer is increased if necessary to accommodate all michael@0: * len chars. michael@0: *

michael@0: * The chars are converted to bytes using simple cast. michael@0: * michael@0: * @param b the chars to be appended. michael@0: * @param off the index of the first char to append. michael@0: * @param len the number of bytes to append. michael@0: * @throws IndexOutOfBoundsException if off if out of michael@0: * range, len is negative, or michael@0: * off + len is out of range. michael@0: */ michael@0: public void append(final CharArrayBuffer b, int off, int len) { michael@0: if (b == null) { michael@0: return; michael@0: } michael@0: append(b.buffer(), off, len); michael@0: } michael@0: michael@0: /** michael@0: * Clears content of the buffer. The underlying byte array is not resized. michael@0: */ michael@0: public void clear() { michael@0: this.len = 0; michael@0: } michael@0: michael@0: /** michael@0: * Converts the content of this buffer to an array of bytes. michael@0: * michael@0: * @return byte array michael@0: */ michael@0: public byte[] toByteArray() { michael@0: byte[] b = new byte[this.len]; michael@0: if (this.len > 0) { michael@0: System.arraycopy(this.buffer, 0, b, 0, this.len); michael@0: } michael@0: return b; michael@0: } michael@0: michael@0: /** michael@0: * Returns the byte value in this buffer at the specified michael@0: * index. The index argument must be greater than or equal to michael@0: * 0, and less than the length of this buffer. michael@0: * michael@0: * @param i the index of the desired byte value. michael@0: * @return the byte value at the specified index. michael@0: * @throws IndexOutOfBoundsException if index is michael@0: * negative or greater than or equal to {@link #length()}. michael@0: */ michael@0: public int byteAt(int i) { michael@0: return this.buffer[i]; michael@0: } michael@0: michael@0: /** michael@0: * Returns the current capacity. The capacity is the amount of storage michael@0: * available for newly appended bytes, beyond which an allocation michael@0: * will occur. michael@0: * michael@0: * @return the current capacity michael@0: */ michael@0: public int capacity() { michael@0: return this.buffer.length; michael@0: } michael@0: michael@0: /** michael@0: * Returns the length of the buffer (byte count). michael@0: * michael@0: * @return the length of the buffer michael@0: */ michael@0: public int length() { michael@0: return this.len; michael@0: } michael@0: michael@0: /** michael@0: * Ensures that the capacity is at least equal to the specified minimum. michael@0: * If the current capacity is less than the argument, then a new internal michael@0: * array is allocated with greater capacity. If the required michael@0: * argument is non-positive, this method takes no action. michael@0: * michael@0: * @param required the minimum required capacity. michael@0: * michael@0: * @since 4.1 michael@0: */ michael@0: public void ensureCapacity(int required) { michael@0: if (required <= 0) { michael@0: return; michael@0: } michael@0: int available = this.buffer.length - this.len; michael@0: if (required > available) { michael@0: expand(this.len + required); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Returns reference to the underlying byte array. michael@0: * michael@0: * @return the byte array. michael@0: */ michael@0: public byte[] buffer() { michael@0: return this.buffer; michael@0: } michael@0: michael@0: /** michael@0: * Sets the length of the buffer. The new length value is expected to be michael@0: * less than the current capacity and greater than or equal to michael@0: * 0. michael@0: * michael@0: * @param len the new length michael@0: * @throws IndexOutOfBoundsException if the michael@0: * len argument is greater than the current michael@0: * capacity of the buffer or less than 0. michael@0: */ michael@0: public void setLength(int len) { michael@0: if (len < 0 || len > this.buffer.length) { michael@0: throw new IndexOutOfBoundsException("len: "+len+" < 0 or > buffer len: "+this.buffer.length); michael@0: } michael@0: this.len = len; michael@0: } michael@0: michael@0: /** michael@0: * Returns true if this buffer is empty, that is, its michael@0: * {@link #length()} is equal to 0. michael@0: * @return true if this buffer is empty, false michael@0: * otherwise. michael@0: */ michael@0: public boolean isEmpty() { michael@0: return this.len == 0; michael@0: } michael@0: michael@0: /** michael@0: * Returns true if this buffer is full, that is, its michael@0: * {@link #length()} is equal to its {@link #capacity()}. michael@0: * @return true if this buffer is full, false michael@0: * otherwise. michael@0: */ michael@0: public boolean isFull() { michael@0: return this.len == this.buffer.length; michael@0: } michael@0: michael@0: /** michael@0: * Returns the index within this buffer of the first occurrence of the michael@0: * specified byte, starting the search at the specified michael@0: * beginIndex and finishing at endIndex. michael@0: * If no such byte occurs in this buffer within the specified bounds, michael@0: * -1 is returned. michael@0: *

michael@0: * There is no restriction on the value of beginIndex and michael@0: * endIndex. If beginIndex is negative, michael@0: * it has the same effect as if it were zero. If endIndex is michael@0: * greater than {@link #length()}, it has the same effect as if it were michael@0: * {@link #length()}. If the beginIndex is greater than michael@0: * the endIndex, -1 is returned. michael@0: * michael@0: * @param b the byte to search for. michael@0: * @param beginIndex the index to start the search from. michael@0: * @param endIndex the index to finish the search at. michael@0: * @return the index of the first occurrence of the byte in the buffer michael@0: * within the given bounds, or -1 if the byte does michael@0: * not occur. michael@0: * michael@0: * @since 4.1 michael@0: */ michael@0: public int indexOf(byte b, int beginIndex, int endIndex) { michael@0: if (beginIndex < 0) { michael@0: beginIndex = 0; michael@0: } michael@0: if (endIndex > this.len) { michael@0: endIndex = this.len; michael@0: } michael@0: if (beginIndex > endIndex) { michael@0: return -1; michael@0: } michael@0: for (int i = beginIndex; i < endIndex; i++) { michael@0: if (this.buffer[i] == b) { michael@0: return i; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: /** michael@0: * Returns the index within this buffer of the first occurrence of the michael@0: * specified byte, starting the search at 0 and finishing michael@0: * at {@link #length()}. If no such byte occurs in this buffer within michael@0: * those bounds, -1 is returned. michael@0: * michael@0: * @param b the byte to search for. michael@0: * @return the index of the first occurrence of the byte in the michael@0: * buffer, or -1 if the byte does not occur. michael@0: * michael@0: * @since 4.1 michael@0: */ michael@0: public int indexOf(byte b) { michael@0: return indexOf(b, 0, this.len); michael@0: } michael@0: }