1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.io;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20b9cc455ed89df1a0cf4186c92b352c9649995d96Elliott Hughesimport java.util.Arrays;
21b9cc455ed89df1a0cf4186c92b352c9649995d96Elliott Hughes
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Wraps an existing {@link OutputStream} and <em>buffers</em> the output.
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Expensive interaction with the underlying input stream is minimized, since
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * most (smaller) requests can be satisfied by accessing the buffer alone. The
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * drawback is that some extra space is required to hold the buffer and that
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * copying takes place when flushing that buffer, but this is usually outweighed
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * by the performance benefits.
29f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p/>A typical application pattern for the class looks like this:<p/>
31f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <pre>
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * BufferedOutputStream buf = new BufferedOutputStream(new FileOutputStream(&quot;file.java&quot;));
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * </pre>
35f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see BufferedInputStream
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class BufferedOutputStream extends FilterOutputStream {
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The buffer containing the bytes to be written to the target stream.
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected byte[] buf;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The total number of bytes inside the byte array {@code buf}.
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected int count;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
50fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * Constructs a new {@code BufferedOutputStream}, providing {@code out} with a buffer
51fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * of 8192 bytes.
52f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
53fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @param out the {@code OutputStream} the buffer writes to.
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BufferedOutputStream(OutputStream out) {
56fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes        this(out, 8192);
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
60fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * Constructs a new {@code BufferedOutputStream}, providing {@code out} with {@code size} bytes
61fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * of buffer.
62f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
63fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @param out the {@code OutputStream} the buffer writes to.
64fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @param size the size of buffer in bytes.
65fb4616d0efbba1903b9237c0a428b59868365a69Elliott Hughes     * @throws IllegalArgumentException if {@code size <= 0}.
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public BufferedOutputStream(OutputStream out, int size) {
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(out);
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (size <= 0) {
70b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("size <= 0");
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        buf = new byte[size];
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Flushes this stream to ensure all pending data is written out to the
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * target stream. In addition, the target stream is flushed.
78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs attempting to flush this stream.
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void flush() throws IOException {
84b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        checkNotClosed();
85f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        flushInternal();
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        out.flush();
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
89b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    private void checkNotClosed() throws IOException {
90b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        if (buf == null) {
91b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IOException("BufferedOutputStream is closed");
92b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        }
93b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    }
94b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Writes {@code count} bytes from the byte array {@code buffer} starting at
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code offset} to this stream. If there is room in the buffer to hold the
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * bytes, they are copied in. If not, the buffered bytes plus the bytes in
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code buffer} are written to the target stream, the target is flushed,
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and the buffer is cleared.
101f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param buffer
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the buffer to be written.
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param offset
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the start position in {@code buffer} from where to get bytes.
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param length
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the number of bytes from {@code buffer} to write to this
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            stream.
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IndexOutOfBoundsException
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code offset < 0} or {@code length < 0}, or if
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@code offset + length} is greater than the size of
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             {@code buffer}.
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs attempting to write to this stream.
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code buffer} is {@code null}.
117f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws ArrayIndexOutOfBoundsException
118f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *             If offset or count is outside of bounds.
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
121b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes    public synchronized void write(byte[] buffer, int offset, int length) throws IOException {
122b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        checkNotClosed();
12355392539fea537abfb6581b474918f9d611fba27Jesse Wilson
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (buffer == null) {
125b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new NullPointerException("buffer == null");
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
127f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
128b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        byte[] internalBuffer = buf;
12955392539fea537abfb6581b474918f9d611fba27Jesse Wilson        if (length >= internalBuffer.length) {
130f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            flushInternal();
131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            out.write(buffer, offset, length);
132f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return;
133f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
134f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
135b9cc455ed89df1a0cf4186c92b352c9649995d96Elliott Hughes        Arrays.checkOffsetAndCount(buffer.length, offset, length);
136f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
137f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // flush the internal buffer first if we have not enough space left
1380efebd8c734d30ed798b80166290b904fa357ee0Jesse Wilson        if (length > (internalBuffer.length - count)) {
139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            flushInternal();
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
141f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
14255392539fea537abfb6581b474918f9d611fba27Jesse Wilson        System.arraycopy(buffer, offset, internalBuffer, count, length);
143f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        count += length;
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
14655392539fea537abfb6581b474918f9d611fba27Jesse Wilson    @Override public synchronized void close() throws IOException {
14755392539fea537abfb6581b474918f9d611fba27Jesse Wilson        if (buf == null) {
14855392539fea537abfb6581b474918f9d611fba27Jesse Wilson            return;
14955392539fea537abfb6581b474918f9d611fba27Jesse Wilson        }
150f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
15155392539fea537abfb6581b474918f9d611fba27Jesse Wilson        try {
15255392539fea537abfb6581b474918f9d611fba27Jesse Wilson            super.close();
15355392539fea537abfb6581b474918f9d611fba27Jesse Wilson        } finally {
15455392539fea537abfb6581b474918f9d611fba27Jesse Wilson            buf = null;
15555392539fea537abfb6581b474918f9d611fba27Jesse Wilson        }
15655392539fea537abfb6581b474918f9d611fba27Jesse Wilson    }
15755392539fea537abfb6581b474918f9d611fba27Jesse Wilson
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Writes one byte to this stream. Only the low order byte of the integer
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code oneByte} is written. If there is room in the buffer, the byte is
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * copied into the buffer and the count incremented. Otherwise, the buffer
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * plus {@code oneByte} are written to the target stream, the target is
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * flushed, and the buffer is reset.
164f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param oneByte
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the byte to be written.
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs attempting to write to this stream.
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void write(int oneByte) throws IOException {
172b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        checkNotClosed();
173b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        if (count == buf.length) {
174b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            out.write(buf, 0, count);
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            count = 0;
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
177b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes        buf[count++] = (byte) oneByte;
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
179f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
180f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    /**
181f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Flushes only internal buffer.
182f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     */
183f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private void flushInternal() throws IOException {
184f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (count > 0) {
185f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            out.write(buf, 0, count);
18655392539fea537abfb6581b474918f9d611fba27Jesse Wilson            count = 0;
187f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
188f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
190