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