/* 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 $ 
 */ 
 
import java.io.IOException; 
import java.io.OutputStream; 
 
 
// ---------------------------------------------------------------------------- 
/** 
 * 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) 
    { 
 
        m_buf = new byte [initialCapacity]; 
    } 
     
 
     
    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) 
    { 
 
        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 
// ---------------------------------------------------------------------------- 
 
    
     
     
     
     
  
  |