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