1 /* 2 * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.io; 27 28 import java.nio.charset.Charset; 29 import java.util.Arrays; 30 import java.util.Objects; 31 32 /** 33 * This class implements an output stream in which the data is 34 * written into a byte array. The buffer automatically grows as data 35 * is written to it. 36 * The data can be retrieved using {@code toByteArray()} and 37 * {@code toString()}. 38 * <p> 39 * Closing a {@code ByteArrayOutputStream} has no effect. The methods in 40 * this class can be called after the stream has been closed without 41 * generating an {@code IOException}. 42 * 43 * @author Arthur van Hoff 44 * @since 1.0 45 */ 46 47 public class ByteArrayOutputStream extends OutputStream { 48 /** 49 * The maximum size of array to allocate. 50 * Some VMs reserve some header words in an array. 51 * Attempts to allocate larger arrays may result in 52 * OutOfMemoryError: Requested array size exceeds VM limit 53 */ 54 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 55 56 /** 57 * The buffer where data is stored. 58 */ 59 protected byte buf[]; 60 61 /** 62 * The number of valid bytes in the buffer. 63 */ 64 protected int count; 65 66 /** 67 * Creates a new {@code ByteArrayOutputStream}. The buffer capacity is 68 * initially 32 bytes, though its size increases if necessary. 69 */ 70 public ByteArrayOutputStream() { 71 this(32); 72 } 73 74 /** 75 * Creates a new {@code ByteArrayOutputStream}, with a buffer capacity of 76 * the specified size, in bytes. 77 * 78 * @implNote 79 * The maximum size permitted by this implementation is 80 * {@code Integer.MAX_VALUE - 8}. 81 * 82 * @param size the initial size. 83 * @throws IllegalArgumentException if size is negative or exceeds the 84 * maximum permitted value. 85 */ 86 public ByteArrayOutputStream(int size) { 87 if (size < 0) { 88 throw new IllegalArgumentException("Negative initial size: " 89 + size); 90 } else if (size > MAX_ARRAY_SIZE) { 91 throw new IllegalArgumentException 92 ("Initial size " + size + " exceeds limit: " + MAX_ARRAY_SIZE); 93 } 94 buf = new byte[size]; 95 } 96 97 /** 98 * Increases the capacity if necessary to ensure that it can hold 99 * at least the number of elements specified by the minimum 100 * capacity argument. 101 * 102 * @param minCapacity the desired minimum capacity 103 * @throws OutOfMemoryError if {@code minCapacity < 0}. This is 104 * interpreted as a request for the unsatisfiably large capacity 105 * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}. 106 */ 107 private void ensureCapacity(int minCapacity) { 108 // overflow-conscious code 109 if (minCapacity - buf.length > 0) 110 grow(minCapacity); 111 } 112 113 /** 114 * Increases the capacity to ensure that it can hold at least the 115 * number of elements specified by the minimum capacity argument. 116 * 117 * @param minCapacity the desired minimum capacity 118 */ 119 private void grow(int minCapacity) { 120 if (minCapacity < 0) // overflow 121 throw new OutOfMemoryError("Memory capacity overflow: " 122 + minCapacity); 123 124 // overflow-conscious code 125 int oldCapacity = buf.length; 126 int newCapacity = oldCapacity << 1; 127 if (newCapacity - minCapacity < 0) 128 newCapacity = minCapacity; 129 if (newCapacity - MAX_ARRAY_SIZE > 0) 130 throw new OutOfMemoryError 131 ("Required capacity " + newCapacity 132 + " exceeds limit: " + MAX_ARRAY_SIZE); 133 buf = Arrays.copyOf(buf, newCapacity); 134 } 135 136 /** 137 * Writes the specified byte to this {@code ByteArrayOutputStream}. 138 * 139 * @param b the byte to be written. 140 */ 141 public synchronized void write(int b) { 142 ensureCapacity(count + 1); 143 buf[count] = (byte) b; 144 count += 1; 145 } 146 147 /** 148 * Writes {@code len} bytes from the specified byte array 149 * starting at offset {@code off} to this {@code ByteArrayOutputStream}. 150 * 151 * @param b the data. 152 * @param off the start offset in the data. 153 * @param len the number of bytes to write. 154 * @throws NullPointerException if {@code b} is {@code null}. 155 * @throws IndexOutOfBoundsException if {@code off} is negative, 156 * {@code len} is negative, or {@code len} is greater than 157 * {@code b.length - off} 158 */ 159 public synchronized void write(byte b[], int off, int len) { 160 Objects.checkFromIndexSize(off, len, b.length); 161 ensureCapacity(count + len); 162 System.arraycopy(b, off, buf, count, len); 163 count += len; 164 } 165 166 /** 167 * Writes the complete contents of the specified byte array 168 * to this {@code ByteArrayOutputStream}. 169 * 170 * @apiNote 171 * This method is equivalent to {@link #write(byte[],int,int) 172 * write(b, 0, b.length)}. 173 * 174 * @param b the data. 175 * @throws NullPointerException if {@code b} is {@code null}. 176 * @since 11 177 */ 178 public void writeBytes(byte b[]) { 179 write(b, 0, b.length); 180 } 181 182 /** 183 * Writes the complete contents of this {@code ByteArrayOutputStream} to 184 * the specified output stream argument, as if by calling the output 185 * stream's write method using {@code out.write(buf, 0, count)}. 186 * 187 * @param out the output stream to which to write the data. 188 * @throws NullPointerException if {@code out} is {@code null}. 189 * @throws IOException if an I/O error occurs. 190 */ 191 public synchronized void writeTo(OutputStream out) throws IOException { 192 out.write(buf, 0, count); 193 } 194 195 /** 196 * Resets the {@code count} field of this {@code ByteArrayOutputStream} 197 * to zero, so that all currently accumulated output in the 198 * output stream is discarded. The output stream can be used again, 199 * reusing the already allocated buffer space. 200 * 201 * @see java.io.ByteArrayInputStream#count 202 */ 203 public synchronized void reset() { 204 count = 0; 205 } 206 207 /** 208 * Creates a newly allocated byte array. Its size is the current 209 * size of this output stream and the valid contents of the buffer 210 * have been copied into it. 211 * 212 * @return the current contents of this output stream, as a byte array. 213 * @see java.io.ByteArrayOutputStream#size() 214 */ 215 public synchronized byte[] toByteArray() { 216 return Arrays.copyOf(buf, count); 217 } 218 219 /** 220 * Returns the current size of the buffer. 221 * 222 * @return the value of the {@code count} field, which is the number 223 * of valid bytes in this output stream. 224 * @see java.io.ByteArrayOutputStream#count 225 */ 226 public synchronized int size() { 227 return count; 228 } 229 230 /** 231 * Converts the buffer's contents into a string decoding bytes using the 232 * platform's default character set. The length of the new {@code String} 233 * is a function of the character set, and hence may not be equal to the 234 * size of the buffer. 235 * 236 * <p> This method always replaces malformed-input and unmappable-character 237 * sequences with the default replacement string for the platform's 238 * default character set. The {@linkplain java.nio.charset.CharsetDecoder} 239 * class should be used when more control over the decoding process is 240 * required. 241 * 242 * @return String decoded from the buffer's contents. 243 * @since 1.1 244 */ 245 public synchronized String toString() { 246 return new String(buf, 0, count); 247 } 248 249 /** 250 * Converts the buffer's contents into a string by decoding the bytes using 251 * the named {@link java.nio.charset.Charset charset}. 252 * 253 * <p> This method is equivalent to {@code #toString(charset)} that takes a 254 * {@link java.nio.charset.Charset charset}. 255 * 256 * <p> An invocation of this method of the form 257 * 258 * <pre> {@code 259 * ByteArrayOutputStream b = ... 260 * b.toString("UTF-8") 261 * } 262 * </pre> 263 * 264 * behaves in exactly the same way as the expression 265 * 266 * <pre> {@code 267 * ByteArrayOutputStream b = ... 268 * b.toString(StandardCharsets.UTF_8) 269 * } 270 * </pre> 271 * 272 * 273 * @param charsetName the name of a supported 274 * {@link java.nio.charset.Charset charset} 275 * @return String decoded from the buffer's contents. 276 * @throws UnsupportedEncodingException 277 * If the named charset is not supported 278 * @since 1.1 279 */ 280 public synchronized String toString(String charsetName) 281 throws UnsupportedEncodingException 282 { 283 return new String(buf, 0, count, charsetName); 284 } 285 286 /** 287 * Converts the buffer's contents into a string by decoding the bytes using 288 * the specified {@link java.nio.charset.Charset charset}. The length of the new 289 * {@code String} is a function of the charset, and hence may not be equal 290 * to the length of the byte array. 291 * 292 * <p> This method always replaces malformed-input and unmappable-character 293 * sequences with the charset's default replacement string. The {@link 294 * java.nio.charset.CharsetDecoder} class should be used when more control 295 * over the decoding process is required. 296 * 297 * @param charset the {@linkplain java.nio.charset.Charset charset} 298 * to be used to decode the {@code bytes} 299 * @return String decoded from the buffer's contents. 300 * @since 10 301 */ 302 public synchronized String toString(Charset charset) { 303 return new String(buf, 0, count, charset); 304 } 305 306 /** 307 * Creates a newly allocated string. Its size is the current size of 308 * the output stream and the valid contents of the buffer have been 309 * copied into it. Each character <i>c</i> in the resulting string is 310 * constructed from the corresponding element <i>b</i> in the byte 311 * array such that: 312 * <blockquote><pre>{@code 313 * c == (char)(((hibyte & 0xff) << 8) | (b & 0xff)) 314 * }</pre></blockquote> 315 * 316 * @deprecated This method does not properly convert bytes into characters. 317 * As of JDK 1.1, the preferred way to do this is via the 318 * {@link #toString(String charsetName)} or {@link #toString(Charset charset)} 319 * method, which takes an encoding-name or charset argument, 320 * or the {@code toString()} method, which uses the platform's default 321 * character encoding. 322 * 323 * @param hibyte the high byte of each resulting Unicode character. 324 * @return the current contents of the output stream, as a string. 325 * @see java.io.ByteArrayOutputStream#size() 326 * @see java.io.ByteArrayOutputStream#toString(String) 327 * @see java.io.ByteArrayOutputStream#toString() 328 */ 329 @Deprecated 330 public synchronized String toString(int hibyte) { 331 return new String(buf, hibyte, 0, count); 332 } 333 334 /** 335 * Closing a {@code ByteArrayOutputStream} has no effect. The methods in 336 * this class can be called after the stream has been closed without 337 * generating an {@code IOException}. 338 */ 339 public void close() throws IOException { 340 } 341 342 }