1e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru/*
2e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * Licensed to the Apache Software Foundation (ASF) under one or more
3e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * contributor license agreements.  See the NOTICE file distributed with
4e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * this work for additional information regarding copyright ownership.
5e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * The ASF licenses this file to You under the Apache License, Version 2.0
6e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * (the "License"); you may not use this file except in compliance with
7e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * the License.  You may obtain a copy of the License at
8e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru *
9e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru *      http://www.apache.org/licenses/LICENSE-2.0
10e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru *
11e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software
12e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS,
13e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * See the License for the specific language governing permissions and
15e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * limitations under the License.
16e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru */
17e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Querupackage org.apache.commons.io.output;
18e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
19e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queruimport java.io.IOException;
20e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queruimport java.io.InputStream;
21e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queruimport java.io.OutputStream;
22e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queruimport java.io.UnsupportedEncodingException;
23e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queruimport java.util.ArrayList;
24e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queruimport java.util.List;
25e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
26e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru/**
27e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * This class implements an output stream in which the data is
28e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * written into a byte array. The buffer automatically grows as data
29e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * is written to it.
30e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * <p>
31e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * The data can be retrieved using <code>toByteArray()</code> and
32e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * <code>toString()</code>.
33e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * <p>
34e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
35e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * this class can be called after the stream has been closed without
36e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * generating an <tt>IOException</tt>.
37e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * <p>
38e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * This is an alternative implementation of the java.io.ByteArrayOutputStream
39e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * class. The original implementation only allocates 32 bytes at the beginning.
40e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * As this class is designed for heavy duty it starts at 1024 bytes. In contrast
41e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * to the original it doesn't reallocate the whole memory block but allocates
42e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * additional buffers. This way no buffers need to be garbage collected and
43e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * the contents don't have to be copied to the new buffer. This class is
44e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * designed to behave exactly like the original. The only exception is the
45e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * deprecated toString(int) method that has been ignored.
46e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru *
47e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
48e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * @author Holger Hoffstatte
49e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru * @version $Id: ByteArrayOutputStream.java 610010 2008-01-08 14:50:59Z niallp $
50e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru */
51e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Querupublic class ByteArrayOutputStream extends OutputStream {
52e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
53e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /** A singleton empty byte array. */
54e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
55e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
56e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /** The list of buffers, which grows and never reduces. */
57e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private List<byte[]> buffers = new ArrayList<byte[]>();
58e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /** The index of the current buffer. */
59e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private int currentBufferIndex;
60e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /** The total count of bytes in all the filled buffers. */
61e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private int filledBufferSum;
62e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /** The current buffer. */
63e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private byte[] currentBuffer;
64e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /** The total count of bytes written. */
65e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private int count;
66e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
67e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
68e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Creates a new byte array output stream. The buffer capacity is
69e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * initially 1024 bytes, though its size increases if necessary.
70e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
71e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public ByteArrayOutputStream() {
72e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        this(1024);
73e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
74e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
75e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
76e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Creates a new byte array output stream, with a buffer capacity of
77e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * the specified size, in bytes.
78e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
79e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param size  the initial size
80e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @throws IllegalArgumentException if size is negative
81e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
82e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public ByteArrayOutputStream(int size) {
83e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        if (size < 0) {
84e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            throw new IllegalArgumentException(
85e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                "Negative initial size: " + size);
86e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
87e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        needNewBuffer(size);
88e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
89e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
90e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
91e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Return the appropriate <code>byte[]</code> buffer
92e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * specified by index.
93e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
94e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param index  the index of the buffer required
95e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @return the buffer
96e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
97e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private byte[] getBuffer(int index) {
98e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        return buffers.get(index);
99e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
100e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
101e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
102e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Makes a new buffer available either by allocating
103e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * a new one or re-cycling an existing one.
104e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
105e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param newcount  the size of the buffer if one is created
106e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
107e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    private void needNewBuffer(int newcount) {
108e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        if (currentBufferIndex < buffers.size() - 1) {
109e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            //Recycling old buffer
110e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            filledBufferSum += currentBuffer.length;
111e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
112e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            currentBufferIndex++;
113e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            currentBuffer = getBuffer(currentBufferIndex);
114e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        } else {
115e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            //Creating new buffer
116e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            int newBufferSize;
117e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            if (currentBuffer == null) {
118e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                newBufferSize = newcount;
119e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                filledBufferSum = 0;
120e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            } else {
121e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                newBufferSize = Math.max(
122e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                    currentBuffer.length << 1,
123e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                    newcount - filledBufferSum);
124e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                filledBufferSum += currentBuffer.length;
125e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            }
126e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
127e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            currentBufferIndex++;
128e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            currentBuffer = new byte[newBufferSize];
129e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            buffers.add(currentBuffer);
130e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
131e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
132e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
133e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
134e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Write the bytes to byte array.
135e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param b the bytes to write
136e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param off The start offset
137e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param len The number of bytes to write
138e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
139e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    @Override
140e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public void write(byte[] b, int off, int len) {
141e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        if ((off < 0)
142e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                || (off > b.length)
143e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                || (len < 0)
144e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                || ((off + len) > b.length)
145e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                || ((off + len) < 0)) {
146e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            throw new IndexOutOfBoundsException();
147e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        } else if (len == 0) {
148e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            return;
149e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
150e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        synchronized (this) {
151e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            int newcount = count + len;
152e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            int remaining = len;
153e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            int inBufferPos = count - filledBufferSum;
154e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            while (remaining > 0) {
155e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                int part = Math.min(remaining, currentBuffer.length - inBufferPos);
156e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part);
157e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                remaining -= part;
158e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                if (remaining > 0) {
159e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                    needNewBuffer(newcount);
160e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                    inBufferPos = 0;
161e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                }
162e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            }
163e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            count = newcount;
164e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
165e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
166e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
167e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
168e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Write a byte to byte array.
169e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param b the byte to write
170e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
171e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    @Override
172e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public synchronized void write(int b) {
173e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        int inBufferPos = count - filledBufferSum;
174e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        if (inBufferPos == currentBuffer.length) {
175e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            needNewBuffer(count + 1);
176e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            inBufferPos = 0;
177e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
178e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        currentBuffer[inBufferPos] = (byte) b;
179e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        count++;
180e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
181e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
182e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
183e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Writes the entire contents of the specified input stream to this
184e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * byte stream. Bytes from the input stream are read directly into the
185e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * internal buffers of this streams.
186e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
187e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param in the input stream to read from
188e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @return total number of bytes read from the input stream
189e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *         (and written to this stream)
190e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @throws IOException if an I/O error occurs while reading the input stream
191e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @since Commons IO 1.4
192e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
193e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public synchronized int write(InputStream in) throws IOException {
194e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        int readCount = 0;
195e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        int inBufferPos = count - filledBufferSum;
196e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
197e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        while (n != -1) {
198e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            readCount += n;
199e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            inBufferPos += n;
200e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            count += n;
201e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            if (inBufferPos == currentBuffer.length) {
202e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                needNewBuffer(currentBuffer.length);
203e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                inBufferPos = 0;
204e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            }
205e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
206e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
207e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        return readCount;
208e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
209e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
210e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
211e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Return the current size of the byte array.
212e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @return the current size of the byte array
213e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
214e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public synchronized int size() {
215e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        return count;
216e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
217e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
218e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
219e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
220e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * this class can be called after the stream has been closed without
221e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * generating an <tt>IOException</tt>.
222e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
223e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @throws IOException never (this method should not declare this exception
224e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * but it has to now due to backwards compatability)
225e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
226e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    @Override
227e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public void close() throws IOException {
228e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        //nop
229e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
230e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
231e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
232e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @see java.io.ByteArrayOutputStream#reset()
233e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
234e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public synchronized void reset() {
235e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        count = 0;
236e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        filledBufferSum = 0;
237e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        currentBufferIndex = 0;
238e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        currentBuffer = getBuffer(currentBufferIndex);
239e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
240e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
241e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
242e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Writes the entire contents of this byte stream to the
243e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * specified output stream.
244e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
245e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param out  the output stream to write to
246e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @throws IOException if an I/O error occurs, such as if the stream is closed
247e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @see java.io.ByteArrayOutputStream#writeTo(OutputStream)
248e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
249e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public synchronized void writeTo(OutputStream out) throws IOException {
250e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        int remaining = count;
251e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        for (int i = 0; i < buffers.size(); i++) {
252e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            byte[] buf = getBuffer(i);
253e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            int c = Math.min(buf.length, remaining);
254e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            out.write(buf, 0, c);
255e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            remaining -= c;
256e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            if (remaining == 0) {
257e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                break;
258e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            }
259e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
260e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
261e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
262e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
263e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Gets the curent contents of this byte stream as a byte array.
264e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * The result is independent of this stream.
265e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
266e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @return the current contents of this output stream, as a byte array
267e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @see java.io.ByteArrayOutputStream#toByteArray()
268e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
269e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public synchronized byte[] toByteArray() {
270e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        int remaining = count;
271e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        if (remaining == 0) {
272e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            return EMPTY_BYTE_ARRAY;
273e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
274e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        byte newbuf[] = new byte[remaining];
275e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        int pos = 0;
276e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        for (int i = 0; i < buffers.size(); i++) {
277e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            byte[] buf = getBuffer(i);
278e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            int c = Math.min(buf.length, remaining);
279e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            System.arraycopy(buf, 0, newbuf, pos, c);
280e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            pos += c;
281e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            remaining -= c;
282e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            if (remaining == 0) {
283e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru                break;
284e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru            }
285e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        }
286e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        return newbuf;
287e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
288e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
289e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
290e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Gets the curent contents of this byte stream as a string.
291e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @return the contents of the byte array as a String
292e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @see java.io.ByteArrayOutputStream#toString()
293e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
294e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    @Override
295e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public String toString() {
296e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        return new String(toByteArray());
297e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
298e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
299e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    /**
300e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * Gets the curent contents of this byte stream as a string
301e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * using the specified encoding.
302e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     *
303e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @param enc  the name of the character encoding
304e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @return the string converted from the byte array
305e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @throws UnsupportedEncodingException if the encoding is not supported
306e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     * @see java.io.ByteArrayOutputStream#toString(String)
307e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru     */
308e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    public String toString(String enc) throws UnsupportedEncodingException {
309e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru        return new String(toByteArray(), enc);
310e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru    }
311e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru
312e858128e970bdead5d5a096d9b5d941b2f5efadeJean-Baptiste Queru}
313