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}