ByteArrayOutputStream.java revision b1396870f92135aa140bd2b86221768dea5bc11d
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.io;
19
20/**
21 * A specialized {@link OutputStream} for class for writing content to an
22 * (internal) byte array. As bytes are written to this stream, the byte array
23 * may be expanded to hold more bytes. When the writing is considered to be
24 * finished, a copy of the byte array can be requested from the class.
25 *
26 * @see ByteArrayInputStream
27 */
28public class ByteArrayOutputStream extends OutputStream {
29    /**
30     * The byte array containing the bytes written.
31     */
32    protected byte[] buf;
33
34    /**
35     * The number of bytes written.
36     */
37    protected int count;
38
39    /**
40     * Constructs a new ByteArrayOutputStream with a default size of 32 bytes.
41     * If more than 32 bytes are written to this instance, the underlying byte
42     * array will expand.
43     */
44    public ByteArrayOutputStream() {
45        super();
46        buf = new byte[32];
47    }
48
49    /**
50     * Constructs a new {@code ByteArrayOutputStream} with a default size of
51     * {@code size} bytes. If more than {@code size} bytes are written to this
52     * instance, the underlying byte array will expand.
53     *
54     * @param size
55     *            initial size for the underlying byte array, must be
56     *            non-negative.
57     * @throws IllegalArgumentException
58     *             if {@code size} < 0.
59     */
60    public ByteArrayOutputStream(int size) {
61        super();
62        if (size >= 0) {
63            buf = new byte[size];
64        } else {
65            throw new IllegalArgumentException("size < 0");
66        }
67    }
68
69    /**
70     * Closes this stream. This releases system resources used for this stream.
71     *
72     * @throws IOException
73     *             if an error occurs while attempting to close this stream.
74     */
75    @Override
76    public void close() throws IOException {
77        /**
78         * Although the spec claims "A closed stream cannot perform output
79         * operations and cannot be reopened.", this implementation must do
80         * nothing.
81         */
82        super.close();
83    }
84
85    private void expand(int i) {
86        /* Can the buffer handle @i more bytes, if not expand it */
87        if (count + i <= buf.length) {
88            return;
89        }
90
91        byte[] newbuf = new byte[(count + i) * 2];
92        System.arraycopy(buf, 0, newbuf, 0, count);
93        buf = newbuf;
94    }
95
96    /**
97     * Resets this stream to the beginning of the underlying byte array. All
98     * subsequent writes will overwrite any bytes previously stored in this
99     * stream.
100     */
101    public synchronized void reset() {
102        count = 0;
103    }
104
105    /**
106     * Returns the total number of bytes written to this stream so far.
107     *
108     * @return the number of bytes written to this stream.
109     */
110    public int size() {
111        return count;
112    }
113
114    /**
115     * Returns the contents of this ByteArrayOutputStream as a byte array. Any
116     * changes made to the receiver after returning will not be reflected in the
117     * byte array returned to the caller.
118     *
119     * @return this stream's current contents as a byte array.
120     */
121    public synchronized byte[] toByteArray() {
122        byte[] newArray = new byte[count];
123        System.arraycopy(buf, 0, newArray, 0, count);
124        return newArray;
125    }
126
127    /**
128     * Returns the contents of this ByteArrayOutputStream as a string. Any
129     * changes made to the receiver after returning will not be reflected in the
130     * string returned to the caller.
131     *
132     * @return this stream's current contents as a string.
133     */
134
135    @Override
136    public String toString() {
137        return new String(buf, 0, count);
138    }
139
140    /**
141     * Returns the contents of this ByteArrayOutputStream as a string. Each byte
142     * {@code b} in this stream is converted to a character {@code c} using the
143     * following function:
144     * {@code c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))}. This method is
145     * deprecated and either {@link #toString()} or {@link #toString(String)}
146     * should be used.
147     *
148     * @param hibyte
149     *            the high byte of each resulting Unicode character.
150     * @return this stream's current contents as a string with the high byte set
151     *         to {@code hibyte}.
152     * @deprecated Use {@link #toString()}.
153     */
154    @Deprecated
155    public String toString(int hibyte) {
156        char[] newBuf = new char[size()];
157        for (int i = 0; i < newBuf.length; i++) {
158            newBuf[i] = (char) (((hibyte & 0xff) << 8) | (buf[i] & 0xff));
159        }
160        return new String(newBuf);
161    }
162
163    /**
164     * Returns the contents of this ByteArrayOutputStream as a string converted
165     * according to the encoding declared in {@code enc}.
166     *
167     * @param enc
168     *            a string representing the encoding to use when translating
169     *            this stream to a string.
170     * @return this stream's current contents as an encoded string.
171     * @throws UnsupportedEncodingException
172     *             if the provided encoding is not supported.
173     */
174    public String toString(String enc) throws UnsupportedEncodingException {
175        return new String(buf, 0, count, enc);
176    }
177
178    /**
179     * Writes {@code count} bytes from the byte array {@code buffer} starting at
180     * offset {@code index} to this stream.
181     *
182     * @param buffer
183     *            the buffer to be written.
184     * @param offset
185     *            the initial position in {@code buffer} to retrieve bytes.
186     * @param len
187     *            the number of bytes of {@code buffer} to write.
188     * @throws NullPointerException
189     *             if {@code buffer} is {@code null}.
190     * @throws IndexOutOfBoundsException
191     *             if {@code offset < 0} or {@code len < 0}, or if
192     *             {@code offset + len} is greater than the length of
193     *             {@code buffer}.
194     */
195    @Override
196    public synchronized void write(byte[] buffer, int offset, int len) {
197        // avoid int overflow
198        // BEGIN android-changed
199        // Exception priorities (in case of multiple errors) differ from
200        // RI, but are spec-compliant.
201        // removed redundant check, made implicit null check explicit,
202        // used (offset | len) < 0 instead of (offset < 0) || (len < 0)
203        // to safe one operation
204        if (buffer == null) {
205            throw new NullPointerException("buffer == null");
206        }
207        if ((offset | len) < 0 || len > buffer.length - offset) {
208            throw new IndexOutOfBoundsException();
209        }
210        // END android-changed
211        if (len == 0) {
212            return;
213        }
214
215        /* Expand if necessary */
216        expand(len);
217        System.arraycopy(buffer, offset, buf, this.count, len);
218        this.count += len;
219    }
220
221    /**
222     * Writes the specified byte {@code oneByte} to the OutputStream. Only the
223     * low order byte of {@code oneByte} is written.
224     *
225     * @param oneByte
226     *            the byte to be written.
227     */
228    @Override
229    public synchronized void write(int oneByte) {
230        if (count == buf.length) {
231            expand(1);
232        }
233        buf[count++] = (byte) oneByte;
234    }
235
236    /**
237     * Takes the contents of this stream and writes it to the output stream
238     * {@code out}.
239     *
240     * @param out
241     *            an OutputStream on which to write the contents of this stream.
242     * @throws IOException
243     *             if an error occurs while writing to {@code out}.
244     */
245    public synchronized void writeTo(OutputStream out) throws IOException {
246        out.write(buf, 0, count);
247    }
248}
249