Java tutorial
// ======================================================================== // $Id: ByteBufferOutputStream.java,v 1.18 2006/10/08 14:13:19 gregwilkins Exp $ // Copyright 2001-2004 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ======================================================================== package net.lightbody.bmp.proxy.jetty.util; import net.lightbody.bmp.proxy.jetty.log.LogFactory; import org.apache.commons.logging.Log; import java.io.IOException; import java.io.OutputStream; /* ------------------------------------------------------------ */ /** ByteBuffer OutputStream. * This stream is similar to the java.io.ByteArrayOutputStream, * except that it maintains a reserve of bytes at the start of the * buffer and allows efficient prepending of data. * * @version $Revision: 1.18 $ * @author Greg Wilkins (gregw) */ public class ByteBufferOutputStream extends OutputStream { private static Log log = LogFactory.getLog(ByteBufferOutputStream.class); protected byte[] _buf; /** The start of data capacity in the buffer */ private int _start; /** The end of data capacity in the buffer */ private int _end; /** The last byte of data written to the buffer * _start <= _pos <= _end */ private int _pos; private int _preReserve; private int _postReserve; private boolean _resized; private boolean _fixed; /* ------------------------------------------------------------ */ /** Constructor. */ public ByteBufferOutputStream() { this(4096, 0, 0); } /* ------------------------------------------------------------ */ /** Constructor. * @param capacity Buffer capacity */ public ByteBufferOutputStream(int capacity) { this(capacity, 0, 0); } /* ------------------------------------------------------------ */ /** Constructor. * @param capacity Buffer capacity. * @param preReserve The reserve of byte for prepending */ public ByteBufferOutputStream(int capacity, int preReserve) { this(capacity, preReserve, 0); } /* ------------------------------------------------------------ */ /** Constructor. * @param bufferSize The size of the buffer == capacity+preReserve+postReserve * @param preReserve The reserve of byte for prepending * @param postReserve The reserve of byte for appending */ public ByteBufferOutputStream(int bufferSize, int preReserve, int postReserve) { _buf = ByteArrayPool.getByteArray(bufferSize); _end = _buf.length - postReserve; _preReserve = preReserve; _start = preReserve; _pos = preReserve; _postReserve = postReserve; } /* ------------------------------------------------------------ */ /** * @return True if the buffer cannot be expanded */ public boolean isFixed() { return _fixed; } /* ------------------------------------------------------------ */ /** * @param fixed True if the buffer cannot be expanded */ public void setFixed(boolean fixed) { _fixed = fixed; } /* ------------------------------------------------------------ */ /** * @return The size of valid data in the buffer. */ public int size() { return _pos - _start; } /* ------------------------------------------------------------ */ /** * @return The size of the buffer. */ public int bufferSize() { return _buf.length; } /* ------------------------------------------------------------ */ /** * @return The capacity of the buffer excluding pre and post reserves. */ public int capacity() { return _end - _start; } /* ------------------------------------------------------------ */ /** * @return The available capacity of the buffer excluding pre and post * reserves and data already written. */ public int spareCapacity() { return _end - _pos; } /* ------------------------------------------------------------ */ /** * @return The current pre reserve. */ public int preReserve() { return _start; } /* ------------------------------------------------------------ */ /** * @return The current post reserve. */ public int postReserve() { return _buf.length - _end; } /* ------------------------------------------------------------ */ public void writeTo(OutputStream out) throws IOException { out.write(_buf, _start, _pos - _start); } /* ------------------------------------------------------------ */ public void write(int b) throws IOException { ensureSpareCapacity(1); _buf[_pos++] = (byte) b; } /* ------------------------------------------------------------ */ public void write(byte[] b) throws IOException { ensureSpareCapacity(b.length); System.arraycopy(b, 0, _buf, _pos, b.length); _pos += b.length; } /* ------------------------------------------------------------ */ public void write(byte[] b, int offset, int length) throws IOException { ensureSpareCapacity(length); System.arraycopy(b, offset, _buf, _pos, length); _pos += length; } /* ------------------------------------------------------------ */ /** Write byte to start of the buffer. * @param b */ public void prewrite(int b) { ensureReserve(1); _buf[--_start] = (byte) b; } /* ------------------------------------------------------------ */ /** Write byte array to start of the buffer. * @param b */ public void prewrite(byte[] b) { ensureReserve(b.length); System.arraycopy(b, 0, _buf, _start - b.length, b.length); _start -= b.length; } /* ------------------------------------------------------------ */ /** Write byte range to start of the buffer. * @param b * @param offset * @param length */ public void prewrite(byte[] b, int offset, int length) { ensureReserve(length); System.arraycopy(b, offset, _buf, _start - length, length); _start -= length; } /* ------------------------------------------------------------ */ /** Write bytes into the postreserve. * The capacity is not checked. * @param b * @param offset * @param length * @exception IOException */ public void postwrite(byte b) throws IOException { _buf[_pos++] = b; } /* ------------------------------------------------------------ */ /** Write bytes into the postreserve. * The capacity is not checked. * @param b * @param offset * @param length * @exception IOException */ public void postwrite(byte[] b, int offset, int length) throws IOException { System.arraycopy(b, offset, _buf, _pos, length); _pos += length; } /* ------------------------------------------------------------ */ public void flush() throws IOException { } /* ------------------------------------------------------------ */ public void resetStream() { _pos = _preReserve; _start = _preReserve; } /* ------------------------------------------------------------ */ public void reset(int reserve) { _preReserve = reserve; _pos = _preReserve; _start = _preReserve; } /* ------------------------------------------------------------ */ public void close() throws IOException { flush(); } /* ------------------------------------------------------------ */ public void destroy() { if (!_resized) ByteArrayPool.returnByteArray(_buf); _buf = null; } /* ------------------------------------------------------------ */ public void ensureReserve(int n) { if (n > _start) { if (log.isDebugEnabled()) log.debug("Reserve: " + n + ">" + _start); if ((_pos + n) < _end) { if (log.isDebugEnabled()) log.debug("Shift reserve: " + _pos + "+" + n + "<" + _end); System.arraycopy(_buf, _start, _buf, n, _pos - _start); _pos = _pos + n - _start; _start = n; } else { if (log.isDebugEnabled()) log.debug("New reserve: " + _pos + "+" + n + ">=" + _end); byte[] buf = new byte[_buf.length + n - _start]; System.arraycopy(_buf, _start, buf, n, _pos - _start); _pos = n + _pos - _start; _start = n; _buf = buf; _end = _buf.length - _postReserve; } } } /* ------------------------------------------------------------ */ public void ensureSize(int bufSize) throws IOException { ensureSize(bufSize, _preReserve, _postReserve); } /* ------------------------------------------------------------ */ public void ensureSize(int bufSize, int pre, int post) throws IOException { // Do we have space? if (bufSize > _buf.length || pre > _preReserve || post > _postReserve) { // Make a bigger buffer if we are allowed. if (_fixed) throw new IllegalStateException("Fixed"); byte[] old = _buf; _buf = ByteArrayPool.getByteArray(bufSize); if (_pos > _start) System.arraycopy(old, _start, _buf, pre, _pos - _start); if (!_resized) ByteArrayPool.returnByteArray(old); _end = _buf.length - post; _preReserve = pre; _start = pre; _pos = pre; _postReserve = post; } } /* ------------------------------------------------------------ */ public void ensureSpareCapacity(int n) throws IOException { // Do we have space? if (n > spareCapacity()) { // No, then try flushing what we do have if (_pos > _start) flush(); ensureCapacity(n); } } /* ------------------------------------------------------------ */ public void ensureCapacity(int n) throws IOException { // Do we have space? if (n > capacity()) { // Make a bigger buffer if we are allowed. if (_fixed) throw new IllegalStateException("Fixed"); int new_size = ((n + _preReserve + _postReserve + 4095) / 4096) * 4096; byte[] old = _buf; _buf = new byte[new_size]; if (_pos > _start) System.arraycopy(old, _start, _buf, _start, _pos - _start); if (!_resized) ByteArrayPool.returnByteArray(old); _end = _buf.length - _postReserve; _resized = true; } } }