package org.bouncycastle.util.io; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; /** * An output stream that buffers data to be feed into an encapsulated output stream. * <p> * The stream zeroes out the internal buffer on each flush. * </p> */ public class BufferingOutputStream extends OutputStream { private final OutputStream other; private final byte[] buf; private int bufOff; /** * Create a buffering stream with the default buffer size (4096). * * @param other output stream to be wrapped. */ public BufferingOutputStream(OutputStream other) { this.other = other; this.buf = new byte[4096]; } /** * Create a buffering stream with a specified buffer size. * * @param other output stream to be wrapped. * @param bufferSize size in bytes for internal buffer. */ public BufferingOutputStream(OutputStream other, int bufferSize) { this.other = other; this.buf = new byte[bufferSize]; } public void write(byte[] bytes, int offset, int len) throws IOException { if (len < buf.length - bufOff) { System.arraycopy(bytes, offset, buf, bufOff, len); bufOff += len; } else { int gap = buf.length - bufOff; System.arraycopy(bytes, offset, buf, bufOff, gap); bufOff += gap; flush(); offset += gap; len -= gap; while (len >= buf.length) { other.write(bytes, offset, buf.length); offset += buf.length; len -= buf.length; } if (len > 0) { System.arraycopy(bytes, offset, buf, bufOff, len); bufOff += len; } } } public void write(int b) throws IOException { buf[bufOff++] = (byte)b; if (bufOff == buf.length) { flush(); } } /** * Flush the internal buffer to the encapsulated output stream. Zero the buffer contents when done. * * @throws IOException on error. */ public void flush() throws IOException { other.write(buf, 0, bufOff); bufOff = 0; Arrays.fill(buf, (byte)0); } public void close() throws IOException { flush(); other.close(); } }