14fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/*
24fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Licensed to the Apache Software Foundation (ASF) under one or more
34fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * contributor license agreements.  See the NOTICE file distributed with
44fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * this work for additional information regarding copyright ownership.
54fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The ASF licenses this file to You under the Apache License, Version 2.0
64fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * (the "License"); you may not use this file except in compliance with
74fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * the License.  You may obtain a copy of the License at
84fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
94fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *      http://www.apache.org/licenses/LICENSE-2.0
104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Unless required by applicable law or agreed to in writing, software
124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * distributed under the License is distributed on an "AS IS" BASIS,
134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * See the License for the specific language governing permissions and
154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * limitations under the License.
164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */
174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypackage org.apache.commons.io.output;
184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.IOException;
204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.InputStream;
214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.OutputStream;
224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.UnsupportedEncodingException;
234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.util.ArrayList;
244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.util.List;
254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/**
274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This class implements an output stream in which the data is
284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * written into a byte array. The buffer automatically grows as data
294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * is written to it.
304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The data can be retrieved using <code>toByteArray()</code> and
324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <code>toString()</code>.
334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * this class can be called after the stream has been closed without
364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * generating an <tt>IOException</tt>.
374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p>
384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This is an alternative implementation of the java.io.ByteArrayOutputStream
394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * class. The original implementation only allocates 32 bytes at the beginning.
404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * As this class is designed for heavy duty it starts at 1024 bytes. In contrast
414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * to the original it doesn't reallocate the whole memory block but allocates
424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * additional buffers. This way no buffers need to be garbage collected and
434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * the contents don't have to be copied to the new buffer. This class is
444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * designed to behave exactly like the original. The only exception is the
454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * deprecated toString(int) method that has been ignored.
464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author Holger Hoffstatte
494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @version $Id: ByteArrayOutputStream.java 610010 2008-01-08 14:50:59Z niallp $
504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */
514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypublic class ByteArrayOutputStream extends OutputStream {
524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** A singleton empty byte array. */
544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The list of buffers, which grows and never reduces. */
574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private List<byte[]> buffers = new ArrayList<byte[]>();
584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The index of the current buffer. */
594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private int currentBufferIndex;
604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The total count of bytes in all the filled buffers. */
614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private int filledBufferSum;
624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The current buffer. */
634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private byte[] currentBuffer;
644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /** The total count of bytes written. */
654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private int count;
664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Creates a new byte array output stream. The buffer capacity is
694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * initially 1024 bytes, though its size increases if necessary.
704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public ByteArrayOutputStream() {
724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        this(1024);
734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Creates a new byte array output stream, with a buffer capacity of
774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * the specified size, in bytes.
784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param size  the initial size
804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IllegalArgumentException if size is negative
814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public ByteArrayOutputStream(int size) {
834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (size < 0) {
844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw new IllegalArgumentException(
854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                "Negative initial size: " + size);
864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        needNewBuffer(size);
884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Return the appropriate <code>byte[]</code> buffer
924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * specified by index.
934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param index  the index of the buffer required
954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return the buffer
964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private byte[] getBuffer(int index) {
984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return buffers.get(index);
994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Makes a new buffer available either by allocating
1034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * a new one or re-cycling an existing one.
1044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param newcount  the size of the buffer if one is created
1064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    private void needNewBuffer(int newcount) {
1084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (currentBufferIndex < buffers.size() - 1) {
1094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            //Recycling old buffer
1104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            filledBufferSum += currentBuffer.length;
1114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            currentBufferIndex++;
1134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            currentBuffer = getBuffer(currentBufferIndex);
1144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        } else {
1154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            //Creating new buffer
1164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            int newBufferSize;
1174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (currentBuffer == null) {
1184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                newBufferSize = newcount;
1194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                filledBufferSum = 0;
1204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            } else {
1214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                newBufferSize = Math.max(
1224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    currentBuffer.length << 1,
1234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    newcount - filledBufferSum);
1244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                filledBufferSum += currentBuffer.length;
1254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
1264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            currentBufferIndex++;
1284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            currentBuffer = new byte[newBufferSize];
1294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            buffers.add(currentBuffer);
1304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Write the bytes to byte array.
1354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param b the bytes to write
1364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param off The start offset
1374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param len The number of bytes to write
1384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    @Override
1404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void write(byte[] b, int off, int len) {
1414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if ((off < 0)
1424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                || (off > b.length)
1434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                || (len < 0)
1444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                || ((off + len) > b.length)
1454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                || ((off + len) < 0)) {
1464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            throw new IndexOutOfBoundsException();
1474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        } else if (len == 0) {
1484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            return;
1494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        synchronized (this) {
1514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            int newcount = count + len;
1524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            int remaining = len;
1534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            int inBufferPos = count - filledBufferSum;
1544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            while (remaining > 0) {
1554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                int part = Math.min(remaining, currentBuffer.length - inBufferPos);
1564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part);
1574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                remaining -= part;
1584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                if (remaining > 0) {
1594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    needNewBuffer(newcount);
1604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                    inBufferPos = 0;
1614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                }
1624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
1634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            count = newcount;
1644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Write a byte to byte array.
1694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param b the byte to write
1704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    @Override
1724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public synchronized void write(int b) {
1734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        int inBufferPos = count - filledBufferSum;
1744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (inBufferPos == currentBuffer.length) {
1754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            needNewBuffer(count + 1);
1764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            inBufferPos = 0;
1774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
1784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        currentBuffer[inBufferPos] = (byte) b;
1794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        count++;
1804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
1814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
1834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Writes the entire contents of the specified input stream to this
1844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * byte stream. Bytes from the input stream are read directly into the
1854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * internal buffers of this streams.
1864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
1874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param in the input stream to read from
1884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return total number of bytes read from the input stream
1894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *         (and written to this stream)
1904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs while reading the input stream
1914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @since Commons IO 1.4
1924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
1934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public synchronized int write(InputStream in) throws IOException {
1944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        int readCount = 0;
1954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        int inBufferPos = count - filledBufferSum;
1964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
1974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        while (n != -1) {
1984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            readCount += n;
1994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            inBufferPos += n;
2004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            count += n;
2014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (inBufferPos == currentBuffer.length) {
2024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                needNewBuffer(currentBuffer.length);
2034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                inBufferPos = 0;
2044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
2054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos);
2064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return readCount;
2084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Return the current size of the byte array.
2124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return the current size of the byte array
2134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public synchronized int size() {
2154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return count;
2164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
2204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * this class can be called after the stream has been closed without
2214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * generating an <tt>IOException</tt>.
2224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException never (this method should not declare this exception
2244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * but it has to now due to backwards compatability)
2254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    @Override
2274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public void close() throws IOException {
2284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        //nop
2294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @see java.io.ByteArrayOutputStream#reset()
2334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public synchronized void reset() {
2354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        count = 0;
2364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        filledBufferSum = 0;
2374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        currentBufferIndex = 0;
2384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        currentBuffer = getBuffer(currentBufferIndex);
2394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Writes the entire contents of this byte stream to the
2434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * specified output stream.
2444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param out  the output stream to write to
2464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws IOException if an I/O error occurs, such as if the stream is closed
2474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @see java.io.ByteArrayOutputStream#writeTo(OutputStream)
2484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public synchronized void writeTo(OutputStream out) throws IOException {
2504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        int remaining = count;
2514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        for (int i = 0; i < buffers.size(); i++) {
2524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            byte[] buf = getBuffer(i);
2534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            int c = Math.min(buf.length, remaining);
2544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            out.write(buf, 0, c);
2554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            remaining -= c;
2564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (remaining == 0) {
2574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                break;
2584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
2594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Gets the curent contents of this byte stream as a byte array.
2644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * The result is independent of this stream.
2654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
2664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return the current contents of this output stream, as a byte array
2674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @see java.io.ByteArrayOutputStream#toByteArray()
2684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public synchronized byte[] toByteArray() {
2704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        int remaining = count;
2714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        if (remaining == 0) {
2724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            return EMPTY_BYTE_ARRAY;
2734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        byte newbuf[] = new byte[remaining];
2754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        int pos = 0;
2764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        for (int i = 0; i < buffers.size(); i++) {
2774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            byte[] buf = getBuffer(i);
2784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            int c = Math.min(buf.length, remaining);
2794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            System.arraycopy(buf, 0, newbuf, pos, c);
2804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            pos += c;
2814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            remaining -= c;
2824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            if (remaining == 0) {
2834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                break;
2844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            }
2854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        }
2864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return newbuf;
2874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
2904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Gets the curent contents of this byte stream as a string.
2914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return the contents of the byte array as a String
2924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @see java.io.ByteArrayOutputStream#toString()
2934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
2944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    @Override
2954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public String toString() {
2964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return new String(toByteArray());
2974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
2984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    /**
3004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * Gets the curent contents of this byte stream as a string
3014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * using the specified encoding.
3024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     *
3034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @param enc  the name of the character encoding
3044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @return the string converted from the byte array
3054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @throws UnsupportedEncodingException if the encoding is not supported
3064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     * @see java.io.ByteArrayOutputStream#toString(String)
3074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy     */
3084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    public String toString(String enc) throws UnsupportedEncodingException {
3094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy        return new String(toByteArray(), enc);
3104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy    }
3114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
3124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy}
313