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&nbsp;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 }