You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by tr...@apache.org on 2005/12/01 06:19:07 UTC
svn commit: r350169 [3/16] - in /directory/network:
branches/chain_refactor/src/java/org/apache/mina/common/
trunk/src/examples/org/apache/mina/examples/echoserver/
trunk/src/examples/org/apache/mina/examples/httpserver/
trunk/src/examples/org/apache/m...
Modified: directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java
URL: http://svn.apache.org/viewcvs/directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java?rev=350169&r1=350168&r2=350169&view=diff
==============================================================================
--- directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java (original)
+++ directory/network/trunk/src/java/org/apache/mina/common/ByteBuffer.java Wed Nov 30 21:17:41 2005
@@ -1,1880 +1,1880 @@
-/*
- * @(#) $Id$
- *
- * Copyright 2004 The Apache Software Foundation
- *
- * 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 org.apache.mina.common;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.ObjectStreamClass;
-import java.io.OutputStream;
-import java.nio.BufferOverflowException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteOrder;
-import java.nio.CharBuffer;
-import java.nio.DoubleBuffer;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import java.nio.LongBuffer;
-import java.nio.ShortBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-
-import org.apache.mina.common.IoFilter.NextFilter;
-import org.apache.mina.common.IoFilter.WriteRequest;
-import org.apache.mina.common.support.ByteBufferHexDumper;
-import org.apache.mina.filter.codec.ProtocolEncoderOutput;
-import org.apache.mina.util.Stack;
-
-/**
- * A pooled byte buffer used by MINA applications.
- * <p>
- * This is a replacement for {@link java.nio.ByteBuffer}. Please refer to
- * {@link java.nio.ByteBuffer} and {@link java.nio.Buffer} documentation for
- * usage. MINA does not use NIO {@link java.nio.ByteBuffer} directly for two
- * reasons:
- * <ul>
- * <li>It doesn't provide useful getters and putters such as
- * <code>fill</code>, <code>get/putString</code>, and
- * <code>get/putAsciiInt()</code> enough.</li>
- * <li>It is hard to distinguish if the buffer is created from MINA buffer
- * pool or not. MINA have to return used buffers back to pool.</li>
- * <li>It is difficult to write variable-length data due to its fixed
- * capacity</li>
- * </ul>
- *
- * <h2>Allocation</h2>
- * <p>
- * You can get a heap buffer from buffer pool:
- * <pre>
- * ByteBuffer buf = ByteBuffer.allocate(1024, false);
- * </pre>
- * you can also get a direct buffer from buffer pool:
- * <pre>
- * ByteBuffer buf = ByteBuffer.allocate(1024, true);
- * </pre>
- * or you can let MINA choose:
- * <pre>
- * ByteBuffer buf = ByteBuffer.allocate(1024);
- * </pre>
- *
- * <h2>Acquire/Release</h2>
- * <p>
- * <b>Please note that you never need to release the allocated buffer</b>
- * because MINA will release it automatically when:
- * <ul>
- * <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li>
- * <li>You pass the buffer by calling {@link NextFilter#filterWrite(IoSession,WriteRequest)}.</li>
- * <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li>
- * </ul>
- * And, you don't need to release any {@link ByteBuffer} which is passed as a parameter
- * of {@link IoHandler#messageReceived(IoSession, ByteBuffer)} method. They are released
- * automatically when the method returns.
- * <p>
- * You have to release buffers manually by calling {@link #release()} when:
- * <ul>
- * <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li>
- * <li>You called {@link #acquire()} to prevent the buffer from being released.</li>
- * </ul>
- *
- * <h2>Wrapping existing NIO buffers and arrays</h2>
- * <p>
- * This class provides a few <tt>wrap(...)</tt> methods that wraps
- * any NIO buffers and byte arrays. Wrapped MINA buffers are not returned
- * to the buffer pool by default to prevent unexpected memory leakage by default.
- * In case you want to make it pooled, you can call {@link #setPooled(boolean)}
- * with <tt>true</tt> flag to enable pooling.
- *
- * <h2>AutoExpand</h2>
- * <p>
- * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really
- * easy, and it is because its size is fixed. MINA <tt>ByteBuffer</tt>
- * introduces <tt>autoExpand</tt> property. If <tt>autoExpand</tt> property
- * is true, you never get {@link BufferOverflowException} or
- * {@link IndexOutOfBoundsException} (except when index is negative).
- * It automatically expands its capacity and limit value. For example:
- * <pre>
- * String greeting = messageBundle.getMessage( "hello" );
- * ByteBuffer buf = ByteBuffer.allocate( 16 );
- * // Turn on autoExpand (it is off by default)
- * buf.setAutoExpand( true );
- * buf.putString( greeting, utf8encoder );
- * </pre>
- * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind
- * the scene if the encoded data is larger than 16 bytes. Its capacity will
- * increase by two times, and its limit will increase to the last position
- * the string is written.
- *
- * @author The Apache Directory Project (dev@directory.apache.org)
- * @version $Rev$, $Date$
- */
-public abstract class ByteBuffer
-{
- private static final int MINIMUM_CAPACITY = 1;
-
- private static final Stack containerStack = new Stack();
-
- private static final Stack[] heapBufferStacks = new Stack[] {
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(), };
-
- private static final Stack[] directBufferStacks = new Stack[] {
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(),
- new Stack(), new Stack(), new Stack(), new Stack(), };
-
- /**
- * Returns the direct or heap buffer which is capable of the specified
- * size. This method tries to allocate direct buffer first, and then
- * tries heap buffer if direct buffer memory is exhausted. Please use
- * {@link #allocate(int, boolean)} to allocate buffers of specific type.
- *
- * @param capacity the capacity of the buffer
- */
- public static ByteBuffer allocate( int capacity )
- {
- try
- {
- // first try to allocate direct buffer
- return allocate( capacity, true );
- }
- catch( OutOfMemoryError e )
- {
- // if failed, try heap
- return allocate( capacity, false );
- }
- }
-
- /**
- * Returns the buffer which is capable of the specified size.
- *
- * @param capacity the capacity of the buffer
- * @param direct <tt>true</tt> to get a direct buffer,
- * <tt>false</tt> to get a heap buffer.
- */
- public static ByteBuffer allocate( int capacity, boolean direct )
- {
- java.nio.ByteBuffer nioBuffer = allocate0( capacity, direct );
- DefaultByteBuffer buf = allocateContainer();
- buf.init( nioBuffer );
- return buf;
- }
-
- private static DefaultByteBuffer allocateContainer()
- {
- DefaultByteBuffer buf;
- synchronized( containerStack )
- {
- buf = ( DefaultByteBuffer ) containerStack.pop();
- }
-
- if( buf == null )
- {
- buf = new DefaultByteBuffer();
- }
- return buf;
- }
-
- private static java.nio.ByteBuffer allocate0( int capacity, boolean direct )
- {
- Stack[] bufferStacks = direct? directBufferStacks : heapBufferStacks;
- int idx = getBufferStackIndex( bufferStacks, capacity );
- Stack stack = bufferStacks[ idx ];
-
- java.nio.ByteBuffer buf;
- synchronized( stack )
- {
- buf = ( java.nio.ByteBuffer ) stack.pop();
- }
-
- if( buf == null )
- {
- buf = direct ? java.nio.ByteBuffer.allocateDirect( MINIMUM_CAPACITY << idx ) :
- java.nio.ByteBuffer.allocate( MINIMUM_CAPACITY << idx );
- }
-
- return buf;
- }
-
- private static void release0( java.nio.ByteBuffer buf )
- {
- Stack[] bufferStacks = buf.isDirect()? directBufferStacks : heapBufferStacks;
- Stack stack = bufferStacks[ getBufferStackIndex( bufferStacks, buf.capacity() ) ];
- synchronized( stack )
- {
- // push back
- stack.push( buf );
- }
- }
-
- /**
- * Wraps the specified NIO {@link java.nio.ByteBuffer} into MINA buffer.
- */
- public static ByteBuffer wrap( java.nio.ByteBuffer nioBuffer )
- {
- DefaultByteBuffer buf = allocateContainer();
- buf.init( nioBuffer );
- buf.setPooled( false );
- return buf;
- }
-
- /**
- * Wraps the specified byte array into MINA heap buffer.
- */
- public static ByteBuffer wrap( byte[] byteArray )
- {
- return wrap( java.nio.ByteBuffer.wrap( byteArray ) );
- }
-
- /**
- * Wraps the specified byte array into MINA heap buffer.
- * Please note that MINA buffers are going to be pooled, and
- * therefore there can be waste of memory if you wrap
- * your byte array specifying <tt>offset</tt> and <tt>length</tt>.
- */
- public static ByteBuffer wrap( byte[] byteArray, int offset, int length )
- {
- return wrap( java.nio.ByteBuffer.wrap( byteArray, offset, length ) );
- }
-
- private static int getBufferStackIndex( Stack[] bufferStacks, int size )
- {
- int targetSize = MINIMUM_CAPACITY;
- int stackIdx = 0;
- while( size > targetSize )
- {
- targetSize <<= 1;
- stackIdx ++ ;
- if( stackIdx >= bufferStacks.length )
- {
- throw new IllegalArgumentException(
- "Buffer size is too big: " + size );
- }
- }
-
- return stackIdx;
- }
-
- protected ByteBuffer()
- {
- }
-
- /**
- * Increases the internal reference count of this buffer to defer
- * automatic release. You have to invoke {@link #release()} as many
- * as you invoked this method to release this buffer.
- *
- * @throws IllegalStateException if you attempt to acquire already
- * released buffer.
- */
- public abstract void acquire();
-
- /**
- * Releases the specified buffer to buffer pool.
- *
- * @throws IllegalStateException if you attempt to release already
- * released buffer.
- */
- public abstract void release();
-
- /**
- * Returns the underlying NIO buffer instance.
- */
- public abstract java.nio.ByteBuffer buf();
-
- public abstract boolean isDirect();
-
- public abstract int capacity();
-
- /**
- * Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on.
- */
- public abstract boolean isAutoExpand();
-
- /**
- * Turns on or off <tt>autoExpand</tt>.
- */
- public abstract ByteBuffer setAutoExpand( boolean autoExpand );
-
- /**
- * Returns <tt>true</tt> if and only if this buffer is returned back
- * to the buffer pool when released.
- * <p>
- * The default value of this property is <tt>true</tt> if and only if you
- * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
- * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
- * and {@link #wrap(java.nio.ByteBuffer)})
- */
- public abstract boolean isPooled();
-
- /**
- * Sets whether this buffer is returned back to the buffer pool when released.
- * <p>
- * The default value of this property is <tt>true</tt> if and only if you
- * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
- * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
- * and {@link #wrap(java.nio.ByteBuffer)})
- */
- public abstract void setPooled( boolean pooled );
-
- public abstract int position();
-
- public abstract ByteBuffer position( int newPosition );
-
- public abstract int limit();
-
- public abstract ByteBuffer limit( int newLimit );
-
- public abstract ByteBuffer mark();
-
- public abstract ByteBuffer reset();
-
- public abstract ByteBuffer clear();
-
- public abstract ByteBuffer flip();
-
- public abstract ByteBuffer rewind();
-
- public abstract int remaining();
-
- public abstract boolean hasRemaining();
-
- public abstract byte get();
-
- public abstract short getUnsigned();
-
- public abstract ByteBuffer put( byte b );
-
- public abstract byte get( int index );
-
- public abstract short getUnsigned( int index );
-
- public abstract ByteBuffer put( int index, byte b );
-
- public abstract ByteBuffer get( byte[] dst, int offset, int length );
-
- public abstract ByteBuffer get( byte[] dst );
-
- public abstract ByteBuffer put( java.nio.ByteBuffer src );
-
- public abstract ByteBuffer put( ByteBuffer src );
-
- public abstract ByteBuffer put( byte[] src, int offset, int length );
-
- public abstract ByteBuffer put( byte[] src );
-
- public abstract ByteBuffer compact();
-
- public abstract String toString();
-
- public abstract int hashCode();
-
- public abstract boolean equals( Object ob );
-
- public abstract int compareTo( ByteBuffer that );
-
- public abstract ByteOrder order();
-
- public abstract ByteBuffer order( ByteOrder bo );
-
- public abstract char getChar();
-
- public abstract ByteBuffer putChar( char value );
-
- public abstract char getChar( int index );
-
- public abstract ByteBuffer putChar( int index, char value );
-
- public abstract CharBuffer asCharBuffer();
-
- public abstract short getShort();
-
- public abstract int getUnsignedShort();
-
- public abstract ByteBuffer putShort( short value );
-
- public abstract short getShort( int index );
-
- public abstract int getUnsignedShort( int index );
-
- public abstract ByteBuffer putShort( int index, short value );
-
- public abstract ShortBuffer asShortBuffer();
-
- public abstract int getInt();
-
- public abstract long getUnsignedInt();
-
- public abstract ByteBuffer putInt( int value );
-
- public abstract int getInt( int index );
-
- public abstract long getUnsignedInt( int index );
-
- public abstract ByteBuffer putInt( int index, int value );
-
- public abstract IntBuffer asIntBuffer();
-
- public abstract long getLong();
-
- public abstract ByteBuffer putLong( long value );
-
- public abstract long getLong( int index );
-
- public abstract ByteBuffer putLong( int index, long value );
-
- public abstract LongBuffer asLongBuffer();
-
- public abstract float getFloat();
-
- public abstract ByteBuffer putFloat( float value );
-
- public abstract float getFloat( int index );
-
- public abstract ByteBuffer putFloat( int index, float value );
-
- public abstract FloatBuffer asFloatBuffer();
-
- public abstract double getDouble();
-
- public abstract ByteBuffer putDouble( double value );
-
- public abstract double getDouble( int index );
-
- public abstract ByteBuffer putDouble( int index, double value );
-
- public abstract DoubleBuffer asDoubleBuffer();
-
- /**
- * Returns an {@link InputStream} that reads the data from this buffer.
- * {@link InputStream#read()} returns <tt>-1</tt> if the buffer position
- * reaches to the limit.
- */
- public InputStream asInputStream()
- {
- return new InputStream()
- {
- public int available() throws IOException
- {
- return ByteBuffer.this.remaining();
- }
-
- public synchronized void mark( int readlimit )
- {
- ByteBuffer.this.mark();
- }
-
- public boolean markSupported()
- {
- return true;
- }
-
- public int read() throws IOException
- {
- if( ByteBuffer.this.hasRemaining() )
- {
- return ByteBuffer.this.get() & 0xff;
- }
- else
- {
- return -1;
- }
- }
-
- public int read( byte[] b, int off, int len ) throws IOException
- {
- int remaining = ByteBuffer.this.remaining();
- if( remaining > 0 )
- {
- int readBytes = Math.min( remaining, len );
- ByteBuffer.this.get( b, off, readBytes );
- return readBytes;
- }
- else
- {
- return -1;
- }
- }
-
- public synchronized void reset() throws IOException
- {
- ByteBuffer.this.reset();
- }
-
- public long skip( long n ) throws IOException
- {
- int bytes;
- if( n > Integer.MAX_VALUE )
- {
- bytes = ByteBuffer.this.remaining();
- }
- else
- {
- bytes = Math.min( ByteBuffer.this.remaining(), ( int ) n );
- }
- ByteBuffer.this.skip( bytes );
- return bytes;
- }
- };
- }
-
- /**
- * Returns an {@link OutputStream} that appends the data into this buffer.
- * Please note that the {@link OutputStream#write(int)} will throw a
- * {@link BufferOverflowException} instead of an {@link IOException}
- * in case of buffer overflow. Please set <tt>autoExpand</tt> property by
- * calling {@link #setAutoExpand(boolean)} to prevent the unexpected runtime
- * exception.
- */
- public OutputStream asOutputStream()
- {
- return new OutputStream()
- {
- public void write( byte[] b, int off, int len ) throws IOException
- {
- ByteBuffer.this.put( b, off, len );
- }
-
- public void write( int b ) throws IOException
- {
- ByteBuffer.this.put( ( byte ) b );
- }
- };
- }
-
- /**
- * Returns hexdump of this buffer.
- */
- public abstract String getHexDump();
-
- ////////////////////////////////
- // String getters and putters //
- ////////////////////////////////
-
- /**
- * Reads a <code>NUL</code>-terminated string from this buffer using the
- * specified <code>decoder</code> and returns it. This method reads
- * until the limit of this buffer if no <tt>NUL</tt> is found.
- */
- public abstract String getString( CharsetDecoder decoder ) throws CharacterCodingException;
-
- /**
- * Reads a <code>NUL</code>-terminated string from this buffer using the
- * specified <code>decoder</code> and returns it.
- *
- * @param fieldSize the maximum number of bytes to read
- */
- public abstract String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException;
-
- /**
- * Writes the content of <code>in</code> into this buffer using the
- * specified <code>encoder</code>. This method doesn't terminate
- * string with <tt>NUL</tt>. You have to do it by yourself.
- *
- * @throws BufferOverflowException if the specified string doesn't fit
- */
- public abstract ByteBuffer putString( CharSequence in, CharsetEncoder encoder ) throws CharacterCodingException;
-
- /**
- * Writes the content of <code>in</code> into this buffer as a
- * <code>NUL</code>-terminated string using the specified
- * <code>encoder</code>.
- * <p>
- * If the charset name of the encoder is UTF-16, you cannot specify
- * odd <code>fieldSize</code>, and this method will append two
- * <code>NUL</code>s as a terminator.
- * <p>
- * Please note that this method doesn't terminate with <code>NUL</code>
- * if the input string is longer than <tt>fieldSize</tt>.
- *
- * @param fieldSize the maximum number of bytes to write
- */
- public abstract ByteBuffer putString(
- CharSequence in, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException;
-
- /**
- * Reads a Pascal string which as a 16-bit length field before the actual
- * encoded string, using the specified <code>decoder</code> and returns it.
- */
- public abstract String getPascalString( CharsetDecoder decoder ) throws CharacterCodingException;
-
- /**
- * Writes the content of <code>in</code> into this buffer as a
- * Pascal string which has a 16-bit length field before the actual
- * encoded string, using the specified <code>encoder</code>.
- * This method doesn't terminate the string with <tt>NUL</tt>
- * because we don't need to do so.
- *
- * @throws BufferOverflowException if the specified string doesn't fit
- */
- public abstract ByteBuffer putPascalString( CharSequence in, CharsetEncoder encoder ) throws CharacterCodingException;
-
- /**
- * Reads a Java object from the buffer using the context {@link ClassLoader}
- * of the current thread.
- */
- public Object getObject() throws ClassNotFoundException
- {
- return getObject( Thread.currentThread().getContextClassLoader() );
- }
-
- /**
- * Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
- */
- public abstract Object getObject( ClassLoader classLoader ) throws ClassNotFoundException;
-
- /**
- * Writes the specified Java object to the buffer.
- */
- public abstract ByteBuffer putObject( Object o );
-
- //////////////////////////
- // Skip or fill methods //
- //////////////////////////
-
- /**
- * Forwards the position of this buffer as the specified <code>size</code>
- * bytes.
- */
- public abstract ByteBuffer skip( int size );
-
- /**
- * Fills this buffer with the specified value.
- * This method moves buffer position forward.
- */
- public abstract ByteBuffer fill( byte value, int size );
-
- /**
- * Fills this buffer with the specified value.
- * This method does not change buffer position.
- */
- public abstract ByteBuffer fillAndReset( byte value, int size );
-
- /**
- * Fills this buffer with <code>NUL (0x00)</code>.
- * This method moves buffer position forward.
- */
- public abstract ByteBuffer fill( int size );
-
- /**
- * Fills this buffer with <code>NUL (0x00)</code>.
- * This method does not change buffer position.
- */
- public abstract ByteBuffer fillAndReset( int size );
-
- private static class DefaultByteBuffer extends ByteBuffer
- {
- private java.nio.ByteBuffer buf;
- private int refCount = 1;
- private boolean autoExpand;
- private boolean pooled;
-
- protected DefaultByteBuffer()
- {
- }
-
- private synchronized void init( java.nio.ByteBuffer buf )
- {
- this.buf = buf;
- buf.clear();
- buf.order( ByteOrder.BIG_ENDIAN );
- autoExpand = false;
- pooled = true;
- refCount = 1;
- }
-
- public synchronized void acquire()
- {
- if( refCount <= 0 )
- {
- throw new IllegalStateException( "Already released buffer." );
- }
-
- refCount ++;
- }
-
- public void release()
- {
- synchronized( this )
- {
- if( refCount <= 0 )
- {
- refCount = 0;
- throw new IllegalStateException(
- "Already released buffer. You released the buffer too many times." );
- }
-
- refCount --;
- if( refCount > 0)
- {
- return;
- }
- }
-
- if( pooled )
- {
- release0( buf );
- }
-
- synchronized( containerStack )
- {
- containerStack.push( this );
- }
- }
-
- public java.nio.ByteBuffer buf()
- {
- return buf;
- }
-
- public boolean isDirect()
- {
- return buf.isDirect();
- }
-
- public boolean isReadOnly()
- {
- return buf.isReadOnly();
- }
-
- public boolean isAutoExpand()
- {
- return autoExpand;
- }
-
- public ByteBuffer setAutoExpand( boolean autoExpand )
- {
- this.autoExpand = autoExpand;
- return this;
- }
-
- public boolean isPooled()
- {
- return pooled;
- }
-
- public void setPooled( boolean pooled )
- {
- this.pooled = pooled;
- }
-
- public int capacity()
- {
- return buf.capacity();
- }
-
- public int position()
- {
- return buf.position();
- }
-
- public ByteBuffer position( int newPosition )
- {
- autoExpand( newPosition, 0 );
- buf.position( newPosition );
- return this;
- }
-
- public int limit()
- {
- return buf.limit();
- }
-
- public ByteBuffer limit( int newLimit )
- {
- autoExpand( newLimit, 0 );
- buf.limit( newLimit );
- return this;
- }
-
- public ByteBuffer mark()
- {
- buf.mark();
- return this;
- }
-
- public ByteBuffer reset()
- {
- buf.reset();
- return this;
- }
-
- public ByteBuffer clear()
- {
- buf.clear();
- return this;
- }
-
- public ByteBuffer flip()
- {
- buf.flip();
- return this;
- }
-
- public ByteBuffer rewind()
- {
- buf.rewind();
- return this;
- }
-
- public int remaining()
- {
- return buf.remaining();
- }
-
- public boolean hasRemaining()
- {
- return buf.hasRemaining();
- }
-
- public byte get()
- {
- return buf.get();
- }
-
- public short getUnsigned()
- {
- return ( short ) ( get() & 0xff );
- }
-
- public ByteBuffer put( byte b )
- {
- autoExpand( 1 );
- buf.put( b );
- return this;
- }
-
- public byte get( int index )
- {
- return buf.get( index );
- }
-
- public short getUnsigned( int index )
- {
- return ( short ) ( get( index ) & 0xff );
- }
-
- public ByteBuffer put( int index, byte b )
- {
- autoExpand( index, 1 );
- buf.put( index, b );
- return this;
- }
-
- public ByteBuffer get( byte[] dst, int offset, int length )
- {
- buf.get( dst, offset, length );
- return this;
- }
-
- public ByteBuffer get( byte[] dst )
- {
- buf.get( dst );
- return this;
- }
-
- public ByteBuffer put( java.nio.ByteBuffer src )
- {
- autoExpand( src.remaining() );
- buf.put( src );
- return this;
- }
-
- public ByteBuffer put( ByteBuffer src )
- {
- autoExpand( src.remaining() );
- buf.put( src.buf() );
- return this;
- }
-
- public ByteBuffer put( byte[] src, int offset, int length )
- {
- autoExpand( length );
- buf.put( src, offset, length );
- return this;
- }
-
- public ByteBuffer put( byte[] src )
- {
- autoExpand( src.length );
- buf.put( src );
- return this;
- }
-
- public ByteBuffer compact()
- {
- buf.compact();
- return this;
- }
-
- public String toString()
- {
- return buf.toString() + " (" + getHexDump() + ')';
- }
-
- public int hashCode()
- {
- return buf.hashCode();
- }
-
- public boolean equals( Object ob )
- {
- if( !( ob instanceof ByteBuffer ) )
- return false;
-
- ByteBuffer that = ( ByteBuffer ) ob;
- return this.buf.equals( that.buf() );
- }
-
- public int compareTo( ByteBuffer that )
- {
- return this.buf.compareTo( that.buf() );
- }
-
- public ByteOrder order()
- {
- return buf.order();
- }
-
- public ByteBuffer order( ByteOrder bo )
- {
- buf.order( bo );
- return this;
- }
-
- public char getChar()
- {
- return buf.getChar();
- }
-
- public ByteBuffer putChar( char value )
- {
- autoExpand( 2 );
- buf.putChar( value );
- return this;
- }
-
- public char getChar( int index )
- {
- return buf.getChar( index );
- }
-
- public ByteBuffer putChar( int index, char value )
- {
- autoExpand( index, 2 );
- buf.putChar( index, value );
- return this;
- }
-
- public CharBuffer asCharBuffer()
- {
- return buf.asCharBuffer();
- }
-
- public short getShort()
- {
- return buf.getShort();
- }
-
- public int getUnsignedShort()
- {
- return getShort() & 0xffff;
- }
-
- public ByteBuffer putShort( short value )
- {
- autoExpand( 2 );
- buf.putShort( value );
- return this;
- }
-
- public short getShort( int index )
- {
- return buf.getShort( index );
- }
-
- public int getUnsignedShort( int index )
- {
- return getShort( index ) & 0xffff;
- }
-
- public ByteBuffer putShort( int index, short value )
- {
- autoExpand( index, 2 );
- buf.putShort( index, value );
- return this;
- }
-
- public ShortBuffer asShortBuffer()
- {
- return buf.asShortBuffer();
- }
-
- public int getInt()
- {
- return buf.getInt();
- }
-
- public long getUnsignedInt()
- {
- return getInt() & 0xffffffffL;
- }
-
- public ByteBuffer putInt( int value )
- {
- autoExpand( 4 );
- buf.putInt( value );
- return this;
- }
-
- public int getInt( int index )
- {
- return buf.getInt( index );
- }
-
- public long getUnsignedInt( int index )
- {
- return getInt( index ) & 0xffffffffL;
- }
-
- public ByteBuffer putInt( int index, int value )
- {
- autoExpand( index, 4 );
- buf.putInt( index, value );
- return this;
- }
-
- public IntBuffer asIntBuffer()
- {
- return buf.asIntBuffer();
- }
-
- public long getLong()
- {
- return buf.getLong();
- }
-
- public ByteBuffer putLong( long value )
- {
- autoExpand( 8 );
- buf.putLong( value );
- return this;
- }
-
- public long getLong( int index )
- {
- return buf.getLong( index );
- }
-
- public ByteBuffer putLong( int index, long value )
- {
- autoExpand( index, 8 );
- buf.putLong( index, value );
- return this;
- }
-
- public LongBuffer asLongBuffer()
- {
- return buf.asLongBuffer();
- }
-
- public float getFloat()
- {
- return buf.getFloat();
- }
-
- public ByteBuffer putFloat( float value )
- {
- autoExpand( 4 );
- buf.putFloat( value );
- return this;
- }
-
- public float getFloat( int index )
- {
- return buf.getFloat( index );
- }
-
- public ByteBuffer putFloat( int index, float value )
- {
- autoExpand( index, 4 );
- buf.putFloat( index, value );
- return this;
- }
-
- public FloatBuffer asFloatBuffer()
- {
- return buf.asFloatBuffer();
- }
-
- public double getDouble()
- {
- return buf.getDouble();
- }
-
- public ByteBuffer putDouble( double value )
- {
- autoExpand( 8 );
- buf.putDouble( value );
- return this;
- }
-
- public double getDouble( int index )
- {
- return buf.getDouble( index );
- }
-
- public ByteBuffer putDouble( int index, double value )
- {
- autoExpand( index, 8 );
- buf.putDouble( index, value );
- return this;
- }
-
- public DoubleBuffer asDoubleBuffer()
- {
- return buf.asDoubleBuffer();
- }
-
- public String getHexDump()
- {
- return ByteBufferHexDumper.getHexdump( this );
- }
-
- public String getString( CharsetDecoder decoder ) throws CharacterCodingException
- {
- if( !buf.hasRemaining() )
- {
- return "";
- }
-
- boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
-
- int oldPos = buf.position();
- int oldLimit = buf.limit();
- int end;
-
- if( !utf16 )
- {
- while( buf.hasRemaining() )
- {
- if( buf.get() == 0 )
- {
- break;
- }
- }
-
- end = buf.position();
- if( end == oldLimit )
- {
- buf.limit( end );
- }
- else
- {
- buf.limit( end - 1 );
- }
- }
- else
- {
- while( buf.remaining() >= 2 )
- {
- if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
- {
- break;
- }
- }
-
- end = buf.position();
- if( end == oldLimit || end == oldLimit - 1 )
- {
- buf.limit( end );
- }
- else
- {
- buf.limit( end - 2 );
- }
- }
-
- buf.position( oldPos );
- if( !buf.hasRemaining() )
- {
- buf.limit( oldLimit );
- buf.position( end );
- return "";
- }
- decoder.reset();
-
- int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
- CharBuffer out = CharBuffer.allocate( expectedLength );
- for( ;; )
- {
- CoderResult cr;
- if ( buf.hasRemaining() )
- {
- cr = decoder.decode( buf, out, true );
- }
- else
- {
- cr = decoder.flush( out );
- }
-
- if ( cr.isUnderflow() )
- {
- break;
- }
-
- if ( cr.isOverflow() )
- {
- CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
- out.flip();
- o.put(out);
- out = o;
- continue;
- }
-
- cr.throwException();
- }
-
- buf.limit( oldLimit );
- buf.position( end );
- return out.flip().toString();
- }
-
- public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException
- {
- checkFieldSize( fieldSize );
-
- if( fieldSize == 0 )
- {
- return "";
- }
-
- if( !buf.hasRemaining() )
- {
- return "";
- }
-
- boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
-
- if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
- {
- throw new IllegalArgumentException( "fieldSize is not even." );
- }
-
- int i;
- int oldPos = buf.position();
- int oldLimit = buf.limit();
- int end = buf.position() + fieldSize;
-
- if( oldLimit < end )
- {
- throw new BufferUnderflowException();
- }
-
- if( !utf16 )
- {
- for( i = 0; i < fieldSize; i ++ )
- {
- if( buf.get() == 0 )
- {
- break;
- }
- }
-
- if( i == fieldSize )
- {
- buf.limit( end );
- }
- else
- {
- buf.limit( buf.position() - 1 );
- }
- }
- else
- {
- for( i = 0; i < fieldSize; i += 2 )
- {
- if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
- {
- break;
- }
- }
-
- if( i == fieldSize )
- {
- buf.limit( end );
- }
- else
- {
- buf.limit( buf.position() - 2 );
- }
- }
-
- buf.position( oldPos );
- if( !buf.hasRemaining() )
- {
- buf.limit( oldLimit );
- buf.position( end );
- return "";
- }
- decoder.reset();
-
- int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
- CharBuffer out = CharBuffer.allocate( expectedLength );
- for( ;; )
- {
- CoderResult cr;
- if ( buf.hasRemaining() )
- {
- cr = decoder.decode( buf, out, true );
- }
- else
- {
- cr = decoder.flush( out );
- }
-
- if ( cr.isUnderflow() )
- {
- break;
- }
-
- if ( cr.isOverflow() )
- {
- CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
- out.flip();
- o.put(out);
- out = o;
- continue;
- }
-
- cr.throwException();
- }
-
- buf.limit( oldLimit );
- buf.position( end );
- return out.flip().toString();
- }
-
- public ByteBuffer putString(
- CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException
- {
- checkFieldSize( fieldSize );
-
- if( fieldSize == 0 )
- return this;
-
- autoExpand( fieldSize );
-
- boolean utf16 = encoder.charset().name().startsWith( "UTF-16" );
-
- if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
- {
- throw new IllegalArgumentException( "fieldSize is not even." );
- }
-
- int oldLimit = buf.limit();
- int end = buf.position() + fieldSize;
-
- if( oldLimit < end )
- {
- throw new BufferOverflowException();
- }
-
- if( val.length() == 0 )
- {
- if( !utf16 )
- {
- buf.put( ( byte ) 0x00 );
- }
- else
- {
- buf.put( ( byte ) 0x00 );
- buf.put( ( byte ) 0x00 );
- }
- buf.position( end );
- return this;
- }
-
- CharBuffer in = CharBuffer.wrap( val );
- buf.limit( end );
- encoder.reset();
-
- for (;;) {
- CoderResult cr;
- if( in.hasRemaining() )
- {
- cr = encoder.encode( in, buf(), true );
- }
- else
- {
- cr = encoder.flush( buf() );
- }
-
- if( cr.isUnderflow() || cr.isOverflow() )
- {
- break;
- }
- cr.throwException();
- }
-
- buf.limit( oldLimit );
-
- if( buf.position() < end )
- {
- if( !utf16 )
- {
- buf.put( ( byte ) 0x00 );
- }
- else
- {
- buf.put( ( byte ) 0x00 );
- buf.put( ( byte ) 0x00 );
- }
- }
-
- buf.position( end );
- return this;
- }
-
- public ByteBuffer putString(
- CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException
- {
- if( val.length() == 0 )
- {
- return this;
- }
-
- CharBuffer in = CharBuffer.wrap( val );
- int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar());
-
- encoder.reset();
-
- for (;;) {
- CoderResult cr;
- if( in.hasRemaining() )
- {
- cr = encoder.encode( in, buf(), true );
- }
- else
- {
- cr = encoder.flush( buf() );
- }
-
- if( cr.isUnderflow() )
- {
- break;
- }
- if( cr.isOverflow() && autoExpand )
- {
- autoExpand( expectedLength );
- continue;
- }
- cr.throwException();
- }
- return this;
- }
-
- public String getPascalString( CharsetDecoder decoder ) throws CharacterCodingException
- {
- int fieldSize = getUnsignedShort();
- if( fieldSize < 0 )
- {
- throw new BufferDataException( "Invalid fieldSize: " + fieldSize );
- }
-
- if( fieldSize == 0 )
- {
- return "";
- }
-
- boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
-
- if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
- {
- throw new BufferDataException( "fieldSize is not even for a UTF-16 string." );
- }
-
- int oldLimit = buf.limit();
- int end = buf.position() + fieldSize;
-
- if( oldLimit < end )
- {
- throw new BufferUnderflowException();
- }
-
- buf.limit( end );
- decoder.reset();
-
- int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
- CharBuffer out = CharBuffer.allocate( expectedLength );
- for( ;; )
- {
- CoderResult cr;
- if ( buf.hasRemaining() )
- {
- cr = decoder.decode( buf, out, true );
- }
- else
- {
- cr = decoder.flush( out );
- }
-
- if ( cr.isUnderflow() )
- {
- break;
- }
-
- if ( cr.isOverflow() )
- {
- CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
- out.flip();
- o.put(out);
- out = o;
- continue;
- }
-
- cr.throwException();
- }
-
- buf.limit( oldLimit );
- buf.position( end );
- return out.flip().toString();
- }
-
- public ByteBuffer putPascalString( CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException
- {
- if( val.length() > 65535 )
- {
- throw new IllegalArgumentException( "The specified string is too long." );
- }
- if( val.length() == 0 )
- {
- putShort( ( short ) 0 );
- return this;
- }
-
- CharBuffer in = CharBuffer.wrap( val );
- int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar());
-
- int oldPos = position();
- skip( 2 ); // make a room for the length field
- encoder.reset();
-
- for (;;) {
- CoderResult cr;
- if( in.hasRemaining() )
- {
- cr = encoder.encode( in, buf(), true );
- }
- else
- {
- cr = encoder.flush( buf() );
- }
-
- if( position() - oldPos > 65535 )
- {
- throw new IllegalArgumentException( "The specified string is too long." );
- }
-
- if( cr.isUnderflow() )
- {
- break;
- }
- if( cr.isOverflow() && autoExpand )
- {
- autoExpand( expectedLength );
- continue;
- }
- cr.throwException();
- }
-
- // Write the length field
- int newPos = position();
- position( oldPos );
- putShort( ( short ) ( newPos - oldPos - 2 ) );
- position( newPos );
- return this;
- }
-
- public Object getObject( final ClassLoader classLoader ) throws ClassNotFoundException
- {
- int length = getInt();
- if( length > remaining() )
- {
- throw new BufferUnderflowException();
- }
- if( length <= 4 )
- {
- throw new BufferDataException( "Object length should be greater than 4: " + length );
- }
-
- int oldLimit = limit();
- limit( position() + length );
- try
- {
- ObjectInputStream in = new ObjectInputStream( asInputStream() )
- {
- protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
- {
- String className = readUTF();
- Class clazz = Class.forName( className, true, classLoader );
- ObjectStreamClass descriptor = ObjectStreamClass.lookup(clazz);
- return descriptor;
- }
- };
- return in.readObject();
- }
- catch( IOException e )
- {
- throw new BufferDataException( e );
- }
- finally
- {
- limit( oldLimit );
- }
- }
-
- public ByteBuffer putObject( Object o )
- {
- int oldPos = position();
- skip( 4 ); // Make a room for the length field.
- try
- {
- ObjectOutputStream out = new ObjectOutputStream( asOutputStream() )
- {
- protected void writeClassDescriptor( ObjectStreamClass desc ) throws IOException
- {
- writeUTF( desc.getName() );
- }
- };
- out.writeObject( o );
- out.flush();
- }
- catch( IOException e )
- {
- throw new BufferDataException( e );
- }
-
- // Fill the length field
- int newPos = position();
- position( oldPos );
- putInt( newPos - oldPos - 4 );
- position( newPos );
- return this;
- }
-
- public ByteBuffer skip( int size )
- {
- autoExpand( size );
- return position( position() + size );
- }
-
- public ByteBuffer fill( byte value, int size )
- {
- autoExpand( size );
- int q = size >>> 3;
- int r = size & 7;
-
- if( q > 0 )
- {
- int intValue = value | ( value << 8 ) | ( value << 16 )
- | ( value << 24 );
- long longValue = intValue;
- longValue <<= 32;
- longValue |= intValue;
-
- for( int i = q; i > 0; i -- )
- {
- buf.putLong( longValue );
- }
- }
-
- q = r >>> 2;
- r = r & 3;
-
- if( q > 0 )
- {
- int intValue = value | ( value << 8 ) | ( value << 16 )
- | ( value << 24 );
- buf.putInt( intValue );
- }
-
- q = r >> 1;
- r = r & 1;
-
- if( q > 0 )
- {
- short shortValue = ( short ) ( value | ( value << 8 ) );
- buf.putShort( shortValue );
- }
-
- if( r > 0 )
- {
- buf.put( value );
- }
-
- return this;
- }
-
- public ByteBuffer fillAndReset( byte value, int size )
- {
- autoExpand( size );
- int pos = buf.position();
- try
- {
- fill( value, size );
- }
- finally
- {
- buf.position( pos );
- }
- return this;
- }
-
- public ByteBuffer fill( int size )
- {
- autoExpand( size );
- int q = size >>> 3;
- int r = size & 7;
-
- for( int i = q; i > 0; i -- )
- {
- buf.putLong( 0L );
- }
-
- q = r >>> 2;
- r = r & 3;
-
- if( q > 0 )
- {
- buf.putInt( 0 );
- }
-
- q = r >> 1;
- r = r & 1;
-
- if( q > 0 )
- {
- buf.putShort( ( short ) 0 );
- }
-
- if( r > 0 )
- {
- buf.put( ( byte ) 0 );
- }
-
- return this;
- }
-
- public ByteBuffer fillAndReset( int size )
- {
- autoExpand( size );
- int pos = buf.position();
- try
- {
- fill( size );
- }
- finally
- {
- buf.position( pos );
- }
-
- return this;
- }
-
- private void autoExpand( int delta )
- {
- if( autoExpand )
- {
- int pos = buf.position();
- int limit = buf.limit();
- int end = pos + delta;
- if( end > limit ) {
- ensureCapacity( end );
- buf.limit( end );
- }
- }
- }
-
- private void autoExpand( int pos, int delta )
- {
- if( autoExpand )
- {
- int limit = buf.limit();
- int end = pos + delta;
- if( end > limit ) {
- ensureCapacity( end ); // expand by 50%
- buf.limit( end );
- }
- }
- }
-
- private void ensureCapacity( int requestedCapacity )
- {
- if( requestedCapacity <= buf.capacity() )
- {
- return;
- }
-
- int newCapacity = MINIMUM_CAPACITY;
- while( newCapacity < requestedCapacity )
- {
- newCapacity <<= 1;
- }
-
- java.nio.ByteBuffer oldBuf = this.buf;
- java.nio.ByteBuffer newBuf = allocate0( newCapacity, isDirect() );
- newBuf.clear();
- newBuf.order( oldBuf.order() );
-
- int pos = oldBuf.position();
- int limit = oldBuf.limit();
- oldBuf.clear();
- newBuf.put( oldBuf );
- newBuf.position( 0 );
- newBuf.limit( limit );
- newBuf.position( pos );
- this.buf = newBuf;
- release0( oldBuf );
- }
-
- private static void checkFieldSize( int fieldSize )
- {
- if( fieldSize < 0 )
- {
- throw new IllegalArgumentException(
- "fieldSize cannot be negative: " + fieldSize );
- }
- }
-
- }
-}
+/*
+ * @(#) $Id$
+ *
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 org.apache.mina.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.OutputStream;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+
+import org.apache.mina.common.IoFilter.NextFilter;
+import org.apache.mina.common.IoFilter.WriteRequest;
+import org.apache.mina.common.support.ByteBufferHexDumper;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+import org.apache.mina.util.Stack;
+
+/**
+ * A pooled byte buffer used by MINA applications.
+ * <p>
+ * This is a replacement for {@link java.nio.ByteBuffer}. Please refer to
+ * {@link java.nio.ByteBuffer} and {@link java.nio.Buffer} documentation for
+ * usage. MINA does not use NIO {@link java.nio.ByteBuffer} directly for two
+ * reasons:
+ * <ul>
+ * <li>It doesn't provide useful getters and putters such as
+ * <code>fill</code>, <code>get/putString</code>, and
+ * <code>get/putAsciiInt()</code> enough.</li>
+ * <li>It is hard to distinguish if the buffer is created from MINA buffer
+ * pool or not. MINA have to return used buffers back to pool.</li>
+ * <li>It is difficult to write variable-length data due to its fixed
+ * capacity</li>
+ * </ul>
+ *
+ * <h2>Allocation</h2>
+ * <p>
+ * You can get a heap buffer from buffer pool:
+ * <pre>
+ * ByteBuffer buf = ByteBuffer.allocate(1024, false);
+ * </pre>
+ * you can also get a direct buffer from buffer pool:
+ * <pre>
+ * ByteBuffer buf = ByteBuffer.allocate(1024, true);
+ * </pre>
+ * or you can let MINA choose:
+ * <pre>
+ * ByteBuffer buf = ByteBuffer.allocate(1024);
+ * </pre>
+ *
+ * <h2>Acquire/Release</h2>
+ * <p>
+ * <b>Please note that you never need to release the allocated buffer</b>
+ * because MINA will release it automatically when:
+ * <ul>
+ * <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li>
+ * <li>You pass the buffer by calling {@link NextFilter#filterWrite(IoSession,WriteRequest)}.</li>
+ * <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li>
+ * </ul>
+ * And, you don't need to release any {@link ByteBuffer} which is passed as a parameter
+ * of {@link IoHandler#messageReceived(IoSession, ByteBuffer)} method. They are released
+ * automatically when the method returns.
+ * <p>
+ * You have to release buffers manually by calling {@link #release()} when:
+ * <ul>
+ * <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li>
+ * <li>You called {@link #acquire()} to prevent the buffer from being released.</li>
+ * </ul>
+ *
+ * <h2>Wrapping existing NIO buffers and arrays</h2>
+ * <p>
+ * This class provides a few <tt>wrap(...)</tt> methods that wraps
+ * any NIO buffers and byte arrays. Wrapped MINA buffers are not returned
+ * to the buffer pool by default to prevent unexpected memory leakage by default.
+ * In case you want to make it pooled, you can call {@link #setPooled(boolean)}
+ * with <tt>true</tt> flag to enable pooling.
+ *
+ * <h2>AutoExpand</h2>
+ * <p>
+ * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really
+ * easy, and it is because its size is fixed. MINA <tt>ByteBuffer</tt>
+ * introduces <tt>autoExpand</tt> property. If <tt>autoExpand</tt> property
+ * is true, you never get {@link BufferOverflowException} or
+ * {@link IndexOutOfBoundsException} (except when index is negative).
+ * It automatically expands its capacity and limit value. For example:
+ * <pre>
+ * String greeting = messageBundle.getMessage( "hello" );
+ * ByteBuffer buf = ByteBuffer.allocate( 16 );
+ * // Turn on autoExpand (it is off by default)
+ * buf.setAutoExpand( true );
+ * buf.putString( greeting, utf8encoder );
+ * </pre>
+ * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind
+ * the scene if the encoded data is larger than 16 bytes. Its capacity will
+ * increase by two times, and its limit will increase to the last position
+ * the string is written.
+ *
+ * @author The Apache Directory Project (dev@directory.apache.org)
+ * @version $Rev$, $Date$
+ */
+public abstract class ByteBuffer
+{
+ private static final int MINIMUM_CAPACITY = 1;
+
+ private static final Stack containerStack = new Stack();
+
+ private static final Stack[] heapBufferStacks = new Stack[] {
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(), };
+
+ private static final Stack[] directBufferStacks = new Stack[] {
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(),
+ new Stack(), new Stack(), new Stack(), new Stack(), };
+
+ /**
+ * Returns the direct or heap buffer which is capable of the specified
+ * size. This method tries to allocate direct buffer first, and then
+ * tries heap buffer if direct buffer memory is exhausted. Please use
+ * {@link #allocate(int, boolean)} to allocate buffers of specific type.
+ *
+ * @param capacity the capacity of the buffer
+ */
+ public static ByteBuffer allocate( int capacity )
+ {
+ try
+ {
+ // first try to allocate direct buffer
+ return allocate( capacity, true );
+ }
+ catch( OutOfMemoryError e )
+ {
+ // if failed, try heap
+ return allocate( capacity, false );
+ }
+ }
+
+ /**
+ * Returns the buffer which is capable of the specified size.
+ *
+ * @param capacity the capacity of the buffer
+ * @param direct <tt>true</tt> to get a direct buffer,
+ * <tt>false</tt> to get a heap buffer.
+ */
+ public static ByteBuffer allocate( int capacity, boolean direct )
+ {
+ java.nio.ByteBuffer nioBuffer = allocate0( capacity, direct );
+ DefaultByteBuffer buf = allocateContainer();
+ buf.init( nioBuffer );
+ return buf;
+ }
+
+ private static DefaultByteBuffer allocateContainer()
+ {
+ DefaultByteBuffer buf;
+ synchronized( containerStack )
+ {
+ buf = ( DefaultByteBuffer ) containerStack.pop();
+ }
+
+ if( buf == null )
+ {
+ buf = new DefaultByteBuffer();
+ }
+ return buf;
+ }
+
+ private static java.nio.ByteBuffer allocate0( int capacity, boolean direct )
+ {
+ Stack[] bufferStacks = direct? directBufferStacks : heapBufferStacks;
+ int idx = getBufferStackIndex( bufferStacks, capacity );
+ Stack stack = bufferStacks[ idx ];
+
+ java.nio.ByteBuffer buf;
+ synchronized( stack )
+ {
+ buf = ( java.nio.ByteBuffer ) stack.pop();
+ }
+
+ if( buf == null )
+ {
+ buf = direct ? java.nio.ByteBuffer.allocateDirect( MINIMUM_CAPACITY << idx ) :
+ java.nio.ByteBuffer.allocate( MINIMUM_CAPACITY << idx );
+ }
+
+ return buf;
+ }
+
+ private static void release0( java.nio.ByteBuffer buf )
+ {
+ Stack[] bufferStacks = buf.isDirect()? directBufferStacks : heapBufferStacks;
+ Stack stack = bufferStacks[ getBufferStackIndex( bufferStacks, buf.capacity() ) ];
+ synchronized( stack )
+ {
+ // push back
+ stack.push( buf );
+ }
+ }
+
+ /**
+ * Wraps the specified NIO {@link java.nio.ByteBuffer} into MINA buffer.
+ */
+ public static ByteBuffer wrap( java.nio.ByteBuffer nioBuffer )
+ {
+ DefaultByteBuffer buf = allocateContainer();
+ buf.init( nioBuffer );
+ buf.setPooled( false );
+ return buf;
+ }
+
+ /**
+ * Wraps the specified byte array into MINA heap buffer.
+ */
+ public static ByteBuffer wrap( byte[] byteArray )
+ {
+ return wrap( java.nio.ByteBuffer.wrap( byteArray ) );
+ }
+
+ /**
+ * Wraps the specified byte array into MINA heap buffer.
+ * Please note that MINA buffers are going to be pooled, and
+ * therefore there can be waste of memory if you wrap
+ * your byte array specifying <tt>offset</tt> and <tt>length</tt>.
+ */
+ public static ByteBuffer wrap( byte[] byteArray, int offset, int length )
+ {
+ return wrap( java.nio.ByteBuffer.wrap( byteArray, offset, length ) );
+ }
+
+ private static int getBufferStackIndex( Stack[] bufferStacks, int size )
+ {
+ int targetSize = MINIMUM_CAPACITY;
+ int stackIdx = 0;
+ while( size > targetSize )
+ {
+ targetSize <<= 1;
+ stackIdx ++ ;
+ if( stackIdx >= bufferStacks.length )
+ {
+ throw new IllegalArgumentException(
+ "Buffer size is too big: " + size );
+ }
+ }
+
+ return stackIdx;
+ }
+
+ protected ByteBuffer()
+ {
+ }
+
+ /**
+ * Increases the internal reference count of this buffer to defer
+ * automatic release. You have to invoke {@link #release()} as many
+ * as you invoked this method to release this buffer.
+ *
+ * @throws IllegalStateException if you attempt to acquire already
+ * released buffer.
+ */
+ public abstract void acquire();
+
+ /**
+ * Releases the specified buffer to buffer pool.
+ *
+ * @throws IllegalStateException if you attempt to release already
+ * released buffer.
+ */
+ public abstract void release();
+
+ /**
+ * Returns the underlying NIO buffer instance.
+ */
+ public abstract java.nio.ByteBuffer buf();
+
+ public abstract boolean isDirect();
+
+ public abstract int capacity();
+
+ /**
+ * Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on.
+ */
+ public abstract boolean isAutoExpand();
+
+ /**
+ * Turns on or off <tt>autoExpand</tt>.
+ */
+ public abstract ByteBuffer setAutoExpand( boolean autoExpand );
+
+ /**
+ * Returns <tt>true</tt> if and only if this buffer is returned back
+ * to the buffer pool when released.
+ * <p>
+ * The default value of this property is <tt>true</tt> if and only if you
+ * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
+ * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
+ * and {@link #wrap(java.nio.ByteBuffer)})
+ */
+ public abstract boolean isPooled();
+
+ /**
+ * Sets whether this buffer is returned back to the buffer pool when released.
+ * <p>
+ * The default value of this property is <tt>true</tt> if and only if you
+ * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
+ * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
+ * and {@link #wrap(java.nio.ByteBuffer)})
+ */
+ public abstract void setPooled( boolean pooled );
+
+ public abstract int position();
+
+ public abstract ByteBuffer position( int newPosition );
+
+ public abstract int limit();
+
+ public abstract ByteBuffer limit( int newLimit );
+
+ public abstract ByteBuffer mark();
+
+ public abstract ByteBuffer reset();
+
+ public abstract ByteBuffer clear();
+
+ public abstract ByteBuffer flip();
+
+ public abstract ByteBuffer rewind();
+
+ public abstract int remaining();
+
+ public abstract boolean hasRemaining();
+
+ public abstract byte get();
+
+ public abstract short getUnsigned();
+
+ public abstract ByteBuffer put( byte b );
+
+ public abstract byte get( int index );
+
+ public abstract short getUnsigned( int index );
+
+ public abstract ByteBuffer put( int index, byte b );
+
+ public abstract ByteBuffer get( byte[] dst, int offset, int length );
+
+ public abstract ByteBuffer get( byte[] dst );
+
+ public abstract ByteBuffer put( java.nio.ByteBuffer src );
+
+ public abstract ByteBuffer put( ByteBuffer src );
+
+ public abstract ByteBuffer put( byte[] src, int offset, int length );
+
+ public abstract ByteBuffer put( byte[] src );
+
+ public abstract ByteBuffer compact();
+
+ public abstract String toString();
+
+ public abstract int hashCode();
+
+ public abstract boolean equals( Object ob );
+
+ public abstract int compareTo( ByteBuffer that );
+
+ public abstract ByteOrder order();
+
+ public abstract ByteBuffer order( ByteOrder bo );
+
+ public abstract char getChar();
+
+ public abstract ByteBuffer putChar( char value );
+
+ public abstract char getChar( int index );
+
+ public abstract ByteBuffer putChar( int index, char value );
+
+ public abstract CharBuffer asCharBuffer();
+
+ public abstract short getShort();
+
+ public abstract int getUnsignedShort();
+
+ public abstract ByteBuffer putShort( short value );
+
+ public abstract short getShort( int index );
+
+ public abstract int getUnsignedShort( int index );
+
+ public abstract ByteBuffer putShort( int index, short value );
+
+ public abstract ShortBuffer asShortBuffer();
+
+ public abstract int getInt();
+
+ public abstract long getUnsignedInt();
+
+ public abstract ByteBuffer putInt( int value );
+
+ public abstract int getInt( int index );
+
+ public abstract long getUnsignedInt( int index );
+
+ public abstract ByteBuffer putInt( int index, int value );
+
+ public abstract IntBuffer asIntBuffer();
+
+ public abstract long getLong();
+
+ public abstract ByteBuffer putLong( long value );
+
+ public abstract long getLong( int index );
+
+ public abstract ByteBuffer putLong( int index, long value );
+
+ public abstract LongBuffer asLongBuffer();
+
+ public abstract float getFloat();
+
+ public abstract ByteBuffer putFloat( float value );
+
+ public abstract float getFloat( int index );
+
+ public abstract ByteBuffer putFloat( int index, float value );
+
+ public abstract FloatBuffer asFloatBuffer();
+
+ public abstract double getDouble();
+
+ public abstract ByteBuffer putDouble( double value );
+
+ public abstract double getDouble( int index );
+
+ public abstract ByteBuffer putDouble( int index, double value );
+
+ public abstract DoubleBuffer asDoubleBuffer();
+
+ /**
+ * Returns an {@link InputStream} that reads the data from this buffer.
+ * {@link InputStream#read()} returns <tt>-1</tt> if the buffer position
+ * reaches to the limit.
+ */
+ public InputStream asInputStream()
+ {
+ return new InputStream()
+ {
+ public int available() throws IOException
+ {
+ return ByteBuffer.this.remaining();
+ }
+
+ public synchronized void mark( int readlimit )
+ {
+ ByteBuffer.this.mark();
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public int read() throws IOException
+ {
+ if( ByteBuffer.this.hasRemaining() )
+ {
+ return ByteBuffer.this.get() & 0xff;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ public int read( byte[] b, int off, int len ) throws IOException
+ {
+ int remaining = ByteBuffer.this.remaining();
+ if( remaining > 0 )
+ {
+ int readBytes = Math.min( remaining, len );
+ ByteBuffer.this.get( b, off, readBytes );
+ return readBytes;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ public synchronized void reset() throws IOException
+ {
+ ByteBuffer.this.reset();
+ }
+
+ public long skip( long n ) throws IOException
+ {
+ int bytes;
+ if( n > Integer.MAX_VALUE )
+ {
+ bytes = ByteBuffer.this.remaining();
+ }
+ else
+ {
+ bytes = Math.min( ByteBuffer.this.remaining(), ( int ) n );
+ }
+ ByteBuffer.this.skip( bytes );
+ return bytes;
+ }
+ };
+ }
+
+ /**
+ * Returns an {@link OutputStream} that appends the data into this buffer.
+ * Please note that the {@link OutputStream#write(int)} will throw a
+ * {@link BufferOverflowException} instead of an {@link IOException}
+ * in case of buffer overflow. Please set <tt>autoExpand</tt> property by
+ * calling {@link #setAutoExpand(boolean)} to prevent the unexpected runtime
+ * exception.
+ */
+ public OutputStream asOutputStream()
+ {
+ return new OutputStream()
+ {
+ public void write( byte[] b, int off, int len ) throws IOException
+ {
+ ByteBuffer.this.put( b, off, len );
+ }
+
+ public void write( int b ) throws IOException
+ {
+ ByteBuffer.this.put( ( byte ) b );
+ }
+ };
+ }
+
+ /**
+ * Returns hexdump of this buffer.
+ */
+ public abstract String getHexDump();
+
+ ////////////////////////////////
+ // String getters and putters //
+ ////////////////////////////////
+
+ /**
+ * Reads a <code>NUL</code>-terminated string from this buffer using the
+ * specified <code>decoder</code> and returns it. This method reads
+ * until the limit of this buffer if no <tt>NUL</tt> is found.
+ */
+ public abstract String getString( CharsetDecoder decoder ) throws CharacterCodingException;
+
+ /**
+ * Reads a <code>NUL</code>-terminated string from this buffer using the
+ * specified <code>decoder</code> and returns it.
+ *
+ * @param fieldSize the maximum number of bytes to read
+ */
+ public abstract String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException;
+
+ /**
+ * Writes the content of <code>in</code> into this buffer using the
+ * specified <code>encoder</code>. This method doesn't terminate
+ * string with <tt>NUL</tt>. You have to do it by yourself.
+ *
+ * @throws BufferOverflowException if the specified string doesn't fit
+ */
+ public abstract ByteBuffer putString( CharSequence in, CharsetEncoder encoder ) throws CharacterCodingException;
+
+ /**
+ * Writes the content of <code>in</code> into this buffer as a
+ * <code>NUL</code>-terminated string using the specified
+ * <code>encoder</code>.
+ * <p>
+ * If the charset name of the encoder is UTF-16, you cannot specify
+ * odd <code>fieldSize</code>, and this method will append two
+ * <code>NUL</code>s as a terminator.
+ * <p>
+ * Please note that this method doesn't terminate with <code>NUL</code>
+ * if the input string is longer than <tt>fieldSize</tt>.
+ *
+ * @param fieldSize the maximum number of bytes to write
+ */
+ public abstract ByteBuffer putString(
+ CharSequence in, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException;
+
+ /**
+ * Reads a Pascal string which as a 16-bit length field before the actual
+ * encoded string, using the specified <code>decoder</code> and returns it.
+ */
+ public abstract String getPascalString( CharsetDecoder decoder ) throws CharacterCodingException;
+
+ /**
+ * Writes the content of <code>in</code> into this buffer as a
+ * Pascal string which has a 16-bit length field before the actual
+ * encoded string, using the specified <code>encoder</code>.
+ * This method doesn't terminate the string with <tt>NUL</tt>
+ * because we don't need to do so.
+ *
+ * @throws BufferOverflowException if the specified string doesn't fit
+ */
+ public abstract ByteBuffer putPascalString( CharSequence in, CharsetEncoder encoder ) throws CharacterCodingException;
+
+ /**
+ * Reads a Java object from the buffer using the context {@link ClassLoader}
+ * of the current thread.
+ */
+ public Object getObject() throws ClassNotFoundException
+ {
+ return getObject( Thread.currentThread().getContextClassLoader() );
+ }
+
+ /**
+ * Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
+ */
+ public abstract Object getObject( ClassLoader classLoader ) throws ClassNotFoundException;
+
+ /**
+ * Writes the specified Java object to the buffer.
+ */
+ public abstract ByteBuffer putObject( Object o );
+
+ //////////////////////////
+ // Skip or fill methods //
+ //////////////////////////
+
+ /**
+ * Forwards the position of this buffer as the specified <code>size</code>
+ * bytes.
+ */
+ public abstract ByteBuffer skip( int size );
+
+ /**
+ * Fills this buffer with the specified value.
+ * This method moves buffer position forward.
+ */
+ public abstract ByteBuffer fill( byte value, int size );
+
+ /**
+ * Fills this buffer with the specified value.
+ * This method does not change buffer position.
+ */
+ public abstract ByteBuffer fillAndReset( byte value, int size );
+
+ /**
+ * Fills this buffer with <code>NUL (0x00)</code>.
+ * This method moves buffer position forward.
+ */
+ public abstract ByteBuffer fill( int size );
+
+ /**
+ * Fills this buffer with <code>NUL (0x00)</code>.
+ * This method does not change buffer position.
+ */
+ public abstract ByteBuffer fillAndReset( int size );
+
+ private static class DefaultByteBuffer extends ByteBuffer
+ {
+ private java.nio.ByteBuffer buf;
+ private int refCount = 1;
+ private boolean autoExpand;
+ private boolean pooled;
+
+ protected DefaultByteBuffer()
+ {
+ }
+
+ private synchronized void init( java.nio.ByteBuffer buf )
+ {
+ this.buf = buf;
+ buf.clear();
+ buf.order( ByteOrder.BIG_ENDIAN );
+ autoExpand = false;
+ pooled = true;
+ refCount = 1;
+ }
+
+ public synchronized void acquire()
+ {
+ if( refCount <= 0 )
+ {
+ throw new IllegalStateException( "Already released buffer." );
+ }
+
+ refCount ++;
+ }
+
+ public void release()
+ {
+ synchronized( this )
+ {
+ if( refCount <= 0 )
+ {
+ refCount = 0;
+ throw new IllegalStateException(
+ "Already released buffer. You released the buffer too many times." );
+ }
+
+ refCount --;
+ if( refCount > 0)
+ {
+ return;
+ }
+ }
+
+ if( pooled )
+ {
+ release0( buf );
+ }
+
+ synchronized( containerStack )
+ {
+ containerStack.push( this );
+ }
+ }
+
+ public java.nio.ByteBuffer buf()
+ {
+ return buf;
+ }
+
+ public boolean isDirect()
+ {
+ return buf.isDirect();
+ }
+
+ public boolean isReadOnly()
+ {
+ return buf.isReadOnly();
+ }
+
+ public boolean isAutoExpand()
+ {
+ return autoExpand;
+ }
+
+ public ByteBuffer setAutoExpand( boolean autoExpand )
+ {
+ this.autoExpand = autoExpand;
+ return this;
+ }
+
+ public boolean isPooled()
+ {
+ return pooled;
+ }
+
+ public void setPooled( boolean pooled )
+ {
+ this.pooled = pooled;
+ }
+
+ public int capacity()
+ {
+ return buf.capacity();
+ }
+
+ public int position()
+ {
+ return buf.position();
+ }
+
+ public ByteBuffer position( int newPosition )
+ {
+ autoExpand( newPosition, 0 );
+ buf.position( newPosition );
+ return this;
+ }
+
+ public int limit()
+ {
+ return buf.limit();
+ }
+
+ public ByteBuffer limit( int newLimit )
+ {
+ autoExpand( newLimit, 0 );
+ buf.limit( newLimit );
+ return this;
+ }
+
+ public ByteBuffer mark()
+ {
+ buf.mark();
+ return this;
+ }
+
+ public ByteBuffer reset()
+ {
+ buf.reset();
+ return this;
+ }
+
+ public ByteBuffer clear()
+ {
+ buf.clear();
+ return this;
+ }
+
+ public ByteBuffer flip()
+ {
+ buf.flip();
+ return this;
+ }
+
+ public ByteBuffer rewind()
+ {
+ buf.rewind();
+ return this;
+ }
+
+ public int remaining()
+ {
+ return buf.remaining();
+ }
+
+ public boolean hasRemaining()
+ {
+ return buf.hasRemaining();
+ }
+
+ public byte get()
+ {
+ return buf.get();
+ }
+
+ public short getUnsigned()
+ {
+ return ( short ) ( get() & 0xff );
+ }
+
+ public ByteBuffer put( byte b )
+ {
+ autoExpand( 1 );
+ buf.put( b );
+ return this;
+ }
+
+ public byte get( int index )
+ {
+ return buf.get( index );
+ }
+
+ public short getUnsigned( int index )
+ {
+ return ( short ) ( get( index ) & 0xff );
+ }
+
+ public ByteBuffer put( int index, byte b )
+ {
+ autoExpand( index, 1 );
+ buf.put( index, b );
+ return this;
+ }
+
+ public ByteBuffer get( byte[] dst, int offset, int length )
+ {
+ buf.get( dst, offset, length );
+ return this;
+ }
+
+ public ByteBuffer get( byte[] dst )
+ {
+ buf.get( dst );
+ return this;
+ }
+
+ public ByteBuffer put( java.nio.ByteBuffer src )
+ {
+ autoExpand( src.remaining() );
+ buf.put( src );
+ return this;
+ }
+
+ public ByteBuffer put( ByteBuffer src )
+ {
+ autoExpand( src.remaining() );
+ buf.put( src.buf() );
+ return this;
+ }
+
+ public ByteBuffer put( byte[] src, int offset, int length )
+ {
+ autoExpand( length );
+ buf.put( src, offset, length );
+ return this;
+ }
+
+ public ByteBuffer put( byte[] src )
+ {
+ autoExpand( src.length );
+ buf.put( src );
+ return this;
+ }
+
+ public ByteBuffer compact()
+ {
+ buf.compact();
+ return this;
+ }
+
+ public String toString()
+ {
+ return buf.toString() + " (" + getHexDump() + ')';
+ }
+
+ public int hashCode()
+ {
+ return buf.hashCode();
+ }
+
+ public boolean equals( Object ob )
+ {
+ if( !( ob instanceof ByteBuffer ) )
+ return false;
+
+ ByteBuffer that = ( ByteBuffer ) ob;
+ return this.buf.equals( that.buf() );
+ }
+
+ public int compareTo( ByteBuffer that )
+ {
+ return this.buf.compareTo( that.buf() );
+ }
+
+ public ByteOrder order()
+ {
+ return buf.order();
+ }
+
+ public ByteBuffer order( ByteOrder bo )
+ {
+ buf.order( bo );
+ return this;
+ }
+
+ public char getChar()
+ {
+ return buf.getChar();
+ }
+
+ public ByteBuffer putChar( char value )
+ {
+ autoExpand( 2 );
+ buf.putChar( value );
+ return this;
+ }
+
+ public char getChar( int index )
+ {
+ return buf.getChar( index );
+ }
+
+ public ByteBuffer putChar( int index, char value )
+ {
+ autoExpand( index, 2 );
+ buf.putChar( index, value );
+ return this;
+ }
+
+ public CharBuffer asCharBuffer()
+ {
+ return buf.asCharBuffer();
+ }
+
+ public short getShort()
+ {
+ return buf.getShort();
+ }
+
+ public int getUnsignedShort()
+ {
+ return getShort() & 0xffff;
+ }
+
+ public ByteBuffer putShort( short value )
+ {
+ autoExpand( 2 );
+ buf.putShort( value );
+ return this;
+ }
+
+ public short getShort( int index )
+ {
+ return buf.getShort( index );
+ }
+
+ public int getUnsignedShort( int index )
+ {
+ return getShort( index ) & 0xffff;
+ }
+
+ public ByteBuffer putShort( int index, short value )
+ {
+ autoExpand( index, 2 );
+ buf.putShort( index, value );
+ return this;
+ }
+
+ public ShortBuffer asShortBuffer()
+ {
+ return buf.asShortBuffer();
+ }
+
+ public int getInt()
+ {
+ return buf.getInt();
+ }
+
+ public long getUnsignedInt()
+ {
+ return getInt() & 0xffffffffL;
+ }
+
+ public ByteBuffer putInt( int value )
+ {
+ autoExpand( 4 );
+ buf.putInt( value );
+ return this;
+ }
+
+ public int getInt( int index )
+ {
[... 821 lines stripped ...]