package org.bouncycastle.crypto.tls;

/**
 * A queue for bytes. This file could be more optimized.
 */
public class ByteQueue
{
    /**
     * @return The smallest number which can be written as 2^x which is bigger than i.
     */
    public static final int nextTwoPow(int i)
    {
        /*
         * This code is based of a lot of code I found on the Internet which mostly
         * referenced a book called "Hacking delight".
         */
        i |= (i >> 1);
        i |= (i >> 2);
        i |= (i >> 4);
        i |= (i >> 8);
        i |= (i >> 16);
        return i + 1;
    }

    /**
     * The initial size for our buffer.
     */
    private static final int INITBUFSIZE = 1024;

    /**
     * The buffer where we store our data.
     */
    private byte[] databuf = new byte[ByteQueue.INITBUFSIZE];

    /**
     * How many bytes at the beginning of the buffer are skipped.
     */
    private int skipped = 0;

    /**
     * How many bytes in the buffer are valid data.
     */
    private int available = 0;

    /**
     * Read data from the buffer.
     *
     * @param buf    The buffer where the read data will be copied to.
     * @param offset How many bytes to skip at the beginning of buf.
     * @param len    How many bytes to read at all.
     * @param skip   How many bytes from our data to skip.
     */
    public void read(byte[] buf, int offset, int len, int skip)
    {
        if ((available - skip) < len)
        {
            throw new TlsRuntimeException("Not enough data to read");
        }
        if ((buf.length - offset) < len)
        {
            throw new TlsRuntimeException("Buffer size of " + buf.length
                + " is too small for a read of " + len + " bytes");
        }
        System.arraycopy(databuf, skipped + skip, buf, offset, len);
        return;
    }

    /**
     * Add some data to our buffer.
     *
     * @param data   A byte-array to read data from.
     * @param offset How many bytes to skip at the beginning of the array.
     * @param len    How many bytes to read from the array.
     */
    public void addData(byte[] data, int offset, int len)
    {
        if ((skipped + available + len) > databuf.length)
        {
            byte[] tmp = new byte[ByteQueue.nextTwoPow(data.length)];
            System.arraycopy(databuf, skipped, tmp, 0, available);
            skipped = 0;
            databuf = tmp;
        }
        System.arraycopy(data, offset, databuf, skipped + available, len);
        available += len;
    }

    /**
     * Remove some bytes from our data from the beginning.
     *
     * @param i How many bytes to remove.
     */
    public void removeData(int i)
    {
        if (i > available)
        {
            throw new TlsRuntimeException("Cannot remove " + i + " bytes, only got " + available);
        }

        /*
         * Skip the data.
         */
        available -= i;
        skipped += i;

        /*
         * If more than half of our data is skipped, we will move the data in the buffer.
         */
        if (skipped > (databuf.length / 2))
        {
            System.arraycopy(databuf, skipped, databuf, 0, available);
            skipped = 0;
        }
    }

    /**
     * @return The number of bytes which are available in this buffer.
     */
    public int size()
    {
        return available;
    }
}

@@ -2218,63 +2218,110 @@
     
-byte%5B%5D tmp = new byte%5BByteQueue.nextTwoPow(
+int desiredSize = ByteQueue.nextTwoPow(available + len);%0A            if (desiredSize %3E 
 data
+buf
 .length)
 %5D;%0A 
@@ -2316,19 +2316,87 @@
 .length)
-%5D;%0A
+%0A            %7B%0A                byte%5B%5D tmp = new byte%5BdesiredSize%5D;%0A    
         
@@ -2470,46 +2470,184 @@
     
-skipped = 0;%0A            databuf = tmp
+    databuf = tmp;%0A            %7D%0A            else%0A            %7B%0A                System.arraycopy(databuf, skipped, databuf, 0, available);%0A            %7D%0A            skipped = 0
 ;%0A  
@@ -2646,32 +2646,33 @@
  = 0;%0A        %7D%0A
+%0A
         System.a
@@ -3172,282 +3172,8 @@
 = i;
-%0A%0A        /*%0A         * If more than half of our data is skipped, we will move the data in the buffer.%0A         */%0A        if (skipped %3E (databuf.length / 2))%0A        %7B%0A            System.arraycopy(databuf, skipped, databuf, 0, available);%0A            skipped = 0;%0A        %7D
 %0A   

Fix space-allocation bug in addData Avoid premature copying in removeData