1 /*
2  * Copyright (c) 1994, 2019, 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 import jdk.internal.util.ArraysSupport;
33 
34 /**
35  * This class implements an output stream in which the data is
36  * written into a byte array. The buffer automatically grows as data
37  * is written to it.
38  * The data can be retrieved using {@code toByteArray()} and
39  * {@code toString()}.
40  * <p>
41  * Closing a {@code ByteArrayOutputStream} has no effect. The methods in
42  * this class can be called after the stream has been closed without
43  * generating an {@code IOException}.
44  *
45  * @author  Arthur van Hoff
46  * @since   1.0
47  */
48 
49 public class ByteArrayOutputStream extends OutputStream {
50 
51     /**
52      * The buffer where data is stored.
53      */
54     protected byte buf[];
55 
56     /**
57      * The number of valid bytes in the buffer.
58      */
59     protected int count;
60 
61     /**
62      * Creates a new {@code ByteArrayOutputStream}. The buffer capacity is
63      * initially 32 bytes, though its size increases if necessary.
64      */
ByteArrayOutputStream()65     public ByteArrayOutputStream() {
66         this(32);
67     }
68 
69     /**
70      * Creates a new {@code ByteArrayOutputStream}, with a buffer capacity of
71      * the specified size, in bytes.
72      *
73      * @param  size   the initial size.
74      * @throws IllegalArgumentException if size is negative.
75      */
ByteArrayOutputStream(int size)76     public ByteArrayOutputStream(int size) {
77         if (size < 0) {
78             throw new IllegalArgumentException("Negative initial size: "
79                                                + size);
80         }
81         buf = new byte[size];
82     }
83 
84     /**
85      * Increases the capacity if necessary to ensure that it can hold
86      * at least the number of elements specified by the minimum
87      * capacity argument.
88      *
89      * @param  minCapacity the desired minimum capacity.
90      * @throws OutOfMemoryError if {@code minCapacity < 0} and
91      * {@code minCapacity - buf.length > 0}.  This is interpreted as a
92      * request for the unsatisfiably large capacity.
93      * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
94      */
ensureCapacity(int minCapacity)95     private void ensureCapacity(int minCapacity) {
96         // overflow-conscious code
97         int oldCapacity = buf.length;
98         int minGrowth = minCapacity - oldCapacity;
99         if (minGrowth > 0) {
100             buf = Arrays.copyOf(buf, ArraysSupport.newLength(oldCapacity,
101                     minGrowth, oldCapacity /* preferred growth */));
102         }
103     }
104 
105     /**
106      * Writes the specified byte to this {@code ByteArrayOutputStream}.
107      *
108      * @param   b   the byte to be written.
109      */
write(int b)110     public synchronized void write(int b) {
111         ensureCapacity(count + 1);
112         buf[count] = (byte) b;
113         count += 1;
114     }
115 
116     /**
117      * Writes {@code len} bytes from the specified byte array
118      * starting at offset {@code off} to this {@code ByteArrayOutputStream}.
119      *
120      * @param   b     the data.
121      * @param   off   the start offset in the data.
122      * @param   len   the number of bytes to write.
123      * @throws  NullPointerException if {@code b} is {@code null}.
124      * @throws  IndexOutOfBoundsException if {@code off} is negative,
125      * {@code len} is negative, or {@code len} is greater than
126      * {@code b.length - off}
127      */
write(byte b[], int off, int len)128     public synchronized void write(byte b[], int off, int len) {
129         Objects.checkFromIndexSize(off, len, b.length);
130         ensureCapacity(count + len);
131         System.arraycopy(b, off, buf, count, len);
132         count += len;
133     }
134 
135     /**
136      * Writes the complete contents of the specified byte array
137      * to this {@code ByteArrayOutputStream}.
138      *
139      * @apiNote
140      * This method is equivalent to {@link #write(byte[],int,int)
141      * write(b, 0, b.length)}.
142      *
143      * @param   b     the data.
144      * @throws  NullPointerException if {@code b} is {@code null}.
145      * @since   11
146      */
writeBytes(byte b[])147     public void writeBytes(byte b[]) {
148         write(b, 0, b.length);
149     }
150 
151     /**
152      * Writes the complete contents of this {@code ByteArrayOutputStream} to
153      * the specified output stream argument, as if by calling the output
154      * stream's write method using {@code out.write(buf, 0, count)}.
155      *
156      * @param   out   the output stream to which to write the data.
157      * @throws  NullPointerException if {@code out} is {@code null}.
158      * @throws  IOException if an I/O error occurs.
159      */
writeTo(OutputStream out)160     public synchronized void writeTo(OutputStream out) throws IOException {
161         out.write(buf, 0, count);
162     }
163 
164     /**
165      * Resets the {@code count} field of this {@code ByteArrayOutputStream}
166      * to zero, so that all currently accumulated output in the
167      * output stream is discarded. The output stream can be used again,
168      * reusing the already allocated buffer space.
169      *
170      * @see     java.io.ByteArrayInputStream#count
171      */
reset()172     public synchronized void reset() {
173         count = 0;
174     }
175 
176     /**
177      * Creates a newly allocated byte array. Its size is the current
178      * size of this output stream and the valid contents of the buffer
179      * have been copied into it.
180      *
181      * @return  the current contents of this output stream, as a byte array.
182      * @see     java.io.ByteArrayOutputStream#size()
183      */
toByteArray()184     public synchronized byte[] toByteArray() {
185         return Arrays.copyOf(buf, count);
186     }
187 
188     /**
189      * Returns the current size of the buffer.
190      *
191      * @return  the value of the {@code count} field, which is the number
192      *          of valid bytes in this output stream.
193      * @see     java.io.ByteArrayOutputStream#count
194      */
size()195     public synchronized int size() {
196         return count;
197     }
198 
199     /**
200      * Converts the buffer's contents into a string decoding bytes using the
201      * platform's default character set. The length of the new {@code String}
202      * is a function of the character set, and hence may not be equal to the
203      * size of the buffer.
204      *
205      * <p> This method always replaces malformed-input and unmappable-character
206      * sequences with the default replacement string for the platform's
207      * default character set. The {@linkplain java.nio.charset.CharsetDecoder}
208      * class should be used when more control over the decoding process is
209      * required.
210      *
211      * @return String decoded from the buffer's contents.
212      * @since  1.1
213      */
toString()214     public synchronized String toString() {
215         return new String(buf, 0, count);
216     }
217 
218     /**
219      * Converts the buffer's contents into a string by decoding the bytes using
220      * the named {@link java.nio.charset.Charset charset}.
221      *
222      * <p> This method is equivalent to {@code #toString(charset)} that takes a
223      * {@link java.nio.charset.Charset charset}.
224      *
225      * <p> An invocation of this method of the form
226      *
227      * <pre> {@code
228      *      ByteArrayOutputStream b = ...
229      *      b.toString("UTF-8")
230      *      }
231      * </pre>
232      *
233      * behaves in exactly the same way as the expression
234      *
235      * <pre> {@code
236      *      ByteArrayOutputStream b = ...
237      *      b.toString(StandardCharsets.UTF_8)
238      *      }
239      * </pre>
240      *
241      *
242      * @param  charsetName  the name of a supported
243      *         {@link java.nio.charset.Charset charset}
244      * @return String decoded from the buffer's contents.
245      * @throws UnsupportedEncodingException
246      *         If the named charset is not supported
247      * @since  1.1
248      */
toString(String charsetName)249     public synchronized String toString(String charsetName)
250         throws UnsupportedEncodingException
251     {
252         return new String(buf, 0, count, charsetName);
253     }
254 
255     /**
256      * Converts the buffer's contents into a string by decoding the bytes using
257      * the specified {@link java.nio.charset.Charset charset}. The length of the new
258      * {@code String} is a function of the charset, and hence may not be equal
259      * to the length of the byte array.
260      *
261      * <p> This method always replaces malformed-input and unmappable-character
262      * sequences with the charset's default replacement string. The {@link
263      * java.nio.charset.CharsetDecoder} class should be used when more control
264      * over the decoding process is required.
265      *
266      * @param      charset  the {@linkplain java.nio.charset.Charset charset}
267      *             to be used to decode the {@code bytes}
268      * @return     String decoded from the buffer's contents.
269      * @since      10
270      */
toString(Charset charset)271     public synchronized String toString(Charset charset) {
272         return new String(buf, 0, count, charset);
273     }
274 
275     /**
276      * Creates a newly allocated string. Its size is the current size of
277      * the output stream and the valid contents of the buffer have been
278      * copied into it. Each character <i>c</i> in the resulting string is
279      * constructed from the corresponding element <i>b</i> in the byte
280      * array such that:
281      * <blockquote><pre>{@code
282      *     c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))
283      * }</pre></blockquote>
284      *
285      * @deprecated This method does not properly convert bytes into characters.
286      * As of JDK&nbsp;1.1, the preferred way to do this is via the
287      * {@link #toString(String charsetName)} or {@link #toString(Charset charset)}
288      * method, which takes an encoding-name or charset argument,
289      * or the {@code toString()} method, which uses the platform's default
290      * character encoding.
291      *
292      * @param      hibyte    the high byte of each resulting Unicode character.
293      * @return     the current contents of the output stream, as a string.
294      * @see        java.io.ByteArrayOutputStream#size()
295      * @see        java.io.ByteArrayOutputStream#toString(String)
296      * @see        java.io.ByteArrayOutputStream#toString()
297      */
298     @Deprecated
toString(int hibyte)299     public synchronized String toString(int hibyte) {
300         return new String(buf, hibyte, 0, count);
301     }
302 
303     /**
304      * Closing a {@code ByteArrayOutputStream} has no effect. The methods in
305      * this class can be called after the stream has been closed without
306      * generating an {@code IOException}.
307      */
close()308     public void close() throws IOException {
309     }
310 
311 }
312