View Javadoc

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         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 }