| /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under |
| * the terms of the Common Public License v1.0 which accompanies this distribution, |
| * and is available at http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * $Id: ByteArrayOStream.java,v 1.1.1.1 2004/05/09 16:57:52 vlad_r Exp $ |
| */ |
| package com.vladium.util; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| |
| import com.vladium.util.asserts.$assert; |
| |
| // ---------------------------------------------------------------------------- |
| /** |
| * An unsynchronized version of java.io.ByteArrayOutputStream that can expose |
| * the underlying byte array without a defensive clone and can also be converted |
| * to a {@link ByteArrayIStream} without intermediate array copies.<p> |
| * |
| * All argument validation is disabled in release mode.<p> |
| * |
| * NOTE: copy-on-write not supported |
| * |
| * @author (C) 2001, Vlad Roubtsov |
| */ |
| public |
| final class ByteArrayOStream extends OutputStream |
| { |
| // public: ................................................................ |
| |
| /** |
| * Callee takes ownership of 'buf'. |
| */ |
| public ByteArrayOStream (final int initialCapacity) |
| { |
| if ($assert.ENABLED) |
| $assert.ASSERT (initialCapacity >= 0, "negative initial capacity: " + initialCapacity); |
| |
| m_buf = new byte [initialCapacity]; |
| } |
| |
| public final ByteArrayIStream toByteIStream () |
| { |
| return new ByteArrayIStream (m_buf, m_pos); |
| } |
| |
| public final void write2 (final int b1, final int b2) |
| { |
| final int pos = m_pos; |
| final int capacity = pos + 2; |
| byte [] mbuf = m_buf; |
| final int mbuflen = mbuf.length; |
| |
| if (mbuflen < capacity) |
| { |
| final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; |
| |
| if (pos < NATIVE_COPY_THRESHOLD) |
| for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; |
| else |
| System.arraycopy (mbuf, 0, newbuf, 0, pos); |
| |
| m_buf = mbuf = newbuf; |
| } |
| |
| mbuf [pos] = (byte) b1; |
| mbuf [pos + 1] = (byte) b2; |
| m_pos = capacity; |
| } |
| |
| public final void write3 (final int b1, final int b2, final int b3) |
| { |
| final int pos = m_pos; |
| final int capacity = pos + 3; |
| byte [] mbuf = m_buf; |
| final int mbuflen = mbuf.length; |
| |
| if (mbuflen < capacity) |
| { |
| final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; |
| |
| if (pos < NATIVE_COPY_THRESHOLD) |
| for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; |
| else |
| System.arraycopy (mbuf, 0, newbuf, 0, pos); |
| |
| m_buf = mbuf = newbuf; |
| } |
| |
| mbuf [pos] = (byte) b1; |
| mbuf [pos + 1] = (byte) b2; |
| mbuf [pos + 2] = (byte) b3; |
| m_pos = capacity; |
| } |
| |
| public final void write4 (final int b1, final int b2, final int b3, final int b4) |
| { |
| final int pos = m_pos; |
| final int capacity = pos + 4; |
| byte [] mbuf = m_buf; |
| final int mbuflen = mbuf.length; |
| |
| if (mbuflen < capacity) |
| { |
| final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; |
| |
| if (pos < NATIVE_COPY_THRESHOLD) |
| for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; |
| else |
| System.arraycopy (mbuf, 0, newbuf, 0, pos); |
| |
| m_buf = mbuf = newbuf; |
| } |
| |
| mbuf [pos] = (byte) b1; |
| mbuf [pos + 1] = (byte) b2; |
| mbuf [pos + 2] = (byte) b3; |
| mbuf [pos + 3] = (byte) b4; |
| m_pos = capacity; |
| } |
| |
| public final void writeTo (final OutputStream out) |
| throws IOException |
| { |
| out.write (m_buf, 0, m_pos); |
| } |
| |
| // public final void readFully (final InputStream in) |
| // throws IOException |
| // { |
| // while (true) |
| // { |
| // int chunk = in.available (); |
| // |
| // System.out.println ("available = " + chunk); |
| // |
| // // TODO: this case is handled poorly (on EOF) |
| // if (chunk == 0) chunk = READ_CHUNK_SIZE; |
| // |
| // // read at least 'available' bytes: extend the capacity as needed |
| // |
| // int free = m_buf.length - m_pos; |
| // |
| // final int read; |
| // if (free > chunk) |
| // { |
| // // try reading more than 'chunk' anyway: |
| // read = in.read (m_buf, m_pos, free); |
| // } |
| // else |
| // { |
| // // extend the capacity to match 'chunk': |
| // { |
| // System.out.println ("reallocation"); |
| // final byte [] newbuf = new byte [m_pos + chunk]; |
| // |
| // if (m_pos < NATIVE_COPY_THRESHOLD) |
| // for (int i = 0; i < m_pos; ++ i) newbuf [i] = m_buf [i]; |
| // else |
| // System.arraycopy (m_buf, 0, newbuf, 0, m_pos); |
| // |
| // m_buf = newbuf; |
| // } |
| // |
| // read = in.read (m_buf, m_pos, chunk); |
| // } |
| // |
| // if (read < 0) |
| // break; |
| // else |
| // m_pos += read; |
| // } |
| // } |
| |
| // public final void addCapacity (final int extraCapacity) |
| // { |
| // final int pos = m_pos; |
| // final int capacity = pos + extraCapacity; |
| // byte [] mbuf = m_buf; |
| // final int mbuflen = mbuf.length; |
| // |
| // if (mbuflen < capacity) |
| // { |
| // final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; |
| // |
| // if (pos < NATIVE_COPY_THRESHOLD) |
| // for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; |
| // else |
| // System.arraycopy (mbuf, 0, newbuf, 0, pos); |
| // |
| // m_buf = newbuf; |
| // } |
| // } |
| |
| public final byte [] getByteArray () |
| { |
| return m_buf; |
| } |
| |
| /** |
| * |
| * @return [result.length = size()] |
| */ |
| public final byte [] copyByteArray () |
| { |
| final int pos = m_pos; |
| |
| final byte [] result = new byte [pos]; |
| final byte [] mbuf = m_buf; |
| |
| if (pos < NATIVE_COPY_THRESHOLD) |
| for (int i = 0; i < pos; ++ i) result [i] = mbuf [i]; |
| else |
| System.arraycopy (mbuf, 0, result, 0, pos); |
| |
| return result; |
| } |
| |
| public final int size () |
| { |
| return m_pos; |
| } |
| |
| public final int capacity () |
| { |
| return m_buf.length; |
| } |
| |
| /** |
| * Does not reduce the current capacity. |
| */ |
| public final void reset () |
| { |
| m_pos = 0; |
| } |
| |
| // OutputStream: |
| |
| public final void write (final int b) |
| { |
| final int pos = m_pos; |
| final int capacity = pos + 1; |
| byte [] mbuf = m_buf; |
| final int mbuflen = mbuf.length; |
| |
| if (mbuflen < capacity) |
| { |
| final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; |
| |
| if (pos < NATIVE_COPY_THRESHOLD) |
| for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; |
| else |
| System.arraycopy (mbuf, 0, newbuf, 0, pos); |
| |
| m_buf = mbuf = newbuf; |
| } |
| |
| mbuf [pos] = (byte) b; |
| m_pos = capacity; |
| } |
| |
| |
| public final void write (final byte [] buf, final int offset, final int length) |
| { |
| if ($assert.ENABLED) |
| $assert.ASSERT ((offset >= 0) && (offset <= buf.length) && |
| (length >= 0) && ((offset + length) <= buf.length), |
| "invalid input (" + buf.length + ", " + offset + ", " + length + ")"); |
| |
| final int pos = m_pos; |
| final int capacity = pos + length; |
| byte [] mbuf = m_buf; |
| final int mbuflen = mbuf.length; |
| |
| if (mbuflen < capacity) |
| { |
| final byte [] newbuf = new byte [Math.max (mbuflen << 1, capacity)]; |
| |
| if (pos < NATIVE_COPY_THRESHOLD) |
| for (int i = 0; i < pos; ++ i) newbuf [i] = mbuf [i]; |
| else |
| System.arraycopy (mbuf, 0, newbuf, 0, pos); |
| |
| m_buf = mbuf = newbuf; |
| } |
| |
| if (length < NATIVE_COPY_THRESHOLD) |
| for (int i = 0; i < length; ++ i) mbuf [pos + i] = buf [offset + i]; |
| else |
| System.arraycopy (buf, offset, mbuf, pos, length); |
| |
| m_pos = capacity; |
| } |
| |
| |
| /** |
| * Equivalent to {@link #reset()}. |
| */ |
| public final void close () |
| { |
| reset (); |
| } |
| |
| // protected: ............................................................. |
| |
| // package: ............................................................... |
| |
| // private: ............................................................... |
| |
| |
| private byte [] m_buf; |
| private int m_pos; |
| |
| // private static final int READ_CHUNK_SIZE = 16 * 1024; |
| private static final int NATIVE_COPY_THRESHOLD = 9; |
| |
| } // end of class |
| // ---------------------------------------------------------------------------- |