You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by el...@apache.org on 2022/01/23 03:00:04 UTC

[mina] branch 2.2.X updated: Tabs removal

This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch 2.2.X
in repository https://gitbox.apache.org/repos/asf/mina.git


The following commit(s) were added to refs/heads/2.2.X by this push:
     new 8d7e162  Tabs removal
8d7e162 is described below

commit 8d7e1628d7f421712cfa06afcac8fc45e14500a6
Author: emmanuel lecharny <el...@apache.org>
AuthorDate: Sun Jan 23 03:59:54 2022 +0100

    Tabs removal
---
 .../apache/mina/core/buffer/AbstractIoBuffer.java  | 5382 ++++++++++----------
 .../java/org/apache/mina/core/buffer/IoBuffer.java | 3920 +++++++-------
 .../apache/mina/core/buffer/IoBufferHexDumper.java |  406 +-
 .../apache/mina/core/buffer/IoBufferWrapper.java   | 2978 +++++------
 .../core/filterchain/DefaultIoFilterChain.java     |   34 +-
 .../mina/core/session/AbstractIoSession.java       |    8 +-
 .../org/apache/mina/core/session/AttributeKey.java |    2 +-
 .../mina/core/write/WriteRejectedException.java    |   94 +-
 .../codec/AbstractProtocolDecoderOutput.java       |   56 +-
 .../codec/AbstractProtocolEncoderOutput.java       |   38 +-
 .../filter/codec/CumulativeProtocolDecoder.java    |   12 +-
 .../mina/filter/codec/ProtocolCodecFilter.java     |  828 +--
 .../mina/filter/codec/ProtocolEncoderOutput.java   |   20 +-
 .../filter/executor/OrderedThreadPoolExecutor.java |   15 +-
 .../executor/PriorityThreadPoolExecutor.java       |   15 +-
 .../executor/UnorderedThreadPoolExecutor.java      |   19 +-
 .../mina/filter/ssl/BogusTrustManagerFactory.java  |  114 +-
 .../mina/filter/ssl/EncryptedWriteRequest.java     |   20 +-
 .../apache/mina/filter/ssl/KeyStoreFactory.java    |  292 +-
 .../apache/mina/filter/ssl/SSLContextFactory.java  |  728 +--
 .../java/org/apache/mina/filter/ssl/SSLEvent.java  |    2 +-
 .../java/org/apache/mina/filter/ssl/SSLFilter.java |  532 +-
 .../org/apache/mina/filter/ssl/SSLHandler.java     |  476 +-
 .../org/apache/mina/filter/ssl/SSLHandlerG0.java   | 1210 ++---
 .../mina/filter/statistic/ProfilerTimerFilter.java |  902 ++--
 .../proxy/handlers/http/ntlm/NTLMUtilities.java    |   10 +-
 .../transport/socket/nio/NioDatagramAcceptor.java  |   58 +-
 .../transport/socket/nio/NioSocketAcceptor.java    |   20 +-
 .../transport/socket/nio/NioSocketSession.java     |  600 +--
 .../org/apache/mina/util/BasicThreadFactory.java   |   47 +-
 .../java/org/apache/mina/util/StackInspector.java  |   78 +-
 .../mina/core/buffer/IoBufferHexDumperTest.java    |   75 +-
 .../filter/codec/ParallelProtocolEncoderTest.java  |  316 +-
 .../org/apache/mina/filter/ssl/SSLFilterMain.java  |  134 +-
 .../apache/mina/transport/AbstractBindTest.java    |   14 +-
 .../java/org/apache/mina/example/chat/Main.java    |    2 +-
 .../org/apache/mina/example/echoserver/Main.java   |    2 +-
 .../mina/example/echoserver/ssl/SSLFilterTest.java |  274 +-
 .../org/apache/mina/http/HttpServerDecoder.java    |   18 +-
 .../apache/mina/http/HttpServerDecoderTest.java    |  578 +--
 .../mina/integration/xbean/datagramAcceptor.xml    |    6 +-
 .../mina/transport/socket/apr/AprIoProcessor.java  |    2 +-
 mina-transport-serial/LICENSE.rxtx.txt             |   12 +-
 pom.xml                                            |   74 +-
 44 files changed, 10231 insertions(+), 10192 deletions(-)

diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
index 15ac0ed..245fe40 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
@@ -56,2695 +56,2695 @@ import java.util.Set;
  * @see IoBufferAllocator
  */
 public abstract class AbstractIoBuffer extends IoBuffer {
-	/** Tells if a buffer has been created from an existing buffer */
-	private final boolean derived;
-
-	/** A flag set to true if the buffer can extend automatically */
-	private boolean autoExpand;
-
-	/** A flag set to true if the buffer can shrink automatically */
-	private boolean autoShrink;
-
-	/** Tells if a buffer can be expanded */
-	private boolean recapacityAllowed = true;
-
-	/** The minimum number of bytes the IoBuffer can hold */
-	private int minimumCapacity;
-
-	/** A mask for a byte */
-	private static final long BYTE_MASK = 0xFFL;
-
-	/** A mask for a short */
-	private static final long SHORT_MASK = 0xFFFFL;
-
-	/** A mask for an int */
-	private static final long INT_MASK = 0xFFFFFFFFL;
-
-	/**
-	 * We don't have any access to Buffer.markValue(), so we need to track it down,
-	 * which will cause small extra overhead.
-	 */
-	private int mark = -1;
-
-	/**
-	 * Creates a new parent buffer.
-	 * 
-	 * @param allocator       The allocator to use to create new buffers
-	 * @param initialCapacity The initial buffer capacity when created
-	 */
-	protected AbstractIoBuffer(IoBufferAllocator allocator, int initialCapacity) {
-		setAllocator(allocator);
-		this.recapacityAllowed = true;
-		this.derived = false;
-		this.minimumCapacity = initialCapacity;
-	}
-
-	/**
-	 * Creates a new derived buffer. A derived buffer uses an existing buffer
-	 * properties - the allocator and capacity -.
-	 * 
-	 * @param parent The buffer we get the properties from
-	 */
-	protected AbstractIoBuffer(AbstractIoBuffer parent) {
-		setAllocator(IoBuffer.getAllocator());
-		this.recapacityAllowed = false;
-		this.derived = true;
-		this.minimumCapacity = parent.minimumCapacity;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final boolean isDirect() {
-		return buf().isDirect();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final boolean isReadOnly() {
-		return buf().isReadOnly();
-	}
-
-	/**
-	 * Sets the underlying NIO buffer instance.
-	 * 
-	 * @param newBuf The buffer to store within this IoBuffer
-	 */
-	protected abstract void buf(ByteBuffer newBuf);
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int minimumCapacity() {
-		return minimumCapacity;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer minimumCapacity(int minimumCapacity) {
-		if (minimumCapacity < 0) {
-			throw new IllegalArgumentException("minimumCapacity: " + minimumCapacity);
-		}
-		this.minimumCapacity = minimumCapacity;
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int capacity() {
-		return buf().capacity();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer capacity(int newCapacity) {
-		if (!recapacityAllowed) {
-			throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
-		}
-
-		// Allocate a new buffer and transfer all settings to it.
-		if (newCapacity > capacity()) {
-			// Expand:
-			//// Save the state.
-			int pos = position();
-			int limit = limit();
-			ByteOrder bo = order();
-
-			//// Reallocate.
-			ByteBuffer oldBuf = buf();
-			ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
-			oldBuf.clear();
-			newBuf.put(oldBuf);
-			buf(newBuf);
-
-			//// Restore the state.
-			buf().limit(limit);
-			if (mark >= 0) {
-				buf().position(mark);
-				buf().mark();
-			}
-			buf().position(pos);
-			buf().order(bo);
-		}
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final boolean isAutoExpand() {
-		return autoExpand && recapacityAllowed;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final boolean isAutoShrink() {
-		return autoShrink && recapacityAllowed;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final boolean isDerived() {
-		return derived;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer setAutoExpand(boolean autoExpand) {
-		if (!recapacityAllowed) {
-			throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
-		}
-		this.autoExpand = autoExpand;
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer setAutoShrink(boolean autoShrink) {
-		if (!recapacityAllowed) {
-			throw new IllegalStateException("Derived buffers and their parent can't be shrinked.");
-		}
-		this.autoShrink = autoShrink;
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer expand(int expectedRemaining) {
-		return expand(position(), expectedRemaining, false);
-	}
-
-	private IoBuffer expand(int expectedRemaining, boolean autoExpand) {
-		return expand(position(), expectedRemaining, autoExpand);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer expand(int pos, int expectedRemaining) {
-		return expand(pos, expectedRemaining, false);
-	}
-
-	private IoBuffer expand(int pos, int expectedRemaining, boolean autoExpand) {
-		if (!recapacityAllowed) {
-			throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
-		}
-
-		int end = pos + expectedRemaining;
-		int newCapacity;
-
-		if (autoExpand) {
-			newCapacity = IoBuffer.normalizeCapacity(end);
-		} else {
-			newCapacity = end;
-		}
-		if (newCapacity > capacity()) {
-			// The buffer needs expansion.
-			capacity(newCapacity);
-		}
-
-		if (end > limit()) {
-			// We call limit() directly to prevent StackOverflowError
-			buf().limit(end);
-		}
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer shrink() {
-
-		if (!recapacityAllowed) {
-			throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
-		}
-
-		int position = position();
-		int capacity = capacity();
-		int limit = limit();
-
-		if (capacity == limit) {
-			return this;
-		}
-
-		int newCapacity = capacity;
-		int minCapacity = Math.max(minimumCapacity, limit);
-
-		for (;;) {
-			if (newCapacity >>> 1 < minCapacity) {
-				break;
-			}
-
-			newCapacity >>>= 1;
-
-			if (minCapacity == 0) {
-				break;
-			}
-		}
-
-		newCapacity = Math.max(minCapacity, newCapacity);
-
-		if (newCapacity == capacity) {
-			return this;
-		}
-
-		// Shrink and compact:
-		//// Save the state.
-		ByteOrder bo = order();
-
-		//// Reallocate.
-		ByteBuffer oldBuf = buf();
-		ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
-		oldBuf.position(0);
-		oldBuf.limit(limit);
-		newBuf.put(oldBuf);
-		buf(newBuf);
-
-		//// Restore the state.
-		buf().position(position);
-		buf().limit(limit);
-		buf().order(bo);
-		mark = -1;
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int position() {
-		return buf().position();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer position(int newPosition) {
-		autoExpand(newPosition, 0);
-		buf().position(newPosition);
-
-		if (mark > newPosition) {
-			mark = -1;
-		}
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int limit() {
-		return buf().limit();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer limit(int newLimit) {
-		autoExpand(newLimit, 0);
-		buf().limit(newLimit);
-		if (mark > newLimit) {
-			mark = -1;
-		}
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer mark() {
-		ByteBuffer byteBuffer = buf();
-		byteBuffer.mark();
-		mark = byteBuffer.position();
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int markValue() {
-		return mark;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer reset() {
-		buf().reset();
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer clear() {
-		buf().clear();
-		mark = -1;
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer sweep() {
-		clear();
-		return fillAndReset(remaining());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer sweep(byte value) {
-		clear();
-		return fillAndReset(value, remaining());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer flip() {
-		buf().flip();
-		mark = -1;
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer rewind() {
-		buf().rewind();
-		mark = -1;
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int remaining() {
-		ByteBuffer byteBuffer = buf();
-
-		return byteBuffer.limit() - byteBuffer.position();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final boolean hasRemaining() {
-		ByteBuffer byteBuffer = buf();
-
-		return byteBuffer.limit() > byteBuffer.position();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final byte get() {
-		return buf().get();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final short getUnsigned() {
-		return (short) (get() & 0xff);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer put(byte b) {
-		autoExpand(1);
-		buf().put(b);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(byte value) {
-		autoExpand(1);
-		buf().put((byte) (value & 0xff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(int index, byte value) {
-		autoExpand(index, 1);
-		buf().put(index, (byte) (value & 0xff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(short value) {
-		autoExpand(1);
-		buf().put((byte) (value & 0x00ff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(int index, short value) {
-		autoExpand(index, 1);
-		buf().put(index, (byte) (value & 0x00ff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(int value) {
-		autoExpand(1);
-		buf().put((byte) (value & 0x000000ff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(int index, int value) {
-		autoExpand(index, 1);
-		buf().put(index, (byte) (value & 0x000000ff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(long value) {
-		autoExpand(1);
-		buf().put((byte) (value & 0x00000000000000ffL));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putUnsigned(int index, long value) {
-		autoExpand(index, 1);
-		buf().put(index, (byte) (value & 0x00000000000000ffL));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final byte get(int index) {
-		return buf().get(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final short getUnsigned(int index) {
-		return (short) (get(index) & 0xff);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer put(int index, byte b) {
-		autoExpand(index, 1);
-		buf().put(index, b);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer get(byte[] dst, int offset, int length) {
-		buf().get(dst, offset, length);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer put(ByteBuffer src) {
-		autoExpand(src.remaining());
-		buf().put(src);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer put(byte[] src, int offset, int length) {
-		autoExpand(length);
-		buf().put(src, offset, length);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer compact() {
-		int remaining = remaining();
-		int capacity = capacity();
-
-		if (capacity == 0) {
-			return this;
-		}
-
-		if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > minimumCapacity) {
-			int newCapacity = capacity;
-			int minCapacity = Math.max(minimumCapacity, remaining << 1);
-			for (;;) {
-				if (newCapacity >>> 1 < minCapacity) {
-					break;
-				}
-				newCapacity >>>= 1;
-			}
-
-			newCapacity = Math.max(minCapacity, newCapacity);
-
-			if (newCapacity == capacity) {
-				return this;
-			}
-
-			// Shrink and compact:
-			//// Save the state.
-			ByteOrder bo = order();
-
-			//// Sanity check.
-			if (remaining > newCapacity) {
-				throw new IllegalStateException(
-						"The amount of the remaining bytes is greater than " + "the new capacity.");
-			}
-
-			//// Reallocate.
-			ByteBuffer oldBuf = buf();
-			ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
-			newBuf.put(oldBuf);
-			buf(newBuf);
-
-			//// Restore the state.
-			buf().order(bo);
-		} else {
-			buf().compact();
-		}
-		mark = -1;
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final ByteOrder order() {
-		return buf().order();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer order(ByteOrder bo) {
-		buf().order(bo);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final char getChar() {
-		return buf().getChar();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putChar(char value) {
-		autoExpand(2);
-		buf().putChar(value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final char getChar(int index) {
-		return buf().getChar(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putChar(int index, char value) {
-		autoExpand(index, 2);
-		buf().putChar(index, value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final CharBuffer asCharBuffer() {
-		return buf().asCharBuffer();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final short getShort() {
-		return buf().getShort();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putShort(short value) {
-		autoExpand(2);
-		buf().putShort(value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final short getShort(int index) {
-		return buf().getShort(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putShort(int index, short value) {
-		autoExpand(index, 2);
-		buf().putShort(index, value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final ShortBuffer asShortBuffer() {
-		return buf().asShortBuffer();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int getInt() {
-		return buf().getInt();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putInt(int value) {
-		autoExpand(4);
-		buf().putInt(value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(byte value) {
-		autoExpand(4);
-		buf().putInt(value & 0x00ff);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(int index, byte value) {
-		autoExpand(index, 4);
-		buf().putInt(index, value & 0x00ff);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(short value) {
-		autoExpand(4);
-		buf().putInt(value & 0x0000ffff);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(int index, short value) {
-		autoExpand(index, 4);
-		buf().putInt(index, value & 0x0000ffff);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(int value) {
-		return putInt(value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(int index, int value) {
-		return putInt(index, value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(long value) {
-		autoExpand(4);
-		buf().putInt((int) (value & 0x00000000ffffffff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedInt(int index, long value) {
-		autoExpand(index, 4);
-		buf().putInt(index, (int) (value & 0x00000000ffffffffL));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(byte value) {
-		autoExpand(2);
-		buf().putShort((short) (value & 0x00ff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(int index, byte value) {
-		autoExpand(index, 2);
-		buf().putShort(index, (short) (value & 0x00ff));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(short value) {
-		return putShort(value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(int index, short value) {
-		return putShort(index, value);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(int value) {
-		autoExpand(2);
-		buf().putShort((short) value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(int index, int value) {
-		autoExpand(index, 2);
-		buf().putShort(index, (short) value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(long value) {
-		autoExpand(2);
-		buf().putShort((short) (value));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putUnsignedShort(int index, long value) {
-		autoExpand(index, 2);
-		buf().putShort(index, (short) (value));
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final int getInt(int index) {
-		return buf().getInt(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putInt(int index, int value) {
-		autoExpand(index, 4);
-		buf().putInt(index, value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IntBuffer asIntBuffer() {
-		return buf().asIntBuffer();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final long getLong() {
-		return buf().getLong();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putLong(long value) {
-		autoExpand(8);
-		buf().putLong(value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final long getLong(int index) {
-		return buf().getLong(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putLong(int index, long value) {
-		autoExpand(index, 8);
-		buf().putLong(index, value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final LongBuffer asLongBuffer() {
-		return buf().asLongBuffer();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final float getFloat() {
-		return buf().getFloat();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putFloat(float value) {
-		autoExpand(4);
-		buf().putFloat(value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final float getFloat(int index) {
-		return buf().getFloat(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putFloat(int index, float value) {
-		autoExpand(index, 4);
-		buf().putFloat(index, value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final FloatBuffer asFloatBuffer() {
-		return buf().asFloatBuffer();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final double getDouble() {
-		return buf().getDouble();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putDouble(double value) {
-		autoExpand(8);
-		buf().putDouble(value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final double getDouble(int index) {
-		return buf().getDouble(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer putDouble(int index, double value) {
-		autoExpand(index, 8);
-		buf().putDouble(index, value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final DoubleBuffer asDoubleBuffer() {
-		return buf().asDoubleBuffer();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer asReadOnlyBuffer() {
-		recapacityAllowed = false;
-		return asReadOnlyBuffer0();
-	}
-
-	/**
-	 * Implement this method to return the unexpandable read only version of this
-	 * buffer.
-	 * 
-	 * @return the IoBoffer instance
-	 */
-	protected abstract IoBuffer asReadOnlyBuffer0();
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer duplicate() {
-		recapacityAllowed = false;
-		return duplicate0();
-	}
-
-	/**
-	 * Implement this method to return the unexpandable duplicate of this buffer.
-	 * 
-	 * @return the IoBoffer instance
-	 */
-	protected abstract IoBuffer duplicate0();
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer slice() {
-		recapacityAllowed = false;
-		return slice0();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer getSlice(int index, int length) {
-		if (length < 0) {
-			throw new IllegalArgumentException("length: " + length);
-		}
-
-		int pos = position();
-		int limit = limit();
-
-		if (index > limit) {
-			throw new IllegalArgumentException("index: " + index);
-		}
-
-		int endIndex = index + length;
-
-		if (endIndex > limit) {
-			throw new IndexOutOfBoundsException(
-					"index + length (" + endIndex + ") is greater " + "than limit (" + limit + ").");
-		}
-
-		clear();
-		limit(endIndex);
-		position(index);
-
-		IoBuffer slice = slice();
-		limit(limit);
-		position(pos);
-
-		return slice;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public final IoBuffer getSlice(int length) {
-		if (length < 0) {
-			throw new IllegalArgumentException("length: " + length);
-		}
-		int pos = position();
-		int limit = limit();
-		int nextPos = pos + length;
-		if (limit < nextPos) {
-			throw new IndexOutOfBoundsException(
-					"position + length (" + nextPos + ") is greater " + "than limit (" + limit + ").");
-		}
-
-		limit(pos + length);
-		IoBuffer slice = slice();
-		position(nextPos);
-		limit(limit);
-		return slice;
-	}
-
-	/**
-	 * Implement this method to return the unexpandable slice of this buffer.
-	 * 
-	 * @return the IoBoffer instance
-	 */
-	protected abstract IoBuffer slice0();
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int hashCode() {
-		int h = 1;
-		int p = position();
-		for (int i = limit() - 1; i >= p; i--) {
-			h = 31 * h + get(i);
-		}
-		return h;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public boolean equals(Object o) {
-		if (!(o instanceof IoBuffer)) {
-			return false;
-		}
-
-		IoBuffer that = (IoBuffer) o;
-		if (this.remaining() != that.remaining()) {
-			return false;
-		}
-
-		int p = this.position();
-		for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
-			byte v1 = this.get(i);
-			byte v2 = that.get(j);
-			if (v1 != v2) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int compareTo(IoBuffer that) {
-		int n = this.position() + Math.min(this.remaining(), that.remaining());
-		for (int i = this.position(), j = that.position(); i < n; i++, j++) {
-			byte v1 = this.get(i);
-			byte v2 = that.get(j);
-			if (v1 == v2) {
-				continue;
-			}
-			if (v1 < v2) {
-				return -1;
-			}
-
-			return +1;
-		}
-		return this.remaining() - that.remaining();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public String toString() {
-		StringBuilder buf = new StringBuilder();
-		if (isDirect()) {
-			buf.append("DirectBuffer");
-		} else {
-			buf.append("HeapBuffer");
-		}
-		buf.append("@");
-		buf.append(Integer.toHexString(super.hashCode()));
-		buf.append("[pos=");
-		buf.append(position());
-		buf.append(" lim=");
-		buf.append(limit());
-		buf.append(" cap=");
-		buf.append(capacity());
-		buf.append(": ");
-		buf.append(getHexDump(16));
-		buf.append(']');
-		return buf.toString();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer get(byte[] dst) {
-		return get(dst, 0, dst.length);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer put(IoBuffer src) {
-		return put(src.buf());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer put(byte[] src) {
-		return put(src, 0, src.length);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int getUnsignedShort() {
-		return getShort() & 0xffff;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int getUnsignedShort(int index) {
-		return getShort(index) & 0xffff;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public long getUnsignedInt() {
-		return getInt() & 0xffffffffL;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int getMediumInt() {
-		byte b1 = get();
-		byte b2 = get();
-		byte b3 = get();
-		if (ByteOrder.BIG_ENDIAN.equals(order())) {
-			return getMediumInt(b1, b2, b3);
-		}
-
-		return getMediumInt(b3, b2, b1);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int getUnsignedMediumInt() {
-		int b1 = getUnsigned();
-		int b2 = getUnsigned();
-		int b3 = getUnsigned();
-		if (ByteOrder.BIG_ENDIAN.equals(order())) {
-			return b1 << 16 | b2 << 8 | b3;
-		}
-
-		return b3 << 16 | b2 << 8 | b1;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int getMediumInt(int index) {
-		byte b1 = get(index);
-		byte b2 = get(index + 1);
-		byte b3 = get(index + 2);
-		if (ByteOrder.BIG_ENDIAN.equals(order())) {
-			return getMediumInt(b1, b2, b3);
-		}
-
-		return getMediumInt(b3, b2, b1);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int getUnsignedMediumInt(int index) {
-		int b1 = getUnsigned(index);
-		int b2 = getUnsigned(index + 1);
-		int b3 = getUnsigned(index + 2);
-
-		if (ByteOrder.BIG_ENDIAN.equals(order())) {
-			return b1 << 16 | b2 << 8 | b3;
-		}
-
-		return b3 << 16 | b2 << 8 | b1;
-	}
-
-	private int getMediumInt(byte b1, byte b2, byte b3) {
-		int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff;
-		// Check to see if the medium int is negative (high bit in b1 set)
-		if ((b1 & 0x80) == 0x80) {
-			// Make the the whole int negative
-			ret |= 0xff000000;
-		}
-		return ret;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putMediumInt(int value) {
-		byte b1 = (byte) (value >> 16);
-		byte b2 = (byte) (value >> 8);
-		byte b3 = (byte) value;
-
-		if (ByteOrder.BIG_ENDIAN.equals(order())) {
-			put(b1).put(b2).put(b3);
-		} else {
-			put(b3).put(b2).put(b1);
-		}
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putMediumInt(int index, int value) {
-		byte b1 = (byte) (value >> 16);
-		byte b2 = (byte) (value >> 8);
-		byte b3 = (byte) value;
-
-		if (ByteOrder.BIG_ENDIAN.equals(order())) {
-			put(index, b1).put(index + 1, b2).put(index + 2, b3);
-		} else {
-			put(index, b3).put(index + 1, b2).put(index + 2, b1);
-		}
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public long getUnsignedInt(int index) {
-		return getInt(index) & 0xffffffffL;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public InputStream asInputStream() {
-		return new InputStream() {
-			@Override
-			public int available() {
-				return AbstractIoBuffer.this.remaining();
-			}
-
-			@Override
-			public synchronized void mark(int readlimit) {
-				AbstractIoBuffer.this.mark();
-			}
-
-			@Override
-			public boolean markSupported() {
-				return true;
-			}
-
-			@Override
-			public int read() {
-				if (AbstractIoBuffer.this.hasRemaining()) {
-					return AbstractIoBuffer.this.get() & 0xff;
-				}
-
-				return -1;
-			}
-
-			@Override
-			public int read(byte[] b, int off, int len) {
-				int remaining = AbstractIoBuffer.this.remaining();
-				if (remaining > 0) {
-					int readBytes = Math.min(remaining, len);
-					AbstractIoBuffer.this.get(b, off, readBytes);
-					return readBytes;
-				}
-
-				return -1;
-			}
-
-			@Override
-			public synchronized void reset() {
-				AbstractIoBuffer.this.reset();
-			}
-
-			@Override
-			public long skip(long n) {
-				int bytes;
-				if (n > Integer.MAX_VALUE) {
-					bytes = AbstractIoBuffer.this.remaining();
-				} else {
-					bytes = Math.min(AbstractIoBuffer.this.remaining(), (int) n);
-				}
-				AbstractIoBuffer.this.skip(bytes);
-				return bytes;
-			}
-		};
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public OutputStream asOutputStream() {
-		return new OutputStream() {
-			@Override
-			public void write(byte[] b, int off, int len) {
-				AbstractIoBuffer.this.put(b, off, len);
-			}
-
-			@Override
-			public void write(int b) {
-				AbstractIoBuffer.this.put((byte) b);
-			}
-		};
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public String getString(CharsetDecoder decoder) throws CharacterCodingException {
-		if (!hasRemaining()) {
-			return "";
-		}
-
-		boolean utf16 = decoder.charset().equals(StandardCharsets.UTF_16)
-				|| decoder.charset().equals(StandardCharsets.UTF_16BE)
-				|| decoder.charset().equals(StandardCharsets.UTF_16LE);
-
-		int oldPos = position();
-		int oldLimit = limit();
-		int end = -1;
-		int newPos;
-
-		if (!utf16) {
-			end = indexOf((byte) 0x00);
-			if (end < 0) {
-				newPos = end = oldLimit;
-			} else {
-				newPos = end + 1;
-			}
-		} else {
-			int i = oldPos;
-			for (;;) {
-				boolean wasZero = get(i) == 0;
-				i++;
-
-				if (i >= oldLimit) {
-					break;
-				}
-
-				if (get(i) != 0) {
-					i++;
-					if (i >= oldLimit) {
-						break;
-					}
-
-					continue;
-				}
-
-				if (wasZero) {
-					end = i - 1;
-					break;
-				}
-			}
-
-			if (end < 0) {
-				newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE);
-			} else {
-				if (end + 2 <= oldLimit) {
-					newPos = end + 2;
-				} else {
-					newPos = end;
-				}
-			}
-		}
-
-		if (oldPos == end) {
-			position(newPos);
-			return "";
-		}
-
-		limit(end);
-		decoder.reset();
-
-		int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
-		CharBuffer out = CharBuffer.allocate(expectedLength);
-		for (;;) {
-			CoderResult cr;
-			if (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;
-			}
-
-			if (cr.isError()) {
-				// Revert the buffer back to the previous state.
-				limit(oldLimit);
-				position(oldPos);
-				cr.throwException();
-			}
-		}
-
-		limit(oldLimit);
-		position(newPos);
-		return out.flip().toString();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException {
-		checkFieldSize(fieldSize);
-
-		if (fieldSize == 0) {
-			return "";
-		}
-
-		if (!hasRemaining()) {
-			return "";
-		}
-
-		boolean utf16 = decoder.charset().equals(StandardCharsets.UTF_16)
-				|| decoder.charset().equals(StandardCharsets.UTF_16BE)
-				|| decoder.charset().equals(StandardCharsets.UTF_16LE);
-
-		if (utf16 && (fieldSize & 1) != 0) {
-			throw new IllegalArgumentException("fieldSize is not even.");
-		}
-
-		int oldPos = position();
-		int oldLimit = limit();
-		int end = oldPos + fieldSize;
-
-		if (oldLimit < end) {
-			throw new BufferUnderflowException();
-		}
-
-		int i;
-
-		if (!utf16) {
-			for (i = oldPos; i < end; i++) {
-				if (get(i) == 0) {
-					break;
-				}
-			}
-
-			if (i == end) {
-				limit(end);
-			} else {
-				limit(i);
-			}
-		} else {
-			for (i = oldPos; i < end; i += 2) {
-				if (get(i) == 0 && get(i + 1) == 0) {
-					break;
-				}
-			}
-
-			if (i == end) {
-				limit(end);
-			} else {
-				limit(i);
-			}
-		}
-
-		if (!hasRemaining()) {
-			limit(oldLimit);
-			position(end);
-			return "";
-		}
-		decoder.reset();
-
-		int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
-		CharBuffer out = CharBuffer.allocate(expectedLength);
-		for (;;) {
-			CoderResult cr;
-			if (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;
-			}
-
-			if (cr.isError()) {
-				// Revert the buffer back to the previous state.
-				limit(oldLimit);
-				position(oldPos);
-				cr.throwException();
-			}
-		}
-
-		limit(oldLimit);
-		position(end);
-		return out.flip().toString();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putString(CharSequence val, CharsetEncoder encoder) throws CharacterCodingException {
-		if (val.length() == 0) {
-			return this;
-		}
-
-		CharBuffer in = CharBuffer.wrap(val);
-		encoder.reset();
-
-		int expandedState = 0;
-
-		for (;;) {
-			CoderResult cr;
-			if (in.hasRemaining()) {
-				cr = encoder.encode(in, buf(), true);
-			} else {
-				cr = encoder.flush(buf());
-			}
-
-			if (cr.isUnderflow()) {
-				break;
-			}
-			if (cr.isOverflow()) {
-				if (isAutoExpand()) {
-					switch (expandedState) {
-					case 0:
-						autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
-						expandedState++;
-						break;
-					case 1:
-						autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
-						expandedState++;
-						break;
-					default:
-						throw new RuntimeException(
-								"Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
-										+ " but that wasn't enough for '" + val + "'");
-					}
-					continue;
-				}
-			} else {
-				expandedState = 0;
-			}
-			cr.throwException();
-		}
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder) throws CharacterCodingException {
-		checkFieldSize(fieldSize);
-
-		if (fieldSize == 0) {
-			return this;
-		}
-
-		autoExpand(fieldSize);
-
-		boolean utf16 = encoder.charset().equals(StandardCharsets.UTF_16)
-				|| encoder.charset().equals(StandardCharsets.UTF_16BE)
-				|| encoder.charset().equals(StandardCharsets.UTF_16LE);
-
-		if (utf16 && (fieldSize & 1) != 0) {
-			throw new IllegalArgumentException("fieldSize is not even.");
-		}
-
-		int oldLimit = limit();
-		int end = position() + fieldSize;
-
-		if (oldLimit < end) {
-			throw new BufferOverflowException();
-		}
-
-		if (val.length() == 0) {
-			if (!utf16) {
-				put((byte) 0x00);
-			} else {
-				put((byte) 0x00);
-				put((byte) 0x00);
-			}
-			position(end);
-			return this;
-		}
-
-		CharBuffer in = CharBuffer.wrap(val);
-		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();
-		}
-
-		limit(oldLimit);
-
-		if (position() < end) {
-			if (!utf16) {
-				put((byte) 0x00);
-			} else {
-				put((byte) 0x00);
-				put((byte) 0x00);
-			}
-		}
-
-		position(end);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException {
-		return getPrefixedString(2, decoder);
-	}
-
-	/**
-	 * Reads a string which has a length field before the actual encoded string,
-	 * using the specified <code>decoder</code> and returns it.
-	 *
-	 * @param prefixLength the length of the length field (1, 2, or 4)
-	 * @param decoder      the decoder to use for decoding the string
-	 * @return the prefixed string
-	 * @throws CharacterCodingException when decoding fails
-	 * @throws BufferUnderflowException when there is not enough data available
-	 */
-	@Override
-	public String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException {
-		if (!prefixedDataAvailable(prefixLength)) {
-			throw new BufferUnderflowException();
-		}
-
-		int fieldSize = 0;
-
-		switch (prefixLength) {
-		case 1:
-			fieldSize = getUnsigned();
-			break;
-		case 2:
-			fieldSize = getUnsignedShort();
-			break;
-		case 4:
-			fieldSize = getInt();
-			break;
-		}
-
-		if (fieldSize == 0) {
-			return "";
-		}
-
-		boolean utf16 = decoder.charset().equals(StandardCharsets.UTF_16)
-				|| decoder.charset().equals(StandardCharsets.UTF_16BE)
-				|| decoder.charset().equals(StandardCharsets.UTF_16LE);
-
-		if (utf16 && (fieldSize & 1) != 0) {
-			throw new BufferDataException("fieldSize is not even for a UTF-16 string.");
-		}
-
-		int oldLimit = limit();
-		int end = position() + fieldSize;
-
-		if (oldLimit < end) {
-			throw new BufferUnderflowException();
-		}
-
-		limit(end);
-		decoder.reset();
-
-		int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
-		CharBuffer out = CharBuffer.allocate(expectedLength);
-		for (;;) {
-			CoderResult cr;
-			if (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();
-		}
-
-		limit(oldLimit);
-		position(end);
-		return out.flip().toString();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException {
-		return putPrefixedString(in, 2, 0, encoder);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
-			throws CharacterCodingException {
-		return putPrefixedString(in, prefixLength, 0, encoder);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder)
-			throws CharacterCodingException {
-		return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue,
-			CharsetEncoder encoder) throws CharacterCodingException {
-		int maxLength;
-		switch (prefixLength) {
-		case 1:
-			maxLength = 255;
-			break;
-		case 2:
-			maxLength = 65535;
-			break;
-		case 4:
-			maxLength = Integer.MAX_VALUE;
-			break;
-		default:
-			throw new IllegalArgumentException("prefixLength: " + prefixLength);
-		}
-
-		if (val.length() > maxLength) {
-			throw new IllegalArgumentException("The specified string is too long.");
-		}
-		if (val.length() == 0) {
-			switch (prefixLength) {
-			case 1:
-				put((byte) 0);
-				break;
-			case 2:
-				putShort((short) 0);
-				break;
-			case 4:
-				putInt(0);
-				break;
-			}
-			return this;
-		}
-
-		int padMask;
-		switch (padding) {
-		case 0:
-		case 1:
-			padMask = 0;
-			break;
-		case 2:
-			padMask = 1;
-			break;
-		case 4:
-			padMask = 3;
-			break;
-		default:
-			throw new IllegalArgumentException("padding: " + padding);
-		}
-
-		CharBuffer in = CharBuffer.wrap(val);
-		skip(prefixLength); // make a room for the length field
-		int oldPos = position();
-		encoder.reset();
-
-		int expandedState = 0;
-
-		for (;;) {
-			CoderResult cr;
-			if (in.hasRemaining()) {
-				cr = encoder.encode(in, buf(), true);
-			} else {
-				cr = encoder.flush(buf());
-			}
-
-			if (position() - oldPos > maxLength) {
-				throw new IllegalArgumentException("The specified string is too long.");
-			}
-
-			if (cr.isUnderflow()) {
-				break;
-			}
-			if (cr.isOverflow()) {
-				if (isAutoExpand()) {
-					switch (expandedState) {
-					case 0:
-						autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
-						expandedState++;
-						break;
-					case 1:
-						autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
-						expandedState++;
-						break;
-					default:
-						throw new RuntimeException(
-								"Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
-										+ " but that wasn't enough for '" + val + "'");
-					}
-					continue;
-				}
-			} else {
-				expandedState = 0;
-			}
-			cr.throwException();
-		}
-
-		// Write the length field
-		fill(padValue, padding - (position() - oldPos & padMask));
-		int length = position() - oldPos;
-		switch (prefixLength) {
-		case 1:
-			put(oldPos - 1, (byte) length);
-			break;
-		case 2:
-			putShort(oldPos - 2, (short) length);
-			break;
-		case 4:
-			putInt(oldPos - 4, length);
-			break;
-		}
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Object getObject() throws ClassNotFoundException {
-		return getObject(Thread.currentThread().getContextClassLoader());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Object getObject(final ClassLoader classLoader) throws ClassNotFoundException {
-		if (!prefixedDataAvailable(4)) {
-			throw new BufferUnderflowException();
-		}
-
-		int length = getInt();
-		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()) {
-			@Override
-			protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
-				int type = read();
-				if (type < 0) {
-					throw new EOFException();
-				}
-				switch (type) {
-				case 0: // NON-Serializable class or Primitive types
-					return super.readClassDescriptor();
-				case 1: // Serializable class
-					String className = readUTF();
-					Class<?> clazz = Class.forName(className, true, classLoader);
-					return ObjectStreamClass.lookup(clazz);
-				default:
-					throw new StreamCorruptedException("Unexpected class descriptor type: " + type);
-				}
-			}
-
-			@Override
-			protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
-				Class<?> clazz = desc.forClass();
-
-				if (clazz == null) {
-					String name = desc.getName();
-					try {
-						return Class.forName(name, false, classLoader);
-					} catch (ClassNotFoundException ex) {
-						return super.resolveClass(desc);
-					}
-				} else {
-					return clazz;
-				}
-			}
-		}) {
-			return in.readObject();
-		} catch (IOException e) {
-			throw new BufferDataException(e);
-		} finally {
-			limit(oldLimit);
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putObject(Object o) {
-		int oldPos = position();
-		skip(4); // Make a room for the length field.
-
-		try (ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
-			@Override
-			protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
-				Class<?> clazz = desc.forClass();
-
-				if (clazz.isArray() || clazz.isPrimitive() || !Serializable.class.isAssignableFrom(clazz)) {
-					write(0);
-					super.writeClassDescriptor(desc);
-				} else {
-					// Serializable class
-					write(1);
-					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;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public boolean prefixedDataAvailable(int prefixLength) {
-		return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
-		if (remaining() < prefixLength) {
-			return false;
-		}
-
-		int dataLength;
-		switch (prefixLength) {
-		case 1:
-			dataLength = getUnsigned(position());
-			break;
-		case 2:
-			dataLength = getUnsignedShort(position());
-			break;
-		case 4:
-			dataLength = getInt(position());
-			break;
-		default:
-			throw new IllegalArgumentException("prefixLength: " + prefixLength);
-		}
-
-		if (dataLength < 0 || dataLength > maxDataLength) {
-			throw new BufferDataException("dataLength: " + dataLength);
-		}
-
-		return remaining() - prefixLength >= dataLength;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int indexOf(byte b) {
-		if (hasArray()) {
-			int arrayOffset = arrayOffset();
-			int beginPos = arrayOffset + position();
-			int limit = arrayOffset + limit();
-			byte[] array = array();
-
-			for (int i = beginPos; i < limit; i++) {
-				if (array[i] == b) {
-					return i - arrayOffset;
-				}
-			}
-		} else {
-			int beginPos = position();
-			int limit = limit();
-
-			for (int i = beginPos; i < limit; i++) {
-				if (get(i) == b) {
-					return i;
-				}
-			}
-		}
-
-		return -1;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer skip(int size) {
-		autoExpand(size);
-		return position(position() + size);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer fill(byte value, int size) {
-		autoExpand(size);
-		int q = size >>> 3;
-		int r = size & 7;
-
-		if (q > 0) {
-			int intValue = value & 0x000000FF | (value << 8) & 0x0000FF00 | (value << 16) & 0x00FF0000 | value << 24;
-			long longValue = intValue & 0x00000000FFFFFFFFL | (long) intValue << 32;
-
-			for (int i = q; i > 0; i--) {
-				putLong(longValue);
-			}
-		}
-
-		q = r >>> 2;
-		r = r & 3;
-
-		if (q > 0) {
-			int intValue = value & 0x000000FF | (value << 8) & 0x0000FF00 | (value << 16) & 0x00FF0000 | value << 24;
-			putInt(intValue);
-		}
-
-		q = r >> 1;
-		r = r & 1;
-
-		if (q > 0) {
-			short shortValue = (short) (value & 0x000FF | value << 8);
-			putShort(shortValue);
-		}
-
-		if (r > 0) {
-			put(value);
-		}
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer fillAndReset(byte value, int size) {
-		autoExpand(size);
-		int pos = position();
-		try {
-			fill(value, size);
-		} finally {
-			position(pos);
-		}
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer fill(int size) {
-		autoExpand(size);
-		int q = size >>> 3;
-		int r = size & 7;
-
-		for (int i = q; i > 0; i--) {
-			putLong(0L);
-		}
-
-		q = r >>> 2;
-		r = r & 3;
-
-		if (q > 0) {
-			putInt(0);
-		}
-
-		q = r >> 1;
-		r = r & 1;
-
-		if (q > 0) {
-			putShort((short) 0);
-		}
-
-		if (r > 0) {
-			put((byte) 0);
-		}
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer fillAndReset(int size) {
-		autoExpand(size);
-		int pos = position();
-		try {
-			fill(size);
-		} finally {
-			position(pos);
-		}
-
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> E getEnum(Class<E> enumClass) {
-		return toEnum(enumClass, getUnsigned());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> E getEnum(int index, Class<E> enumClass) {
-		return toEnum(enumClass, getUnsigned(index));
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> E getEnumShort(Class<E> enumClass) {
-		return toEnum(enumClass, getUnsignedShort());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass) {
-		return toEnum(enumClass, getUnsignedShort(index));
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> E getEnumInt(Class<E> enumClass) {
-		return toEnum(enumClass, getInt());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass) {
-		return toEnum(enumClass, getInt(index));
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putEnum(Enum<?> e) {
-		if (e.ordinal() > BYTE_MASK) {
-			throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
-		}
-		return put((byte) e.ordinal());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putEnum(int index, Enum<?> e) {
-		if (e.ordinal() > BYTE_MASK) {
-			throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
-		}
-		return put(index, (byte) e.ordinal());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putEnumShort(Enum<?> e) {
-		if (e.ordinal() > SHORT_MASK) {
-			throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
-		}
-		return putShort((short) e.ordinal());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putEnumShort(int index, Enum<?> e) {
-		if (e.ordinal() > SHORT_MASK) {
-			throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
-		}
-		return putShort(index, (short) e.ordinal());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putEnumInt(Enum<?> e) {
-		return putInt(e.ordinal());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer putEnumInt(int index, Enum<?> e) {
-		return putInt(index, e.ordinal());
-	}
-
-	private <E> E toEnum(Class<E> enumClass, int i) {
-		E[] enumConstants = enumClass.getEnumConstants();
-		if (i > enumConstants.length) {
-			throw new IndexOutOfBoundsException(
-					String.format("%d is too large of an ordinal to convert to the enum %s", i, enumClass.getName()));
-		}
-		return enumConstants[i];
-	}
-
-	private String enumConversionErrorMessage(Enum<?> e, String type) {
-		return String.format("%s.%s has an ordinal value too large for a %s", e.getClass().getName(), e.name(), type);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSet(Class<E> enumClass) {
-		return toEnumSet(enumClass, get() & BYTE_MASK);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSet(int index, Class<E> enumClass) {
-		return toEnumSet(enumClass, get(index) & BYTE_MASK);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSetShort(Class<E> enumClass) {
-		return toEnumSet(enumClass, getShort() & SHORT_MASK);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSetShort(int index, Class<E> enumClass) {
-		return toEnumSet(enumClass, getShort(index) & SHORT_MASK);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSetInt(Class<E> enumClass) {
-		return toEnumSet(enumClass, getInt() & INT_MASK);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSetInt(int index, Class<E> enumClass) {
-		return toEnumSet(enumClass, getInt(index) & INT_MASK);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSetLong(Class<E> enumClass) {
-		return toEnumSet(enumClass, getLong());
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> Set<E> getEnumSetLong(int index, Class<E> enumClass) {
-		return toEnumSet(enumClass, getLong(index));
-	}
-
-	private <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> clazz, long vector) {
-		EnumSet<E> set = EnumSet.noneOf(clazz);
-		long mask = 1;
-		for (E e : clazz.getEnumConstants()) {
-			if ((mask & vector) == mask) {
-				set.add(e);
-			}
-			mask <<= 1;
-		}
-		return set;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set) {
-		long vector = toLong(set);
-		if ((vector & ~BYTE_MASK) != 0) {
-			throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
-		}
-		return put((byte) vector);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set) {
-		long vector = toLong(set);
-		if ((vector & ~BYTE_MASK) != 0) {
-			throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
-		}
-		return put(index, (byte) vector);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set) {
-		long vector = toLong(set);
-		if ((vector & ~SHORT_MASK) != 0) {
-			throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
-		}
-		return putShort((short) vector);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set) {
-		long vector = toLong(set);
-		if ((vector & ~SHORT_MASK) != 0) {
-			throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
-		}
-		return putShort(index, (short) vector);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set) {
-		long vector = toLong(set);
-		if ((vector & ~INT_MASK) != 0) {
-			throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
-		}
-		return putInt((int) vector);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set) {
-		long vector = toLong(set);
-		if ((vector & ~INT_MASK) != 0) {
-			throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
-		}
-		return putInt(index, (int) vector);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set) {
-		return putLong(toLong(set));
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set) {
-		return putLong(index, toLong(set));
-	}
-
-	private <E extends Enum<E>> long toLong(Set<E> set) {
-		long vector = 0;
-		for (E e : set) {
-			if (e.ordinal() >= Long.SIZE) {
-				throw new IllegalArgumentException("The enum set is too large to fit in a bit vector: " + set);
-			}
-			vector |= 1L << e.ordinal();
-		}
-		return vector;
-	}
-
-	/**
-	 * This method forwards the call to {@link #expand(int)} only when
-	 * <tt>autoExpand</tt> property is <tt>true</tt>.
-	 */
-	private IoBuffer autoExpand(int expectedRemaining) {
-		if (isAutoExpand()) {
-			expand(expectedRemaining, true);
-		}
-		return this;
-	}
-
-	/**
-	 * This method forwards the call to {@link #expand(int)} only when
-	 * <tt>autoExpand</tt> property is <tt>true</tt>.
-	 */
-	private IoBuffer autoExpand(int pos, int expectedRemaining) {
-		if (isAutoExpand()) {
-			expand(pos, expectedRemaining, true);
-		}
-		return this;
-	}
-
-	private static void checkFieldSize(int fieldSize) {
-		if (fieldSize < 0) {
-			throw new IllegalArgumentException("fieldSize cannot be negative: " + fieldSize);
-		}
-	}
+    /** Tells if a buffer has been created from an existing buffer */
+    private final boolean derived;
+
+    /** A flag set to true if the buffer can extend automatically */
+    private boolean autoExpand;
+
+    /** A flag set to true if the buffer can shrink automatically */
+    private boolean autoShrink;
+
+    /** Tells if a buffer can be expanded */
+    private boolean recapacityAllowed = true;
+
+    /** The minimum number of bytes the IoBuffer can hold */
+    private int minimumCapacity;
+
+    /** A mask for a byte */
+    private static final long BYTE_MASK = 0xFFL;
+
+    /** A mask for a short */
+    private static final long SHORT_MASK = 0xFFFFL;
+
+    /** A mask for an int */
+    private static final long INT_MASK = 0xFFFFFFFFL;
+
+    /**
+     * We don't have any access to Buffer.markValue(), so we need to track it down,
+     * which will cause small extra overhead.
+     */
+    private int mark = -1;
+
+    /**
+     * Creates a new parent buffer.
+     * 
+     * @param allocator       The allocator to use to create new buffers
+     * @param initialCapacity The initial buffer capacity when created
+     */
+    protected AbstractIoBuffer(IoBufferAllocator allocator, int initialCapacity) {
+        setAllocator(allocator);
+        this.recapacityAllowed = true;
+        this.derived = false;
+        this.minimumCapacity = initialCapacity;
+    }
+
+    /**
+     * Creates a new derived buffer. A derived buffer uses an existing buffer
+     * properties - the allocator and capacity -.
+     * 
+     * @param parent The buffer we get the properties from
+     */
+    protected AbstractIoBuffer(AbstractIoBuffer parent) {
+        setAllocator(IoBuffer.getAllocator());
+        this.recapacityAllowed = false;
+        this.derived = true;
+        this.minimumCapacity = parent.minimumCapacity;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final boolean isDirect() {
+        return buf().isDirect();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final boolean isReadOnly() {
+        return buf().isReadOnly();
+    }
+
+    /**
+     * Sets the underlying NIO buffer instance.
+     * 
+     * @param newBuf The buffer to store within this IoBuffer
+     */
+    protected abstract void buf(ByteBuffer newBuf);
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int minimumCapacity() {
+        return minimumCapacity;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer minimumCapacity(int minimumCapacity) {
+        if (minimumCapacity < 0) {
+            throw new IllegalArgumentException("minimumCapacity: " + minimumCapacity);
+        }
+        this.minimumCapacity = minimumCapacity;
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int capacity() {
+        return buf().capacity();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer capacity(int newCapacity) {
+        if (!recapacityAllowed) {
+            throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
+        }
+
+        // Allocate a new buffer and transfer all settings to it.
+        if (newCapacity > capacity()) {
+            // Expand:
+            //// Save the state.
+            int pos = position();
+            int limit = limit();
+            ByteOrder bo = order();
+
+            //// Reallocate.
+            ByteBuffer oldBuf = buf();
+            ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
+            oldBuf.clear();
+            newBuf.put(oldBuf);
+            buf(newBuf);
+
+            //// Restore the state.
+            buf().limit(limit);
+            if (mark >= 0) {
+                buf().position(mark);
+                buf().mark();
+            }
+            buf().position(pos);
+            buf().order(bo);
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final boolean isAutoExpand() {
+        return autoExpand && recapacityAllowed;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final boolean isAutoShrink() {
+        return autoShrink && recapacityAllowed;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final boolean isDerived() {
+        return derived;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer setAutoExpand(boolean autoExpand) {
+        if (!recapacityAllowed) {
+            throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
+        }
+        this.autoExpand = autoExpand;
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer setAutoShrink(boolean autoShrink) {
+        if (!recapacityAllowed) {
+            throw new IllegalStateException("Derived buffers and their parent can't be shrinked.");
+        }
+        this.autoShrink = autoShrink;
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer expand(int expectedRemaining) {
+        return expand(position(), expectedRemaining, false);
+    }
+
+    private IoBuffer expand(int expectedRemaining, boolean autoExpand) {
+        return expand(position(), expectedRemaining, autoExpand);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer expand(int pos, int expectedRemaining) {
+        return expand(pos, expectedRemaining, false);
+    }
+
+    private IoBuffer expand(int pos, int expectedRemaining, boolean autoExpand) {
+        if (!recapacityAllowed) {
+            throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
+        }
+
+        int end = pos + expectedRemaining;
+        int newCapacity;
+
+        if (autoExpand) {
+            newCapacity = IoBuffer.normalizeCapacity(end);
+        } else {
+            newCapacity = end;
+        }
+        if (newCapacity > capacity()) {
+            // The buffer needs expansion.
+            capacity(newCapacity);
+        }
+
+        if (end > limit()) {
+            // We call limit() directly to prevent StackOverflowError
+            buf().limit(end);
+        }
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer shrink() {
+
+        if (!recapacityAllowed) {
+            throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
+        }
+
+        int position = position();
+        int capacity = capacity();
+        int limit = limit();
+
+        if (capacity == limit) {
+            return this;
+        }
+
+        int newCapacity = capacity;
+        int minCapacity = Math.max(minimumCapacity, limit);
+
+        for (;;) {
+            if (newCapacity >>> 1 < minCapacity) {
+                break;
+            }
+
+            newCapacity >>>= 1;
+
+            if (minCapacity == 0) {
+                break;
+            }
+        }
+
+        newCapacity = Math.max(minCapacity, newCapacity);
+
+        if (newCapacity == capacity) {
+            return this;
+        }
+
+        // Shrink and compact:
+        //// Save the state.
+        ByteOrder bo = order();
+
+        //// Reallocate.
+        ByteBuffer oldBuf = buf();
+        ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
+        oldBuf.position(0);
+        oldBuf.limit(limit);
+        newBuf.put(oldBuf);
+        buf(newBuf);
+
+        //// Restore the state.
+        buf().position(position);
+        buf().limit(limit);
+        buf().order(bo);
+        mark = -1;
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int position() {
+        return buf().position();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer position(int newPosition) {
+        autoExpand(newPosition, 0);
+        buf().position(newPosition);
+
+        if (mark > newPosition) {
+            mark = -1;
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int limit() {
+        return buf().limit();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer limit(int newLimit) {
+        autoExpand(newLimit, 0);
+        buf().limit(newLimit);
+        if (mark > newLimit) {
+            mark = -1;
+        }
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer mark() {
+        ByteBuffer byteBuffer = buf();
+        byteBuffer.mark();
+        mark = byteBuffer.position();
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int markValue() {
+        return mark;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer reset() {
+        buf().reset();
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer clear() {
+        buf().clear();
+        mark = -1;
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer sweep() {
+        clear();
+        return fillAndReset(remaining());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer sweep(byte value) {
+        clear();
+        return fillAndReset(value, remaining());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer flip() {
+        buf().flip();
+        mark = -1;
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer rewind() {
+        buf().rewind();
+        mark = -1;
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int remaining() {
+        ByteBuffer byteBuffer = buf();
+
+        return byteBuffer.limit() - byteBuffer.position();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final boolean hasRemaining() {
+        ByteBuffer byteBuffer = buf();
+
+        return byteBuffer.limit() > byteBuffer.position();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final byte get() {
+        return buf().get();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final short getUnsigned() {
+        return (short) (get() & 0xff);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer put(byte b) {
+        autoExpand(1);
+        buf().put(b);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(byte value) {
+        autoExpand(1);
+        buf().put((byte) (value & 0xff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(int index, byte value) {
+        autoExpand(index, 1);
+        buf().put(index, (byte) (value & 0xff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(short value) {
+        autoExpand(1);
+        buf().put((byte) (value & 0x00ff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(int index, short value) {
+        autoExpand(index, 1);
+        buf().put(index, (byte) (value & 0x00ff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(int value) {
+        autoExpand(1);
+        buf().put((byte) (value & 0x000000ff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(int index, int value) {
+        autoExpand(index, 1);
+        buf().put(index, (byte) (value & 0x000000ff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(long value) {
+        autoExpand(1);
+        buf().put((byte) (value & 0x00000000000000ffL));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putUnsigned(int index, long value) {
+        autoExpand(index, 1);
+        buf().put(index, (byte) (value & 0x00000000000000ffL));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final byte get(int index) {
+        return buf().get(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final short getUnsigned(int index) {
+        return (short) (get(index) & 0xff);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer put(int index, byte b) {
+        autoExpand(index, 1);
+        buf().put(index, b);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer get(byte[] dst, int offset, int length) {
+        buf().get(dst, offset, length);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer put(ByteBuffer src) {
+        autoExpand(src.remaining());
+        buf().put(src);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer put(byte[] src, int offset, int length) {
+        autoExpand(length);
+        buf().put(src, offset, length);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer compact() {
+        int remaining = remaining();
+        int capacity = capacity();
+
+        if (capacity == 0) {
+            return this;
+        }
+
+        if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > minimumCapacity) {
+            int newCapacity = capacity;
+            int minCapacity = Math.max(minimumCapacity, remaining << 1);
+            for (;;) {
+                if (newCapacity >>> 1 < minCapacity) {
+                    break;
+                }
+                newCapacity >>>= 1;
+            }
+
+            newCapacity = Math.max(minCapacity, newCapacity);
+
+            if (newCapacity == capacity) {
+                return this;
+            }
+
+            // Shrink and compact:
+            //// Save the state.
+            ByteOrder bo = order();
+
+            //// Sanity check.
+            if (remaining > newCapacity) {
+                throw new IllegalStateException(
+                        "The amount of the remaining bytes is greater than " + "the new capacity.");
+            }
+
+            //// Reallocate.
+            ByteBuffer oldBuf = buf();
+            ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
+            newBuf.put(oldBuf);
+            buf(newBuf);
+
+            //// Restore the state.
+            buf().order(bo);
+        } else {
+            buf().compact();
+        }
+        mark = -1;
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final ByteOrder order() {
+        return buf().order();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer order(ByteOrder bo) {
+        buf().order(bo);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final char getChar() {
+        return buf().getChar();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putChar(char value) {
+        autoExpand(2);
+        buf().putChar(value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final char getChar(int index) {
+        return buf().getChar(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putChar(int index, char value) {
+        autoExpand(index, 2);
+        buf().putChar(index, value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final CharBuffer asCharBuffer() {
+        return buf().asCharBuffer();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final short getShort() {
+        return buf().getShort();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putShort(short value) {
+        autoExpand(2);
+        buf().putShort(value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final short getShort(int index) {
+        return buf().getShort(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putShort(int index, short value) {
+        autoExpand(index, 2);
+        buf().putShort(index, value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final ShortBuffer asShortBuffer() {
+        return buf().asShortBuffer();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int getInt() {
+        return buf().getInt();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putInt(int value) {
+        autoExpand(4);
+        buf().putInt(value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(byte value) {
+        autoExpand(4);
+        buf().putInt(value & 0x00ff);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(int index, byte value) {
+        autoExpand(index, 4);
+        buf().putInt(index, value & 0x00ff);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(short value) {
+        autoExpand(4);
+        buf().putInt(value & 0x0000ffff);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(int index, short value) {
+        autoExpand(index, 4);
+        buf().putInt(index, value & 0x0000ffff);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(int value) {
+        return putInt(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(int index, int value) {
+        return putInt(index, value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(long value) {
+        autoExpand(4);
+        buf().putInt((int) (value & 0x00000000ffffffff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedInt(int index, long value) {
+        autoExpand(index, 4);
+        buf().putInt(index, (int) (value & 0x00000000ffffffffL));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(byte value) {
+        autoExpand(2);
+        buf().putShort((short) (value & 0x00ff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(int index, byte value) {
+        autoExpand(index, 2);
+        buf().putShort(index, (short) (value & 0x00ff));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(short value) {
+        return putShort(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(int index, short value) {
+        return putShort(index, value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(int value) {
+        autoExpand(2);
+        buf().putShort((short) value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(int index, int value) {
+        autoExpand(index, 2);
+        buf().putShort(index, (short) value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(long value) {
+        autoExpand(2);
+        buf().putShort((short) (value));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putUnsignedShort(int index, long value) {
+        autoExpand(index, 2);
+        buf().putShort(index, (short) (value));
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final int getInt(int index) {
+        return buf().getInt(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putInt(int index, int value) {
+        autoExpand(index, 4);
+        buf().putInt(index, value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IntBuffer asIntBuffer() {
+        return buf().asIntBuffer();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final long getLong() {
+        return buf().getLong();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putLong(long value) {
+        autoExpand(8);
+        buf().putLong(value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final long getLong(int index) {
+        return buf().getLong(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putLong(int index, long value) {
+        autoExpand(index, 8);
+        buf().putLong(index, value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final LongBuffer asLongBuffer() {
+        return buf().asLongBuffer();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final float getFloat() {
+        return buf().getFloat();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putFloat(float value) {
+        autoExpand(4);
+        buf().putFloat(value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final float getFloat(int index) {
+        return buf().getFloat(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putFloat(int index, float value) {
+        autoExpand(index, 4);
+        buf().putFloat(index, value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final FloatBuffer asFloatBuffer() {
+        return buf().asFloatBuffer();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final double getDouble() {
+        return buf().getDouble();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putDouble(double value) {
+        autoExpand(8);
+        buf().putDouble(value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final double getDouble(int index) {
+        return buf().getDouble(index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer putDouble(int index, double value) {
+        autoExpand(index, 8);
+        buf().putDouble(index, value);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final DoubleBuffer asDoubleBuffer() {
+        return buf().asDoubleBuffer();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer asReadOnlyBuffer() {
+        recapacityAllowed = false;
+        return asReadOnlyBuffer0();
+    }
+
+    /**
+     * Implement this method to return the unexpandable read only version of this
+     * buffer.
+     * 
+     * @return the IoBoffer instance
+     */
+    protected abstract IoBuffer asReadOnlyBuffer0();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer duplicate() {
+        recapacityAllowed = false;
+        return duplicate0();
+    }
+
+    /**
+     * Implement this method to return the unexpandable duplicate of this buffer.
+     * 
+     * @return the IoBoffer instance
+     */
+    protected abstract IoBuffer duplicate0();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer slice() {
+        recapacityAllowed = false;
+        return slice0();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer getSlice(int index, int length) {
+        if (length < 0) {
+            throw new IllegalArgumentException("length: " + length);
+        }
+
+        int pos = position();
+        int limit = limit();
+
+        if (index > limit) {
+            throw new IllegalArgumentException("index: " + index);
+        }
+
+        int endIndex = index + length;
+
+        if (endIndex > limit) {
+            throw new IndexOutOfBoundsException(
+                    "index + length (" + endIndex + ") is greater " + "than limit (" + limit + ").");
+        }
+
+        clear();
+        limit(endIndex);
+        position(index);
+
+        IoBuffer slice = slice();
+        limit(limit);
+        position(pos);
+
+        return slice;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final IoBuffer getSlice(int length) {
+        if (length < 0) {
+            throw new IllegalArgumentException("length: " + length);
+        }
+        int pos = position();
+        int limit = limit();
+        int nextPos = pos + length;
+        if (limit < nextPos) {
+            throw new IndexOutOfBoundsException(
+                    "position + length (" + nextPos + ") is greater " + "than limit (" + limit + ").");
+        }
+
+        limit(pos + length);
+        IoBuffer slice = slice();
+        position(nextPos);
+        limit(limit);
+        return slice;
+    }
+
+    /**
+     * Implement this method to return the unexpandable slice of this buffer.
+     * 
+     * @return the IoBoffer instance
+     */
+    protected abstract IoBuffer slice0();
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--) {
+            h = 31 * h + get(i);
+        }
+        return h;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof IoBuffer)) {
+            return false;
+        }
+
+        IoBuffer that = (IoBuffer) o;
+        if (this.remaining() != that.remaining()) {
+            return false;
+        }
+
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
+            byte v1 = this.get(i);
+            byte v2 = that.get(j);
+            if (v1 != v2) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int compareTo(IoBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            byte v1 = this.get(i);
+            byte v2 = that.get(j);
+            if (v1 == v2) {
+                continue;
+            }
+            if (v1 < v2) {
+                return -1;
+            }
+
+            return +1;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        if (isDirect()) {
+            buf.append("DirectBuffer");
+        } else {
+            buf.append("HeapBuffer");
+        }
+        buf.append("@");
+        buf.append(Integer.toHexString(super.hashCode()));
+        buf.append("[pos=");
+        buf.append(position());
+        buf.append(" lim=");
+        buf.append(limit());
+        buf.append(" cap=");
+        buf.append(capacity());
+        buf.append(": ");
+        buf.append(getHexDump(16));
+        buf.append(']');
+        return buf.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer get(byte[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer put(IoBuffer src) {
+        return put(src.buf());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer put(byte[] src) {
+        return put(src, 0, src.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getUnsignedShort() {
+        return getShort() & 0xffff;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getUnsignedShort(int index) {
+        return getShort(index) & 0xffff;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long getUnsignedInt() {
+        return getInt() & 0xffffffffL;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getMediumInt() {
+        byte b1 = get();
+        byte b2 = get();
+        byte b3 = get();
+        if (ByteOrder.BIG_ENDIAN.equals(order())) {
+            return getMediumInt(b1, b2, b3);
+        }
+
+        return getMediumInt(b3, b2, b1);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getUnsignedMediumInt() {
+        int b1 = getUnsigned();
+        int b2 = getUnsigned();
+        int b3 = getUnsigned();
+        if (ByteOrder.BIG_ENDIAN.equals(order())) {
+            return b1 << 16 | b2 << 8 | b3;
+        }
+
+        return b3 << 16 | b2 << 8 | b1;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getMediumInt(int index) {
+        byte b1 = get(index);
+        byte b2 = get(index + 1);
+        byte b3 = get(index + 2);
+        if (ByteOrder.BIG_ENDIAN.equals(order())) {
+            return getMediumInt(b1, b2, b3);
+        }
+
+        return getMediumInt(b3, b2, b1);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getUnsignedMediumInt(int index) {
+        int b1 = getUnsigned(index);
+        int b2 = getUnsigned(index + 1);
+        int b3 = getUnsigned(index + 2);
+
+        if (ByteOrder.BIG_ENDIAN.equals(order())) {
+            return b1 << 16 | b2 << 8 | b3;
+        }
+
+        return b3 << 16 | b2 << 8 | b1;
+    }
+
+    private int getMediumInt(byte b1, byte b2, byte b3) {
+        int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff;
+        // Check to see if the medium int is negative (high bit in b1 set)
+        if ((b1 & 0x80) == 0x80) {
+            // Make the the whole int negative
+            ret |= 0xff000000;
+        }
+        return ret;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putMediumInt(int value) {
+        byte b1 = (byte) (value >> 16);
+        byte b2 = (byte) (value >> 8);
+        byte b3 = (byte) value;
+
+        if (ByteOrder.BIG_ENDIAN.equals(order())) {
+            put(b1).put(b2).put(b3);
+        } else {
+            put(b3).put(b2).put(b1);
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putMediumInt(int index, int value) {
+        byte b1 = (byte) (value >> 16);
+        byte b2 = (byte) (value >> 8);
+        byte b3 = (byte) value;
+
+        if (ByteOrder.BIG_ENDIAN.equals(order())) {
+            put(index, b1).put(index + 1, b2).put(index + 2, b3);
+        } else {
+            put(index, b3).put(index + 1, b2).put(index + 2, b1);
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long getUnsignedInt(int index) {
+        return getInt(index) & 0xffffffffL;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public InputStream asInputStream() {
+        return new InputStream() {
+            @Override
+            public int available() {
+                return AbstractIoBuffer.this.remaining();
+            }
+
+            @Override
+            public synchronized void mark(int readlimit) {
+                AbstractIoBuffer.this.mark();
+            }
+
+            @Override
+            public boolean markSupported() {
+                return true;
+            }
+
+            @Override
+            public int read() {
+                if (AbstractIoBuffer.this.hasRemaining()) {
+                    return AbstractIoBuffer.this.get() & 0xff;
+                }
+
+                return -1;
+            }
+
+            @Override
+            public int read(byte[] b, int off, int len) {
+                int remaining = AbstractIoBuffer.this.remaining();
+                if (remaining > 0) {
+                    int readBytes = Math.min(remaining, len);
+                    AbstractIoBuffer.this.get(b, off, readBytes);
+                    return readBytes;
+                }
+
+                return -1;
+            }
+
+            @Override
+            public synchronized void reset() {
+                AbstractIoBuffer.this.reset();
+            }
+
+            @Override
+            public long skip(long n) {
+                int bytes;
+                if (n > Integer.MAX_VALUE) {
+                    bytes = AbstractIoBuffer.this.remaining();
+                } else {
+                    bytes = Math.min(AbstractIoBuffer.this.remaining(), (int) n);
+                }
+                AbstractIoBuffer.this.skip(bytes);
+                return bytes;
+            }
+        };
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public OutputStream asOutputStream() {
+        return new OutputStream() {
+            @Override
+            public void write(byte[] b, int off, int len) {
+                AbstractIoBuffer.this.put(b, off, len);
+            }
+
+            @Override
+            public void write(int b) {
+                AbstractIoBuffer.this.put((byte) b);
+            }
+        };
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getString(CharsetDecoder decoder) throws CharacterCodingException {
+        if (!hasRemaining()) {
+            return "";
+        }
+
+        boolean utf16 = decoder.charset().equals(StandardCharsets.UTF_16)
+                || decoder.charset().equals(StandardCharsets.UTF_16BE)
+                || decoder.charset().equals(StandardCharsets.UTF_16LE);
+
+        int oldPos = position();
+        int oldLimit = limit();
+        int end = -1;
+        int newPos;
+
+        if (!utf16) {
+            end = indexOf((byte) 0x00);
+            if (end < 0) {
+                newPos = end = oldLimit;
+            } else {
+                newPos = end + 1;
+            }
+        } else {
+            int i = oldPos;
+            for (;;) {
+                boolean wasZero = get(i) == 0;
+                i++;
+
+                if (i >= oldLimit) {
+                    break;
+                }
+
+                if (get(i) != 0) {
+                    i++;
+                    if (i >= oldLimit) {
+                        break;
+                    }
+
+                    continue;
+                }
+
+                if (wasZero) {
+                    end = i - 1;
+                    break;
+                }
+            }
+
+            if (end < 0) {
+                newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE);
+            } else {
+                if (end + 2 <= oldLimit) {
+                    newPos = end + 2;
+                } else {
+                    newPos = end;
+                }
+            }
+        }
+
+        if (oldPos == end) {
+            position(newPos);
+            return "";
+        }
+
+        limit(end);
+        decoder.reset();
+
+        int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
+        CharBuffer out = CharBuffer.allocate(expectedLength);
+        for (;;) {
+            CoderResult cr;
+            if (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;
+            }
+
+            if (cr.isError()) {
+                // Revert the buffer back to the previous state.
+                limit(oldLimit);
+                position(oldPos);
+                cr.throwException();
+            }
+        }
+
+        limit(oldLimit);
+        position(newPos);
+        return out.flip().toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException {
+        checkFieldSize(fieldSize);
+
+        if (fieldSize == 0) {
+            return "";
+        }
+
+        if (!hasRemaining()) {
+            return "";
+        }
+
+        boolean utf16 = decoder.charset().equals(StandardCharsets.UTF_16)
+                || decoder.charset().equals(StandardCharsets.UTF_16BE)
+                || decoder.charset().equals(StandardCharsets.UTF_16LE);
+
+        if (utf16 && (fieldSize & 1) != 0) {
+            throw new IllegalArgumentException("fieldSize is not even.");
+        }
+
+        int oldPos = position();
+        int oldLimit = limit();
+        int end = oldPos + fieldSize;
+
+        if (oldLimit < end) {
+            throw new BufferUnderflowException();
+        }
+
+        int i;
+
+        if (!utf16) {
+            for (i = oldPos; i < end; i++) {
+                if (get(i) == 0) {
+                    break;
+                }
+            }
+
+            if (i == end) {
+                limit(end);
+            } else {
+                limit(i);
+            }
+        } else {
+            for (i = oldPos; i < end; i += 2) {
+                if (get(i) == 0 && get(i + 1) == 0) {
+                    break;
+                }
+            }
+
+            if (i == end) {
+                limit(end);
+            } else {
+                limit(i);
+            }
+        }
+
+        if (!hasRemaining()) {
+            limit(oldLimit);
+            position(end);
+            return "";
+        }
+        decoder.reset();
+
+        int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
+        CharBuffer out = CharBuffer.allocate(expectedLength);
+        for (;;) {
+            CoderResult cr;
+            if (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;
+            }
+
+            if (cr.isError()) {
+                // Revert the buffer back to the previous state.
+                limit(oldLimit);
+                position(oldPos);
+                cr.throwException();
+            }
+        }
+
+        limit(oldLimit);
+        position(end);
+        return out.flip().toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putString(CharSequence val, CharsetEncoder encoder) throws CharacterCodingException {
+        if (val.length() == 0) {
+            return this;
+        }
+
+        CharBuffer in = CharBuffer.wrap(val);
+        encoder.reset();
+
+        int expandedState = 0;
+
+        for (;;) {
+            CoderResult cr;
+            if (in.hasRemaining()) {
+                cr = encoder.encode(in, buf(), true);
+            } else {
+                cr = encoder.flush(buf());
+            }
+
+            if (cr.isUnderflow()) {
+                break;
+            }
+            if (cr.isOverflow()) {
+                if (isAutoExpand()) {
+                    switch (expandedState) {
+                    case 0:
+                        autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
+                        expandedState++;
+                        break;
+                    case 1:
+                        autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
+                        expandedState++;
+                        break;
+                    default:
+                        throw new RuntimeException(
+                                "Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
+                                        + " but that wasn't enough for '" + val + "'");
+                    }
+                    continue;
+                }
+            } else {
+                expandedState = 0;
+            }
+            cr.throwException();
+        }
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder) throws CharacterCodingException {
+        checkFieldSize(fieldSize);
+
+        if (fieldSize == 0) {
+            return this;
+        }
+
+        autoExpand(fieldSize);
+
+        boolean utf16 = encoder.charset().equals(StandardCharsets.UTF_16)
+                || encoder.charset().equals(StandardCharsets.UTF_16BE)
+                || encoder.charset().equals(StandardCharsets.UTF_16LE);
+
+        if (utf16 && (fieldSize & 1) != 0) {
+            throw new IllegalArgumentException("fieldSize is not even.");
+        }
+
+        int oldLimit = limit();
+        int end = position() + fieldSize;
+
+        if (oldLimit < end) {
+            throw new BufferOverflowException();
+        }
+
+        if (val.length() == 0) {
+            if (!utf16) {
+                put((byte) 0x00);
+            } else {
+                put((byte) 0x00);
+                put((byte) 0x00);
+            }
+            position(end);
+            return this;
+        }
+
+        CharBuffer in = CharBuffer.wrap(val);
+        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();
+        }
+
+        limit(oldLimit);
+
+        if (position() < end) {
+            if (!utf16) {
+                put((byte) 0x00);
+            } else {
+                put((byte) 0x00);
+                put((byte) 0x00);
+            }
+        }
+
+        position(end);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException {
+        return getPrefixedString(2, decoder);
+    }
+
+    /**
+     * Reads a string which has a length field before the actual encoded string,
+     * using the specified <code>decoder</code> and returns it.
+     *
+     * @param prefixLength the length of the length field (1, 2, or 4)
+     * @param decoder      the decoder to use for decoding the string
+     * @return the prefixed string
+     * @throws CharacterCodingException when decoding fails
+     * @throws BufferUnderflowException when there is not enough data available
+     */
+    @Override
+    public String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException {
+        if (!prefixedDataAvailable(prefixLength)) {
+            throw new BufferUnderflowException();
+        }
+
+        int fieldSize = 0;
+
+        switch (prefixLength) {
+        case 1:
+            fieldSize = getUnsigned();
+            break;
+        case 2:
+            fieldSize = getUnsignedShort();
+            break;
+        case 4:
+            fieldSize = getInt();
+            break;
+        }
+
+        if (fieldSize == 0) {
+            return "";
+        }
+
+        boolean utf16 = decoder.charset().equals(StandardCharsets.UTF_16)
+                || decoder.charset().equals(StandardCharsets.UTF_16BE)
+                || decoder.charset().equals(StandardCharsets.UTF_16LE);
+
+        if (utf16 && (fieldSize & 1) != 0) {
+            throw new BufferDataException("fieldSize is not even for a UTF-16 string.");
+        }
+
+        int oldLimit = limit();
+        int end = position() + fieldSize;
+
+        if (oldLimit < end) {
+            throw new BufferUnderflowException();
+        }
+
+        limit(end);
+        decoder.reset();
+
+        int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
+        CharBuffer out = CharBuffer.allocate(expectedLength);
+        for (;;) {
+            CoderResult cr;
+            if (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();
+        }
+
+        limit(oldLimit);
+        position(end);
+        return out.flip().toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException {
+        return putPrefixedString(in, 2, 0, encoder);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
+            throws CharacterCodingException {
+        return putPrefixedString(in, prefixLength, 0, encoder);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder)
+            throws CharacterCodingException {
+        return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue,
+            CharsetEncoder encoder) throws CharacterCodingException {
+        int maxLength;
+        switch (prefixLength) {
+        case 1:
+            maxLength = 255;
+            break;
+        case 2:
+            maxLength = 65535;
+            break;
+        case 4:
+            maxLength = Integer.MAX_VALUE;
+            break;
+        default:
+            throw new IllegalArgumentException("prefixLength: " + prefixLength);
+        }
+
+        if (val.length() > maxLength) {
+            throw new IllegalArgumentException("The specified string is too long.");
+        }
+        if (val.length() == 0) {
+            switch (prefixLength) {
+            case 1:
+                put((byte) 0);
+                break;
+            case 2:
+                putShort((short) 0);
+                break;
+            case 4:
+                putInt(0);
+                break;
+            }
+            return this;
+        }
+
+        int padMask;
+        switch (padding) {
+        case 0:
+        case 1:
+            padMask = 0;
+            break;
+        case 2:
+            padMask = 1;
+            break;
+        case 4:
+            padMask = 3;
+            break;
+        default:
+            throw new IllegalArgumentException("padding: " + padding);
+        }
+
+        CharBuffer in = CharBuffer.wrap(val);
+        skip(prefixLength); // make a room for the length field
+        int oldPos = position();
+        encoder.reset();
+
+        int expandedState = 0;
+
+        for (;;) {
+            CoderResult cr;
+            if (in.hasRemaining()) {
+                cr = encoder.encode(in, buf(), true);
+            } else {
+                cr = encoder.flush(buf());
+            }
+
+            if (position() - oldPos > maxLength) {
+                throw new IllegalArgumentException("The specified string is too long.");
+            }
+
+            if (cr.isUnderflow()) {
+                break;
+            }
+            if (cr.isOverflow()) {
+                if (isAutoExpand()) {
+                    switch (expandedState) {
+                    case 0:
+                        autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
+                        expandedState++;
+                        break;
+                    case 1:
+                        autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
+                        expandedState++;
+                        break;
+                    default:
+                        throw new RuntimeException(
+                                "Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
+                                        + " but that wasn't enough for '" + val + "'");
+                    }
+                    continue;
+                }
+            } else {
+                expandedState = 0;
+            }
+            cr.throwException();
+        }
+
+        // Write the length field
+        fill(padValue, padding - (position() - oldPos & padMask));
+        int length = position() - oldPos;
+        switch (prefixLength) {
+        case 1:
+            put(oldPos - 1, (byte) length);
+            break;
+        case 2:
+            putShort(oldPos - 2, (short) length);
+            break;
+        case 4:
+            putInt(oldPos - 4, length);
+            break;
+        }
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object getObject() throws ClassNotFoundException {
+        return getObject(Thread.currentThread().getContextClassLoader());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object getObject(final ClassLoader classLoader) throws ClassNotFoundException {
+        if (!prefixedDataAvailable(4)) {
+            throw new BufferUnderflowException();
+        }
+
+        int length = getInt();
+        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()) {
+            @Override
+            protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
+                int type = read();
+                if (type < 0) {
+                    throw new EOFException();
+                }
+                switch (type) {
+                case 0: // NON-Serializable class or Primitive types
+                    return super.readClassDescriptor();
+                case 1: // Serializable class
+                    String className = readUTF();
+                    Class<?> clazz = Class.forName(className, true, classLoader);
+                    return ObjectStreamClass.lookup(clazz);
+                default:
+                    throw new StreamCorruptedException("Unexpected class descriptor type: " + type);
+                }
+            }
+
+            @Override
+            protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+                Class<?> clazz = desc.forClass();
+
+                if (clazz == null) {
+                    String name = desc.getName();
+                    try {
+                        return Class.forName(name, false, classLoader);
+                    } catch (ClassNotFoundException ex) {
+                        return super.resolveClass(desc);
+                    }
+                } else {
+                    return clazz;
+                }
+            }
+        }) {
+            return in.readObject();
+        } catch (IOException e) {
+            throw new BufferDataException(e);
+        } finally {
+            limit(oldLimit);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putObject(Object o) {
+        int oldPos = position();
+        skip(4); // Make a room for the length field.
+
+        try (ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
+            @Override
+            protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
+                Class<?> clazz = desc.forClass();
+
+                if (clazz.isArray() || clazz.isPrimitive() || !Serializable.class.isAssignableFrom(clazz)) {
+                    write(0);
+                    super.writeClassDescriptor(desc);
+                } else {
+                    // Serializable class
+                    write(1);
+                    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;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean prefixedDataAvailable(int prefixLength) {
+        return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
+        if (remaining() < prefixLength) {
+            return false;
+        }
+
+        int dataLength;
+        switch (prefixLength) {
+        case 1:
+            dataLength = getUnsigned(position());
+            break;
+        case 2:
+            dataLength = getUnsignedShort(position());
+            break;
+        case 4:
+            dataLength = getInt(position());
+            break;
+        default:
+            throw new IllegalArgumentException("prefixLength: " + prefixLength);
+        }
+
+        if (dataLength < 0 || dataLength > maxDataLength) {
+            throw new BufferDataException("dataLength: " + dataLength);
+        }
+
+        return remaining() - prefixLength >= dataLength;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int indexOf(byte b) {
+        if (hasArray()) {
+            int arrayOffset = arrayOffset();
+            int beginPos = arrayOffset + position();
+            int limit = arrayOffset + limit();
+            byte[] array = array();
+
+            for (int i = beginPos; i < limit; i++) {
+                if (array[i] == b) {
+                    return i - arrayOffset;
+                }
+            }
+        } else {
+            int beginPos = position();
+            int limit = limit();
+
+            for (int i = beginPos; i < limit; i++) {
+                if (get(i) == b) {
+                    return i;
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer skip(int size) {
+        autoExpand(size);
+        return position(position() + size);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer fill(byte value, int size) {
+        autoExpand(size);
+        int q = size >>> 3;
+        int r = size & 7;
+
+        if (q > 0) {
+            int intValue = value & 0x000000FF | (value << 8) & 0x0000FF00 | (value << 16) & 0x00FF0000 | value << 24;
+            long longValue = intValue & 0x00000000FFFFFFFFL | (long) intValue << 32;
+
+            for (int i = q; i > 0; i--) {
+                putLong(longValue);
+            }
+        }
+
+        q = r >>> 2;
+        r = r & 3;
+
+        if (q > 0) {
+            int intValue = value & 0x000000FF | (value << 8) & 0x0000FF00 | (value << 16) & 0x00FF0000 | value << 24;
+            putInt(intValue);
+        }
+
+        q = r >> 1;
+        r = r & 1;
+
+        if (q > 0) {
+            short shortValue = (short) (value & 0x000FF | value << 8);
+            putShort(shortValue);
+        }
+
+        if (r > 0) {
+            put(value);
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer fillAndReset(byte value, int size) {
+        autoExpand(size);
+        int pos = position();
+        try {
+            fill(value, size);
+        } finally {
+            position(pos);
+        }
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer fill(int size) {
+        autoExpand(size);
+        int q = size >>> 3;
+        int r = size & 7;
+
+        for (int i = q; i > 0; i--) {
+            putLong(0L);
+        }
+
+        q = r >>> 2;
+        r = r & 3;
+
+        if (q > 0) {
+            putInt(0);
+        }
+
+        q = r >> 1;
+        r = r & 1;
+
+        if (q > 0) {
+            putShort((short) 0);
+        }
+
+        if (r > 0) {
+            put((byte) 0);
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer fillAndReset(int size) {
+        autoExpand(size);
+        int pos = position();
+        try {
+            fill(size);
+        } finally {
+            position(pos);
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> E getEnum(Class<E> enumClass) {
+        return toEnum(enumClass, getUnsigned());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> E getEnum(int index, Class<E> enumClass) {
+        return toEnum(enumClass, getUnsigned(index));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> E getEnumShort(Class<E> enumClass) {
+        return toEnum(enumClass, getUnsignedShort());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass) {
+        return toEnum(enumClass, getUnsignedShort(index));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> E getEnumInt(Class<E> enumClass) {
+        return toEnum(enumClass, getInt());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass) {
+        return toEnum(enumClass, getInt(index));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putEnum(Enum<?> e) {
+        if (e.ordinal() > BYTE_MASK) {
+            throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
+        }
+        return put((byte) e.ordinal());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putEnum(int index, Enum<?> e) {
+        if (e.ordinal() > BYTE_MASK) {
+            throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
+        }
+        return put(index, (byte) e.ordinal());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putEnumShort(Enum<?> e) {
+        if (e.ordinal() > SHORT_MASK) {
+            throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
+        }
+        return putShort((short) e.ordinal());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putEnumShort(int index, Enum<?> e) {
+        if (e.ordinal() > SHORT_MASK) {
+            throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
+        }
+        return putShort(index, (short) e.ordinal());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putEnumInt(Enum<?> e) {
+        return putInt(e.ordinal());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer putEnumInt(int index, Enum<?> e) {
+        return putInt(index, e.ordinal());
+    }
+
+    private <E> E toEnum(Class<E> enumClass, int i) {
+        E[] enumConstants = enumClass.getEnumConstants();
+        if (i > enumConstants.length) {
+            throw new IndexOutOfBoundsException(
+                    String.format("%d is too large of an ordinal to convert to the enum %s", i, enumClass.getName()));
+        }
+        return enumConstants[i];
+    }
+
+    private String enumConversionErrorMessage(Enum<?> e, String type) {
+        return String.format("%s.%s has an ordinal value too large for a %s", e.getClass().getName(), e.name(), type);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSet(Class<E> enumClass) {
+        return toEnumSet(enumClass, get() & BYTE_MASK);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSet(int index, Class<E> enumClass) {
+        return toEnumSet(enumClass, get(index) & BYTE_MASK);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSetShort(Class<E> enumClass) {
+        return toEnumSet(enumClass, getShort() & SHORT_MASK);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSetShort(int index, Class<E> enumClass) {
+        return toEnumSet(enumClass, getShort(index) & SHORT_MASK);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSetInt(Class<E> enumClass) {
+        return toEnumSet(enumClass, getInt() & INT_MASK);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSetInt(int index, Class<E> enumClass) {
+        return toEnumSet(enumClass, getInt(index) & INT_MASK);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSetLong(Class<E> enumClass) {
+        return toEnumSet(enumClass, getLong());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> Set<E> getEnumSetLong(int index, Class<E> enumClass) {
+        return toEnumSet(enumClass, getLong(index));
+    }
+
+    private <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> clazz, long vector) {
+        EnumSet<E> set = EnumSet.noneOf(clazz);
+        long mask = 1;
+        for (E e : clazz.getEnumConstants()) {
+            if ((mask & vector) == mask) {
+                set.add(e);
+            }
+            mask <<= 1;
+        }
+        return set;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set) {
+        long vector = toLong(set);
+        if ((vector & ~BYTE_MASK) != 0) {
+            throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
+        }
+        return put((byte) vector);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set) {
+        long vector = toLong(set);
+        if ((vector & ~BYTE_MASK) != 0) {
+            throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
+        }
+        return put(index, (byte) vector);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set) {
+        long vector = toLong(set);
+        if ((vector & ~SHORT_MASK) != 0) {
+            throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
+        }
+        return putShort((short) vector);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set) {
+        long vector = toLong(set);
+        if ((vector & ~SHORT_MASK) != 0) {
+            throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
+        }
+        return putShort(index, (short) vector);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set) {
+        long vector = toLong(set);
+        if ((vector & ~INT_MASK) != 0) {
+            throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
+        }
+        return putInt((int) vector);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set) {
+        long vector = toLong(set);
+        if ((vector & ~INT_MASK) != 0) {
+            throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
+        }
+        return putInt(index, (int) vector);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set) {
+        return putLong(toLong(set));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set) {
+        return putLong(index, toLong(set));
+    }
+
+    private <E extends Enum<E>> long toLong(Set<E> set) {
+        long vector = 0;
+        for (E e : set) {
+            if (e.ordinal() >= Long.SIZE) {
+                throw new IllegalArgumentException("The enum set is too large to fit in a bit vector: " + set);
+            }
+            vector |= 1L << e.ordinal();
+        }
+        return vector;
+    }
+
+    /**
+     * This method forwards the call to {@link #expand(int)} only when
+     * <tt>autoExpand</tt> property is <tt>true</tt>.
+     */
+    private IoBuffer autoExpand(int expectedRemaining) {
+        if (isAutoExpand()) {
+            expand(expectedRemaining, true);
+        }
+        return this;
+    }
+
+    /**
+     * This method forwards the call to {@link #expand(int)} only when
+     * <tt>autoExpand</tt> property is <tt>true</tt>.
+     */
+    private IoBuffer autoExpand(int pos, int expectedRemaining) {
+        if (isAutoExpand()) {
+            expand(pos, expectedRemaining, true);
+        }
+        return this;
+    }
+
+    private static void checkFieldSize(int fieldSize) {
+        if (fieldSize < 0) {
+            throw new IllegalArgumentException("fieldSize cannot be negative: " + fieldSize);
+        }
+    }
 }
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
index 0313d79..db5e477 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
@@ -146,1964 +146,1964 @@ import org.apache.mina.core.session.IoSession;
  * @author <a href="http://mina.apache.org">Apache MINA Project</a>
  */
 public abstract class IoBuffer implements Comparable<IoBuffer> {
-	/** The allocator used to create new buffers */
-	private static IoBufferAllocator allocator = new SimpleBufferAllocator();
-
-	/** A flag indicating which type of buffer we are using : heap or direct */
-	private static boolean useDirectBuffer = false;
-
-	/**
-	 * Creates a new instance. This is an empty constructor. It's protected, to
-	 * forbid its usage by the users.
-	 */
-	protected IoBuffer() {
-		// Do nothing
-	}
-
-	/**
-	 * @return the allocator used by existing and new buffers
-	 */
-	public static IoBufferAllocator getAllocator() {
-		return allocator;
-	}
-
-	/**
-	 * Sets the allocator used by existing and new buffers
-	 * 
-	 * @param newAllocator the new allocator to use
-	 */
-	public static void setAllocator(IoBufferAllocator newAllocator) {
-		if (newAllocator == null) {
-			throw new IllegalArgumentException("allocator");
-		}
-
-		IoBufferAllocator oldAllocator = allocator;
-
-		allocator = newAllocator;
-
-		if (null != oldAllocator) {
-			oldAllocator.dispose();
-		}
-	}
-
-	/**
-	 * @return <tt>true</tt> if and only if a direct buffer is allocated by default
-	 *         when the type of the new buffer is not specified. The default value
-	 *         is <tt>false</tt>.
-	 */
-	public static boolean isUseDirectBuffer() {
-		return useDirectBuffer;
-	}
-
-	/**
-	 * Sets if a direct buffer should be allocated by default when the type of the
-	 * new buffer is not specified. The default value is <tt>false</tt>.
-	 * 
-	 * @param useDirectBuffer Tells if direct buffers should be allocated
-	 */
-	public static void setUseDirectBuffer(boolean useDirectBuffer) {
-		IoBuffer.useDirectBuffer = useDirectBuffer;
-	}
-
-	/**
-	 * Returns the direct or heap buffer which is capable to store the specified
-	 * amount of bytes.
-	 * 
-	 * @param capacity the capacity of the buffer
-	 * @return a IoBuffer which can hold up to capacity bytes
-	 * 
-	 * @see #setUseDirectBuffer(boolean)
-	 */
-	public static IoBuffer allocate(int capacity) {
-		return allocate(capacity, useDirectBuffer);
-	}
-
-	/**
-	 * Returns a direct or heap IoBuffer which can contain the specified number of
-	 * bytes.
-	 * 
-	 * @param capacity        the capacity of the buffer
-	 * @param useDirectBuffer <tt>true</tt> to get a direct buffer, <tt>false</tt>
-	 *                        to get a heap buffer.
-	 * @return a direct or heap IoBuffer which can hold up to capacity bytes
-	 */
-	public static IoBuffer allocate(int capacity, boolean useDirectBuffer) {
-		if (capacity < 0) {
-			throw new IllegalArgumentException("capacity: " + capacity);
-		}
-
-		return allocator.allocate(capacity, useDirectBuffer);
-	}
-
-	/**
-	 * Wraps the specified NIO {@link ByteBuffer} into a MINA buffer (either direct
-	 * or heap).
-	 * 
-	 * @param nioBuffer The {@link ByteBuffer} to wrap
-	 * @return a IoBuffer containing the bytes stored in the {@link ByteBuffer}
-	 */
-	public static IoBuffer wrap(ByteBuffer nioBuffer) {
-		return allocator.wrap(nioBuffer);
-	}
-
-	/**
-	 * Wraps the specified byte array into a MINA heap buffer. Note that the byte
-	 * array is not copied, so any modification done on it will be visible by both
-	 * sides.
-	 * 
-	 * @param byteArray The byte array to wrap
-	 * @return a heap IoBuffer containing the byte array
-	 */
-	public static IoBuffer wrap(byte[] byteArray) {
-		return wrap(ByteBuffer.wrap(byteArray));
-	}
-
-	/**
-	 * Wraps the specified byte array into MINA heap buffer. We just wrap the bytes
-	 * starting from offset up to offset + length. Note that the byte array is not
-	 * copied, so any modification done on it will be visible by both sides.
-	 * 
-	 * @param byteArray The byte array to wrap
-	 * @param offset    The starting point in the byte array
-	 * @param length    The number of bytes to store
-	 * @return a heap IoBuffer containing the selected part of the byte array
-	 */
-	public static IoBuffer wrap(byte[] byteArray, int offset, int length) {
-		return wrap(ByteBuffer.wrap(byteArray, offset, length));
-	}
-
-	/**
-	 * Normalizes the specified capacity of the buffer to power of 2, which is often
-	 * helpful for optimal memory usage and performance. If it is greater than or
-	 * equal to {@link Integer#MAX_VALUE}, it returns {@link Integer#MAX_VALUE}. If
-	 * it is zero, it returns zero.
-	 * 
-	 * @param requestedCapacity The IoBuffer capacity we want to be able to store
-	 * @return The power of 2 strictly superior to the requested capacity
-	 */
-	protected static int normalizeCapacity(int requestedCapacity) {
-		if (requestedCapacity < 0) {
-			return Integer.MAX_VALUE;
-		}
-
-		int newCapacity = Integer.highestOneBit(requestedCapacity);
-		newCapacity <<= (newCapacity < requestedCapacity ? 1 : 0);
-
-		return newCapacity < 0 ? Integer.MAX_VALUE : newCapacity;
-	}
-
-	/**
-	 * Declares this buffer and all its derived buffers are not used anymore so that
-	 * it can be reused by some {@link IoBufferAllocator} implementations. It is not
-	 * mandatory to call this method, but you might want to invoke this method for
-	 * maximum performance.
-	 */
-	public abstract void free();
-
-	/**
-	 * @return the underlying NIO {@link ByteBuffer} instance.
-	 */
-	public abstract ByteBuffer buf();
-
-	/**
-	 * @see ByteBuffer#isDirect()
-	 * 
-	 * @return <tt>True</tt> if this is a direct buffer
-	 */
-	public abstract boolean isDirect();
-
-	/**
-	 * @return <tt>true</tt> if and only if this buffer is derived from another
-	 *         buffer via one of the {@link #duplicate()}, {@link #slice()} or
-	 *         {@link #asReadOnlyBuffer()} methods.
-	 */
-	public abstract boolean isDerived();
-
-	/**
-	 * @see ByteBuffer#isReadOnly()
-	 * 
-	 * @return <tt>true</tt> if the buffer is readOnly
-	 */
-	public abstract boolean isReadOnly();
-
-	/**
-	 * @return the minimum capacity of this buffer which is used to determine the
-	 *         new capacity of the buffer shrunk by the {@link #compact()} and
-	 *         {@link #shrink()} operation. The default value is the initial
-	 *         capacity of the buffer.
-	 */
-	public abstract int minimumCapacity();
-
-	/**
-	 * Sets the minimum capacity of this buffer which is used to determine the new
-	 * capacity of the buffer shrunk by {@link #compact()} and {@link #shrink()}
-	 * operation. The default value is the initial capacity of the buffer.
-	 * 
-	 * @param minimumCapacity the wanted minimum capacity
-	 * @return the underlying NIO {@link ByteBuffer} instance.
-	 */
-	public abstract IoBuffer minimumCapacity(int minimumCapacity);
-
-	/**
-	 * @see ByteBuffer#capacity()
-	 * 
-	 * @return the buffer capacity
-	 */
-	public abstract int capacity();
-
-	/**
-	 * Increases the capacity of this buffer. If the new capacity is less than or
-	 * equal to the current capacity, this method returns the original buffer. If
-	 * the new capacity is greater than the current capacity, the buffer is
-	 * reallocated while retaining the position, limit, mark and the content of the
-	 * buffer. <br>
-	 * Note that the IoBuffer is replaced, it's not copied. <br>
-	 * Assuming a buffer contains N bytes, its position is 0 and its current
-	 * capacity is C, here are the resulting buffer if we set the new capacity to a
-	 * value V &lt; C and V &gt; C :
-	 * 
-	 * <pre>
-	 *  Initial buffer :
-	 *   
-	 *   0       L          C
-	 *  +--------+----------+
-	 *  |XXXXXXXX|          |
-	 *  +--------+----------+
-	 *   ^       ^          ^
-	 *   |       |          |
-	 *  pos    limit     capacity
-	 *  
-	 * V &lt;= C :
-	 * 
-	 *   0       L          C
-	 *  +--------+----------+
-	 *  |XXXXXXXX|          |
-	 *  +--------+----------+
-	 *   ^       ^          ^
-	 *   |       |          |
-	 *  pos    limit   newCapacity
-	 *  
-	 * V &gt; C :
-	 * 
-	 *   0       L          C            V
-	 *  +--------+-----------------------+
-	 *  |XXXXXXXX|          :            |
-	 *  +--------+-----------------------+
-	 *   ^       ^          ^            ^
-	 *   |       |          |            |
-	 *  pos    limit   oldCapacity  newCapacity
-	 *  
-	 *  The buffer has been increased.
-	 * 
-	 * </pre>
-	 * 
-	 * @param newCapacity the wanted capacity
-	 * @return the underlying NIO {@link ByteBuffer} instance.
-	 */
-	public abstract IoBuffer capacity(int newCapacity);
-
-	/**
-	 * @return <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on.
-	 */
-	public abstract boolean isAutoExpand();
-
-	/**
-	 * Turns on or off <tt>autoExpand</tt>.
-	 * 
-	 * @param autoExpand The flag value to set
-	 * @return The modified IoBuffer instance
-	 */
-	public abstract IoBuffer setAutoExpand(boolean autoExpand);
-
-	/**
-	 * @return <tt>true</tt> if and only if <tt>autoShrink</tt> is turned on.
-	 */
-	public abstract boolean isAutoShrink();
-
-	/**
-	 * Turns on or off <tt>autoShrink</tt>.
-	 * 
-	 * @param autoShrink The flag value to set
-	 * @return The modified IoBuffer instance
-	 */
-	public abstract IoBuffer setAutoShrink(boolean autoShrink);
-
-	/**
-	 * Changes the capacity and limit of this buffer so this buffer get the
-	 * specified <tt>expectedRemaining</tt> room from the current position. This
-	 * method works even if you didn't set <tt>autoExpand</tt> to <tt>true</tt>.
-	 * <br>
-	 * Assuming a buffer contains N bytes, its position is P and its current
-	 * capacity is C, here are the resulting buffer if we call the expand method
-	 * with a expectedRemaining value V :
-	 * 
-	 * <pre>
-	 *  Initial buffer :
-	 *   
-	 *   0       L          C
-	 *  +--------+----------+
-	 *  |XXXXXXXX|          |
-	 *  +--------+----------+
-	 *   ^       ^          ^
-	 *   |       |          |
-	 *  pos    limit     capacity
-	 *  
-	 * ( pos + V )  &lt;= L, no change :
-	 * 
-	 *   0       L          C
-	 *  +--------+----------+
-	 *  |XXXXXXXX|          |
-	 *  +--------+----------+
-	 *   ^       ^          ^
-	 *   |       |          |
-	 *  pos    limit   newCapacity
-	 *  
-	 * You can still put ( L - pos ) bytes in the buffer
-	 *  
-	 * ( pos + V ) &gt; L &amp; ( pos + V ) &lt;= C :
-	 * 
-	 *  0        L          C
-	 *  +------------+------+
-	 *  |XXXXXXXX:...|      |
-	 *  +------------+------+
-	 *   ^           ^      ^
-	 *   |           |      |
-	 *  pos       newlimit  newCapacity
-	 *  
-	 *  You can now put ( L - pos + V )  bytes in the buffer.
-	 *  
-	 *  
-	 *  ( pos + V ) &gt; C
-	 * 
-	 *   0       L          C
-	 *  +-------------------+----+
-	 *  |XXXXXXXX:..........:....|
-	 *  +------------------------+
-	 *   ^                       ^
-	 *   |                       |
-	 *  pos                      +-- newlimit
-	 *                           |
-	 *                           +-- newCapacity
-	 *                           
-	 * You can now put ( L - pos + V ) bytes in the buffer, which limit is now
-	 * equals to the capacity.
-	 * </pre>
-	 *
-	 * Note that the expecting remaining bytes starts at the current position. In
-	 * all those examples, the position is 0.
-	 * 
-	 * @param expectedRemaining The expected remaining bytes in the buffer
-	 * @return The modified IoBuffer instance
-	 */
-	public abstract IoBuffer expand(int expectedRemaining);
-
-	/**
-	 * Changes the capacity and limit of this buffer so this buffer get the
-	 * specified <tt>expectedRemaining</tt> room from the specified
-	 * <tt>position</tt>. This method works even if you didn't set
-	 * <tt>autoExpand</tt> to <tt>true</tt>. Assuming a buffer contains N bytes, its
-	 * position is P and its current capacity is C, here are the resulting buffer if
-	 * we call the expand method with a expectedRemaining value V :
-	 * 
-	 * <pre>
-	 *  Initial buffer :
-	 *   
-	 *      P    L          C
-	 *  +--------+----------+
-	 *  |XXXXXXXX|          |
-	 *  +--------+----------+
-	 *      ^    ^          ^
-	 *      |    |          |
-	 *     pos limit     capacity
-	 *  
-	 * ( pos + V )  &lt;= L, no change :
-	 * 
-	 *      P    L          C
-	 *  +--------+----------+
-	 *  |XXXXXXXX|          |
-	 *  +--------+----------+
-	 *      ^    ^          ^
-	 *      |    |          |
-	 *     pos limit   newCapacity
-	 *  
-	 * You can still put ( L - pos ) bytes in the buffer
-	 *  
-	 * ( pos + V ) &gt; L &amp; ( pos + V ) &lt;= C :
-	 * 
-	 *      P    L          C
-	 *  +------------+------+
-	 *  |XXXXXXXX:...|      |
-	 *  +------------+------+
-	 *      ^        ^      ^
-	 *      |        |      |
-	 *     pos    newlimit  newCapacity
-	 *  
-	 *  You can now put ( L - pos + V)  bytes in the buffer.
-	 *  
-	 *  
-	 *  ( pos + V ) &gt; C
-	 * 
-	 *      P       L          C
-	 *  +-------------------+----+
-	 *  |XXXXXXXX:..........:....|
-	 *  +------------------------+
-	 *      ^                    ^
-	 *      |                    |
-	 *     pos                   +-- newlimit
-	 *                           |
-	 *                           +-- newCapacity
-	 *                           
-	 * You can now put ( L - pos + V ) bytes in the buffer, which limit is now
-	 * equals to the capacity.
-	 * </pre>
-	 *
-	 * Note that the expecting remaining bytes starts at the current position. In
-	 * all those examples, the position is P.
-	 * 
-	 * @param position          The starting position from which we want to define a
-	 *                          remaining number of bytes
-	 * @param expectedRemaining The expected remaining bytes in the buffer
-	 * @return The modified IoBuffer instance
-	 */
-	public abstract IoBuffer expand(int position, int expectedRemaining);
-
-	/**
-	 * Changes the capacity of this buffer so this buffer occupies as less memory as
-	 * possible while retaining the position, limit and the buffer content between
-	 * the position and limit. <br>
-	 * <b>The capacity of the buffer never becomes less than
-	 * {@link #minimumCapacity()}</b> <br>
-	 * . The mark is discarded once the capacity changes. <br>
-	 * Typically, a call to this method tries to remove as much unused bytes as
-	 * possible, dividing by two the initial capacity until it can't without
-	 * obtaining a new capacity lower than the {@link #minimumCapacity()}. For
-	 * instance, if the limit is 7 and the capacity is 36, with a minimum capacity
-	 * of 8, shrinking the buffer will left a capacity of 9 (we go down from 36 to
-	 * 18, then from 18 to 9).
-	 * 
-	 * <pre>
-	 *  Initial buffer :
-	 *   
-	 *  +--------+----------+
-	 *  |XXXXXXXX|          |
-	 *  +--------+----------+
-	 *      ^    ^  ^       ^
-	 *      |    |  |       |
-	 *     pos   |  |    capacity
-	 *           |  |
-	 *           |  +-- minimumCapacity
-	 *           |
-	 *           +-- limit
-	 * 
-	 * Resulting buffer :
-	 * 
-	 *  +--------+--+-+
-	 *  |XXXXXXXX|  | |
-	 *  +--------+--+-+
-	 *      ^    ^  ^ ^
-	 *      |    |  | |
-	 *      |    |  | +-- new capacity
-	 *      |    |  |
-	 *     pos   |  +-- minimum capacity
-	 *           |
-	 *           +-- limit
-	 * </pre>
-	 * 
-	 * @return The modified IoBuffer instance
-	 */
-	public abstract IoBuffer shrink();
-
-	/**
-	 * @see java.nio.Buffer#position()
-	 * @return The current position in the buffer
-	 */
-	public abstract int position();
-
-	/**
-	 * @see java.nio.Buffer#position(int)
-	 * 
-	 * @param newPosition Sets the new position in the buffer
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer position(int newPosition);
-
-	/**
-	 * @see java.nio.Buffer#limit()
-	 * 
-	 * @return the modified IoBuffer 's limit
-	 */
-	public abstract int limit();
-
-	/**
-	 * @see java.nio.Buffer#limit(int)
-	 * 
-	 * @param newLimit The new buffer's limit
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer limit(int newLimit);
-
-	/**
-	 * @see java.nio.Buffer#mark()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer mark();
-
-	/**
-	 * @return the position of the current mark. This method returns <tt>-1</tt> if
-	 *         no mark is set.
-	 */
-	public abstract int markValue();
-
-	/**
-	 * @see java.nio.Buffer#reset()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer reset();
-
-	/**
-	 * @see java.nio.Buffer#clear()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer clear();
-
-	/**
-	 * Clears this buffer and fills its content with <tt>NUL</tt>. The position is
-	 * set to zero, the limit is set to the capacity, and the mark is discarded.
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer sweep();
-
-	/**
-	 * double Clears this buffer and fills its content with <tt>value</tt>. The
-	 * position is set to zero, the limit is set to the capacity, and the mark is
-	 * discarded.
-	 *
-	 * @param value The value to put in the buffer
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer sweep(byte value);
-
-	/**
-	 * @see java.nio.Buffer#flip()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer flip();
-
-	/**
-	 * @see java.nio.Buffer#rewind()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer rewind();
-
-	/**
-	 * @see java.nio.Buffer#remaining()
-	 * 
-	 * @return The remaining bytes in the buffer
-	 */
-	public abstract int remaining();
-
-	/**
-	 * @see java.nio.Buffer#hasRemaining()
-	 * 
-	 * @return <tt>true</tt> if there are some remaining bytes in the buffer
-	 */
-	public abstract boolean hasRemaining();
-
-	/**
-	 * @see ByteBuffer#duplicate()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer duplicate();
-
-	/**
-	 * @see ByteBuffer#slice()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer slice();
-
-	/**
-	 * @see ByteBuffer#asReadOnlyBuffer()
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer asReadOnlyBuffer();
-
-	/**
-	 * @see ByteBuffer#hasArray()
-	 * 
-	 * @return <tt>true</tt> if the {@link #array()} method will return a byte[]
-	 */
-	public abstract boolean hasArray();
-
-	/**
-	 * @see ByteBuffer#array()
-	 * 
-	 * @return A byte[] if this IoBuffer supports it
-	 */
-	public abstract byte[] array();
-
-	/**
-	 * @see ByteBuffer#arrayOffset()
-	 * 
-	 * @return The offset in the returned byte[] when the {@link #array()} method is
-	 *         called
-	 */
-	public abstract int arrayOffset();
-
-	/**
-	 * @see ByteBuffer#get()
-	 * 
-	 * @return The byte at the current position
-	 */
-	public abstract byte get();
-
-	/**
-	 * Reads one unsigned byte as a short integer.
-	 * 
-	 * @return the unsigned short at the current position
-	 */
-	public abstract short getUnsigned();
-
-	/**
-	 * @see ByteBuffer#put(byte)
-	 * 
-	 * @param b The byte to put in the buffer
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer put(byte b);
-
-	/**
-	 * @see ByteBuffer#get(int)
-	 * 
-	 * @param index The position for which we want to read a byte
-	 * @return the byte at the given position
-	 */
-	public abstract byte get(int index);
-
-	/**
-	 * Reads one byte as an unsigned short integer.
-	 * 
-	 * @param index The position for which we want to read an unsigned byte
-	 * @return the unsigned byte at the given position
-	 */
-	public abstract short getUnsigned(int index);
-
-	/**
-	 * @see ByteBuffer#put(int, byte)
-	 * 
-	 * @param index The position where the byte will be put
-	 * @param b     The byte to put
-	 * @return the modified IoBuffer
-	 * 
-	 */
-	public abstract IoBuffer put(int index, byte b);
-
-	/**
-	 * @see ByteBuffer#get(byte[], int, int)
-	 * 
-	 * @param dst    The destination buffer
-	 * @param offset The position in the original buffer
-	 * @param length The number of bytes to copy
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer get(byte[] dst, int offset, int length);
-
-	/**
-	 * @see ByteBuffer#get(byte[])
-	 *
-	 * @param dst The byte[] that will contain the read bytes
-	 * @return the IoBuffer
-	 */
-	public abstract IoBuffer get(byte[] dst);
-
-	/**
-	 * Get a new IoBuffer containing a slice of the current buffer
-	 * 
-	 * @param index  The position in the buffer
-	 * @param length The number of bytes to copy
-	 * @return the new IoBuffer
-	 */
-	public abstract IoBuffer getSlice(int index, int length);
-
-	/**
-	 * Get a new IoBuffer containing a slice of the current buffer
-	 * 
-	 * @param length The number of bytes to copy
-	 * @return the new IoBuffer
-	 */
-	public abstract IoBuffer getSlice(int length);
-
-	/**
-	 * Writes the content of the specified <tt>src</tt> into this buffer.
-	 * 
-	 * @param src The source ByteBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer put(ByteBuffer src);
-
-	/**
-	 * Writes the content of the specified <tt>src</tt> into this buffer.
-	 * 
-	 * @param src The source IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer put(IoBuffer src);
-
-	/**
-	 * @see ByteBuffer#put(byte[], int, int)
-	 * 
-	 * @param src    The byte[] to put
-	 * @param offset The position in the source
-	 * @param length The number of bytes to copy
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer put(byte[] src, int offset, int length);
-
-	/**
-	 * @see ByteBuffer#put(byte[])
-	 * 
-	 * @param src The byte[] to put
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer put(byte[] src);
-
-	/**
-	 * @see ByteBuffer#compact()
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer compact();
-
-	/**
-	 * @see ByteBuffer#order()
-	 * 
-	 * @return the IoBuffer ByteOrder
-	 */
-	public abstract ByteOrder order();
-
-	/**
-	 * @see ByteBuffer#order(ByteOrder)
-	 * 
-	 * @param bo The new ByteBuffer to use for this IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer order(ByteOrder bo);
-
-	/**
-	 * @see ByteBuffer#getChar()
-	 * 
-	 * @return The char at the current position
-	 */
-	public abstract char getChar();
-
-	/**
-	 * @see ByteBuffer#putChar(char)
-	 * 
-	 * @param value The char to put at the current position
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putChar(char value);
-
-	/**
-	 * @see ByteBuffer#getChar(int)
-	 * 
-	 * @param index The index in the IoBuffer where we will read a char from
-	 * @return the char at 'index' position
-	 */
-	public abstract char getChar(int index);
-
-	/**
-	 * @see ByteBuffer#putChar(int, char)
-	 * 
-	 * @param index The index in the IoBuffer where we will put a char in
-	 * @param value The char to put at the current position
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putChar(int index, char value);
-
-	/**
-	 * @see ByteBuffer#asCharBuffer()
-	 * 
-	 * @return a new CharBuffer
-	 */
-	public abstract CharBuffer asCharBuffer();
-
-	/**
-	 * @see ByteBuffer#getShort()
-	 * 
-	 * @return The read short
-	 */
-	public abstract short getShort();
-
-	/**
-	 * Reads two bytes unsigned integer.
-	 * 
-	 * @return The read unsigned short
-	 */
-	public abstract int getUnsignedShort();
-
-	/**
-	 * @see ByteBuffer#putShort(short)
-	 * 
-	 * @param value The short to put at the current position
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putShort(short value);
-
-	/**
-	 * @see ByteBuffer#getShort()
-	 * 
-	 * @param index The index in the IoBuffer where we will read a short from
-	 * @return The read short
-	 */
-	public abstract short getShort(int index);
-
-	/**
-	 * Reads two bytes unsigned integer.
-	 * 
-	 * @param index The index in the IoBuffer where we will read an unsigned short
-	 *              from
-	 * @return the unsigned short at the given position
-	 */
-	public abstract int getUnsignedShort(int index);
-
-	/**
-	 * @see ByteBuffer#putShort(int, short)
-	 * 
-	 * @param index The position at which the short should be written
-	 * @param value The short to put at the current position
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putShort(int index, short value);
-
-	/**
-	 * @see ByteBuffer#asShortBuffer()
-	 * 
-	 * @return A ShortBuffer from this IoBuffer
-	 */
-	public abstract ShortBuffer asShortBuffer();
-
-	/**
-	 * @see ByteBuffer#getInt()
-	 * 
-	 * @return The int read
-	 */
-	public abstract int getInt();
-
-	/**
-	 * Reads four bytes unsigned integer.
-	 * 
-	 * @return The unsigned int read
-	 */
-	public abstract long getUnsignedInt();
-
-	/**
-	 * Relative <i>get</i> method for reading a medium int value.
-	 * 
-	 * <p>
-	 * Reads the next three bytes at this buffer's current position, composing them
-	 * into an int value according to the current byte order, and then increments
-	 * the position by three.
-	 * 
-	 * @return The medium int value at the buffer's current position
-	 */
-	public abstract int getMediumInt();
-
-	/**
-	 * Relative <i>get</i> method for reading an unsigned medium int value.
-	 * 
-	 * <p>
-	 * Reads the next three bytes at this buffer's current position, composing them
-	 * into an int value according to the current byte order, and then increments
-	 * the position by three.
-	 * 
-	 * @return The unsigned medium int value at the buffer's current position
-	 */
-	public abstract int getUnsignedMediumInt();
-
-	/**
-	 * Absolute <i>get</i> method for reading a medium int value.
-	 * 
-	 * <p>
-	 * Reads the next three bytes at this buffer's current position, composing them
-	 * into an int value according to the current byte order.
-	 * 
-	 * @param index The index from which the medium int will be read
-	 * @return The medium int value at the given index
-	 * 
-	 * @throws IndexOutOfBoundsException If <tt>index</tt> is negative or not
-	 *                                   smaller than the buffer's limit
-	 */
-	public abstract int getMediumInt(int index);
-
-	/**
-	 * Absolute <i>get</i> method for reading an unsigned medium int value.
-	 * 
-	 * <p>
-	 * Reads the next three bytes at this buffer's current position, composing them
-	 * into an int value according to the current byte order.
-	 * 
-	 * @param index The index from which the unsigned medium int will be read
-	 * @return The unsigned medium int value at the given index
-	 * 
-	 * @throws IndexOutOfBoundsException If <tt>index</tt> is negative or not
-	 *                                   smaller than the buffer's limit
-	 */
-	public abstract int getUnsignedMediumInt(int index);
-
-	/**
-	 * Relative <i>put</i> method for writing a medium int value.
-	 * 
-	 * <p>
-	 * Writes three bytes containing the given int value, in the current byte order,
-	 * into this buffer at the current position, and then increments the position by
-	 * three.
-	 * 
-	 * @param value The medium int value to be written
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putMediumInt(int value);
-
-	/**
-	 * Absolute <i>put</i> method for writing a medium int value.
-	 * 
-	 * <p>
-	 * Writes three bytes containing the given int value, in the current byte order,
-	 * into this buffer at the given index.
-	 * 
-	 * @param index The index at which the bytes will be written
-	 * 
-	 * @param value The medium int value to be written
-	 * 
-	 * @return the modified IoBuffer
-	 * 
-	 * @throws IndexOutOfBoundsException If <tt>index</tt> is negative or not
-	 *                                   smaller than the buffer's limit, minus
-	 *                                   three
-	 */
-	public abstract IoBuffer putMediumInt(int index, int value);
-
-	/**
-	 * @see ByteBuffer#putInt(int)
-	 * 
-	 * @param value The int to put at the current position
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putInt(int value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer
-	 * 
-	 * @param value the byte to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(byte value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the byte to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(int index, byte value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer
-	 * 
-	 * @param value the short to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(short value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the short to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(int index, short value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer
-	 * 
-	 * @param value the int to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(int value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the int to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(int index, int value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer
-	 * 
-	 * @param value the long to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(long value);
-
-	/**
-	 * Writes an unsigned byte into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the long to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsigned(int index, long value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer
-	 * 
-	 * @param value the byte to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(byte value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the byte to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(int index, byte value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer
-	 * 
-	 * @param value the short to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(short value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the short to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(int index, short value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer
-	 * 
-	 * @param value the int to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(int value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the int to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(int index, int value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer
-	 * 
-	 * @param value the long to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(long value);
-
-	/**
-	 * Writes an unsigned int into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the long to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedInt(int index, long value);
-
-	/**
-	 * Writes an unsigned short into the ByteBuffer
-	 * 
-	 * @param value the byte to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(byte value);
-
-	/**
-	 * Writes an unsigned Short into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the byte to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(int index, byte value);
-
-	/**
-	 * Writes an unsigned Short into the ByteBuffer
-	 * 
-	 * @param value the short to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(short value);
-
-	/**
-	 * Writes an unsigned Short into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the unsigned short
-	 * @param value the unsigned short to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(int index, short value);
-
-	/**
-	 * Writes an unsigned Short into the ByteBuffer
-	 * 
-	 * @param value the int to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(int value);
-
-	/**
-	 * Writes an unsigned Short into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the value
-	 * @param value the int to write
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(int index, int value);
-
-	/**
-	 * Writes an unsigned Short into the ByteBuffer
-	 * 
-	 * @param value the long to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(long value);
-
-	/**
-	 * Writes an unsigned Short into the ByteBuffer at a specified position
-	 * 
-	 * @param index the position in the buffer to write the short
-	 * @param value the long to write
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putUnsignedShort(int index, long value);
-
-	/**
-	 * @see ByteBuffer#getInt(int)
-	 * @param index The index in the IoBuffer where we will read an int from
-	 * @return the int at the given position
-	 */
-	public abstract int getInt(int index);
-
-	/**
-	 * Reads four bytes unsigned integer.
-	 * 
-	 * @param index The index in the IoBuffer where we will read an unsigned int
-	 *              from
-	 * @return The long at the given position
-	 */
-	public abstract long getUnsignedInt(int index);
-
-	/**
-	 * @see ByteBuffer#putInt(int, int)
-	 * 
-	 * @param index The position where to put the int
-	 * @param value The int to put in the IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putInt(int index, int value);
-
-	/**
-	 * @see ByteBuffer#asIntBuffer()
-	 * 
-	 * @return the modified IoBuffer
-	 */
-	public abstract IntBuffer asIntBuffer();
-
-	/**
-	 * @see ByteBuffer#getLong()
-	 * 
-	 * @return The long at the current position
-	 */
-	public abstract long getLong();
-
-	/**
-	 * @see ByteBuffer#putLong(int, long)
-	 * 
-	 * @param value The log to put in the IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putLong(long value);
-
-	/**
-	 * @see ByteBuffer#getLong(int)
-	 * 
-	 * @param index The index in the IoBuffer where we will read a long from
-	 * @return the long at the given position
-	 */
-	public abstract long getLong(int index);
-
-	/**
-	 * @see ByteBuffer#putLong(int, long)
-	 * 
-	 * @param index The position where to put the long
-	 * @param value The long to put in the IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putLong(int index, long value);
-
-	/**
-	 * @see ByteBuffer#asLongBuffer()
-	 * 
-	 * @return a LongBuffer from this IoBffer
-	 */
-	public abstract LongBuffer asLongBuffer();
-
-	/**
-	 * @see ByteBuffer#getFloat()
-	 * 
-	 * @return the float at the current position
-	 */
-	public abstract float getFloat();
-
-	/**
-	 * @see ByteBuffer#putFloat(float)
-	 *
-	 * @param value The float to put in the IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putFloat(float value);
-
-	/**
-	 * @see ByteBuffer#getFloat(int)
-	 * 
-	 * @param index The index in the IoBuffer where we will read a float from
-	 * @return The float at the given position
-	 */
-	public abstract float getFloat(int index);
-
-	/**
-	 * @see ByteBuffer#putFloat(int, float)
-	 * 
-	 * @param index The position where to put the float
-	 * @param value The float to put in the IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putFloat(int index, float value);
-
-	/**
-	 * @see ByteBuffer#asFloatBuffer()
-	 * 
-	 * @return A FloatBuffer from this IoBuffer
-	 */
-	public abstract FloatBuffer asFloatBuffer();
-
-	/**
-	 * @see ByteBuffer#getDouble()
-	 * 
-	 * @return the double at the current position
-	 */
-	public abstract double getDouble();
-
-	/**
-	 * @see ByteBuffer#putDouble(double)
-	 * 
-	 * @param value The double to put at the IoBuffer current position
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putDouble(double value);
-
-	/**
-	 * @see ByteBuffer#getDouble(int)
-	 * 
-	 * @param index The position where to get the double from
-	 * @return The double at the given position
-	 */
-	public abstract double getDouble(int index);
-
-	/**
-	 * @see ByteBuffer#putDouble(int, double)
-	 * 
-	 * @param index The position where to put the double
-	 * @param value The double to put in the IoBuffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract IoBuffer putDouble(int index, double value);
-
-	/**
-	 * @see ByteBuffer#asDoubleBuffer()
-	 * 
-	 * @return A buffer containing Double
-	 */
-	public abstract DoubleBuffer asDoubleBuffer();
-
-	/**
-	 * @return 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 abstract InputStream asInputStream();
-
-	/**
-	 * @return 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 abstract OutputStream asOutputStream();
-
-	/**
-	 * Returns hexdump of this buffer. The data and pointer are not changed as a
-	 * result of this method call.
-	 * 
-	 * @return hexidecimal representation of this buffer
-	 */
-	public String getHexDump() {
-		return this.getHexDump(this.remaining(), false);
-	}
-
-	/**
-	 * Returns hexdump of this buffer. The data and pointer are not changed as a
-	 * result of this method call.
-	 * 
-	 * @return hexidecimal representation of this buffer
-	 */
-	public String getHexDump(boolean pretty) {
-		return getHexDump(this.remaining(), pretty);
-	}
-
-	/**
-	 * Return hexdump of this buffer with limited length.
-	 * 
-	 * @param length The maximum number of bytes to dump from the current buffer
-	 *               position.
-	 * @return hexidecimal representation of this buffer
-	 */
-	public String getHexDump(int length) {
-		return getHexDump(length, false);
-	}
-
-	/**
-	 * Return hexdump of this buffer with limited length.
-	 * 
-	 * @param length The maximum number of bytes to dump from the current buffer
-	 *               position.
-	 * @return hexidecimal representation of this buffer
-	 */
-	public String getHexDump(int length, boolean pretty) {
-		return (pretty) ? IoBufferHexDumper.getPrettyHexDumpSlice(this, this.position(), Math.min(this.remaining(), length))
-				: IoBufferHexDumper.getHexDumpSlice(this, this.position(), Math.min(this.remaining(), length));
-	}
-
-	// //////////////////////////////
-	// 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.
-	 * 
-	 * @param decoder The {@link CharsetDecoder} to use
-	 * @return the read String
-	 * @exception CharacterCodingException Thrown when an error occurred while
-	 *                                     decoding the buffer
-	 */
-	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
-	 * @param decoder   The {@link CharsetDecoder} to use
-	 * @return the read String
-	 * @exception CharacterCodingException Thrown when an error occurred while
-	 *                                     decoding the buffer
-	 */
-	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.
-	 * 
-	 * @param val     The CharSequence to put in the IoBuffer
-	 * @param encoder The CharsetEncoder to use
-	 * @return The modified IoBuffer
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  String
-	 */
-	public abstract IoBuffer putString(CharSequence val, 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 val       The CharSequence to put in the IoBuffer
-	 * @param fieldSize the maximum number of bytes to write
-	 * @param encoder   The CharsetEncoder to use
-	 * @return The modified IoBuffer
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  String
-	 */
-	public abstract IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder)
-			throws CharacterCodingException;
-
-	/**
-	 * Reads a string which has a 16-bit length field before the actual encoded
-	 * string, using the specified <code>decoder</code> and returns it. This method
-	 * is a shortcut for <tt>getPrefixedString(2, decoder)</tt>.
-	 * 
-	 * @param decoder The CharsetDecoder to use
-	 * @return The read String
-	 * 
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  String
-	 */
-	public abstract String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException;
-
-	/**
-	 * Reads a string which has a length field before the actual encoded string,
-	 * using the specified <code>decoder</code> and returns it.
-	 * 
-	 * @param prefixLength the length of the length field (1, 2, or 4)
-	 * @param decoder      The CharsetDecoder to use
-	 * @return The read String
-	 * 
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  String
-	 */
-	public abstract String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException;
-
-	/**
-	 * Writes the content of <code>in</code> into this buffer as a string which has
-	 * a 16-bit length field before the actual encoded string, using the specified
-	 * <code>encoder</code>. This method is a shortcut for
-	 * <tt>putPrefixedString(in, 2, 0, encoder)</tt>.
-	 * 
-	 * @param in      The CharSequence to put in the IoBuffer
-	 * @param encoder The CharsetEncoder to use
-	 * @return The modified IoBuffer
-	 * 
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  CharSequence
-	 */
-	public abstract IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException;
-
-	/**
-	 * Writes the content of <code>in</code> into this buffer as a string which has
-	 * a 16-bit length field before the actual encoded string, using the specified
-	 * <code>encoder</code>. This method is a shortcut for
-	 * <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>.
-	 * 
-	 * @param in           The CharSequence to put in the IoBuffer
-	 * @param prefixLength the length of the length field (1, 2, or 4)
-	 * @param encoder      The CharsetEncoder to use
-	 * @return The modified IoBuffer
-	 * 
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  CharSequence
-	 */
-	public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
-			throws CharacterCodingException;
-
-	/**
-	 * Writes the content of <code>in</code> into this buffer as a string which has
-	 * a 16-bit length field before the actual encoded string, using the specified
-	 * <code>encoder</code>. This method is a shortcut for
-	 * <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>
-	 * 
-	 * @param in           The CharSequence to put in the IoBuffer
-	 * @param prefixLength the length of the length field (1, 2, or 4)
-	 * @param padding      the number of padded <tt>NUL</tt>s (1 (or 0), 2, or 4)
-	 * @param encoder      The CharsetEncoder to use
-	 * @return The modified IoBuffer
-	 * 
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  CharSequence
-	 */
-	public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder)
-			throws CharacterCodingException;
-
-	/**
-	 * Writes the content of <code>val</code> into this buffer as a string which has
-	 * a 16-bit length field before the actual encoded string, using the specified
-	 * <code>encoder</code>.
-	 * 
-	 * @param val          The CharSequence to put in teh IoBuffer
-	 * @param prefixLength the length of the length field (1, 2, or 4)
-	 * @param padding      the number of padded bytes (1 (or 0), 2, or 4)
-	 * @param padValue     the value of padded bytes
-	 * @param encoder      The CharsetEncoder to use
-	 * @return The modified IoBuffer
-	 * @throws CharacterCodingException When we have an error while decoding the
-	 *                                  CharSequence
-	 */
-	public abstract IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue,
-			CharsetEncoder encoder) throws CharacterCodingException;
-
-	/**
-	 * Reads a Java object from the buffer using the context {@link ClassLoader} of
-	 * the current thread.
-	 * 
-	 * @return The read Object
-	 * @throws ClassNotFoundException thrown when we can't find the Class to use
-	 */
-	public abstract Object getObject() throws ClassNotFoundException;
-
-	/**
-	 * Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
-	 * 
-	 * @param classLoader The classLoader to use to read an Object from the IoBuffer
-	 * @return The read Object
-	 * @throws ClassNotFoundException thrown when we can't find the Class to use
-	 */
-	public abstract Object getObject(final ClassLoader classLoader) throws ClassNotFoundException;
-
-	/**
-	 * Writes the specified Java object to the buffer.
-	 * 
-	 * @param o The Object to write in the IoBuffer
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer putObject(Object o);
-
-	/**
-	 * 
-	 * @param prefixLength the length of the prefix field (1, 2, or 4)
-	 * @return <tt>true</tt> if this buffer contains a data which has a data length
-	 *         as a prefix and the buffer has remaining data as enough as specified
-	 *         in the data length field. This method is identical with
-	 *         <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>.
-	 *         Please not that using this method can allow DoS (Denial of Service)
-	 *         attack in case the remote peer sends too big data length value. It is
-	 *         recommended to use {@link #prefixedDataAvailable(int, int)} instead.
-	 * @throws IllegalArgumentException if prefixLength is wrong
-	 * @throws BufferDataException      if data length is negative
-	 */
-	public abstract boolean prefixedDataAvailable(int prefixLength);
-
-	/**
-	 * @param prefixLength  the length of the prefix field (1, 2, or 4)
-	 * @param maxDataLength the allowed maximum of the read data length
-	 * @return <tt>true</tt> if this buffer contains a data which has a data length
-	 *         as a prefix and the buffer has remaining data as enough as specified
-	 *         in the data length field.
-	 * @throws IllegalArgumentException if prefixLength is wrong
-	 * @throws BufferDataException      if data length is negative or greater then
-	 *                                  <tt>maxDataLength</tt>
-	 */
-	public abstract boolean prefixedDataAvailable(int prefixLength, int maxDataLength);
-
-	// ///////////////////
-	// IndexOf methods //
-	// ///////////////////
-
-	/**
-	 * Returns the first occurrence position of the specified byte from the current
-	 * position to the current limit.
-	 *
-	 * @param b The byte we are looking for
-	 * @return <tt>-1</tt> if the specified byte is not found
-	 */
-	public abstract int indexOf(byte b);
-
-	// ////////////////////////
-	// Skip or fill methods //
-	// ////////////////////////
-
-	/**
-	 * Forwards the position of this buffer as the specified <code>size</code>
-	 * bytes.
-	 * 
-	 * @param size The added size
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer skip(int size);
-
-	/**
-	 * Fills this buffer with the specified value. This method moves buffer position
-	 * forward.
-	 * 
-	 * @param value The value to fill the IoBuffer with
-	 * @param size  The added size
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer fill(byte value, int size);
-
-	/**
-	 * Fills this buffer with the specified value. This method does not change
-	 * buffer position.
-	 *
-	 * @param value The value to fill the IoBuffer with
-	 * @param size  The added size
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer fillAndReset(byte value, int size);
-
-	/**
-	 * Fills this buffer with <code>NUL (0x00)</code>. This method moves buffer
-	 * position forward.
-	 * 
-	 * @param size The added size
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer fill(int size);
-
-	/**
-	 * Fills this buffer with <code>NUL (0x00)</code>. This method does not change
-	 * buffer position.
-	 * 
-	 * @param size The added size
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer fillAndReset(int size);
-
-	// ////////////////////////
-	// Enum methods //
-	// ////////////////////////
-
-	/**
-	 * Reads a byte from the buffer and returns the correlating enum constant
-	 * defined by the specified enum type.
-	 * 
-	 * @param <E>       The enum type to return
-	 * @param enumClass The enum's class object
-	 * @return The correlated enum constant
-	 */
-	public abstract <E extends Enum<E>> E getEnum(Class<E> enumClass);
-
-	/**
-	 * Reads a byte from the buffer and returns the correlating enum constant
-	 * defined by the specified enum type.
-	 * 
-	 * @param <E>       The enum type to return
-	 * @param index     the index from which the byte will be read
-	 * @param enumClass The enum's class object
-	 * @return The correlated enum constant
-	 */
-	public abstract <E extends Enum<E>> E getEnum(int index, Class<E> enumClass);
-
-	/**
-	 * Reads a short from the buffer and returns the correlating enum constant
-	 * defined by the specified enum type.
-	 * 
-	 * @param <E>       The enum type to return
-	 * @param enumClass The enum's class object
-	 * @return The correlated enum constant
-	 */
-	public abstract <E extends Enum<E>> E getEnumShort(Class<E> enumClass);
-
-	/**
-	 * Reads a short from the buffer and returns the correlating enum constant
-	 * defined by the specified enum type.
-	 * 
-	 * @param <E>       The enum type to return
-	 * @param index     the index from which the bytes will be read
-	 * @param enumClass The enum's class object
-	 * @return The correlated enum constant
-	 */
-	public abstract <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass);
-
-	/**
-	 * Reads an int from the buffer and returns the correlating enum constant
-	 * defined by the specified enum type.
-	 * 
-	 * @param <E>       The enum type to return
-	 * @param enumClass The enum's class object
-	 * @return The correlated enum constant
-	 */
-	public abstract <E extends Enum<E>> E getEnumInt(Class<E> enumClass);
-
-	/**
-	 * Reads an int from the buffer and returns the correlating enum constant
-	 * defined by the specified enum type.
-	 * 
-	 * @param <E>       The enum type to return
-	 * @param index     the index from which the bytes will be read
-	 * @param enumClass The enum's class object
-	 * @return The correlated enum constant
-	 */
-	public abstract <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass);
-
-	/**
-	 * Writes an enum's ordinal value to the buffer as a byte.
-	 * 
-	 * @param e The enum to write to the buffer
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer putEnum(Enum<?> e);
-
-	/**
-	 * Writes an enum's ordinal value to the buffer as a byte.
-	 * 
-	 * @param index The index at which the byte will be written
-	 * @param e     The enum to write to the buffer
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer putEnum(int index, Enum<?> e);
-
-	/**
-	 * Writes an enum's ordinal value to the buffer as a short.
-	 * 
-	 * @param e The enum to write to the buffer
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer putEnumShort(Enum<?> e);
-
-	/**
-	 * Writes an enum's ordinal value to the buffer as a short.
-	 * 
-	 * @param index The index at which the bytes will be written
-	 * @param e     The enum to write to the buffer
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer putEnumShort(int index, Enum<?> e);
-
-	/**
-	 * Writes an enum's ordinal value to the buffer as an integer.
-	 * 
-	 * @param e The enum to write to the buffer
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer putEnumInt(Enum<?> e);
-
-	/**
-	 * Writes an enum's ordinal value to the buffer as an integer.
-	 * 
-	 * @param index The index at which the bytes will be written
-	 * @param e     The enum to write to the buffer
-	 * @return The modified IoBuffer
-	 */
-	public abstract IoBuffer putEnumInt(int index, Enum<?> e);
-
-	// ////////////////////////
-	// EnumSet methods //
-	// ////////////////////////
-
-	/**
-	 * Reads a byte sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * <p>
-	 * Each bit is mapped to a value in the specified enum. The least significant
-	 * bit maps to the first entry in the specified enum and each subsequent bit
-	 * maps to each subsequent bit as mapped to the subsequent enum value.
-	 * 
-	 * @param <E>       the enum type
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSet(Class<E> enumClass);
-
-	/**
-	 * Reads a byte sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * @see #getEnumSet(Class)
-	 * @param <E>       the enum type
-	 * @param index     the index from which the byte will be read
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSet(int index, Class<E> enumClass);
-
-	/**
-	 * Reads a short sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * @see #getEnumSet(Class)
-	 * @param <E>       the enum type
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSetShort(Class<E> enumClass);
-
-	/**
-	 * Reads a short sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * @see #getEnumSet(Class)
-	 * @param <E>       the enum type
-	 * @param index     the index from which the bytes will be read
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSetShort(int index, Class<E> enumClass);
-
-	/**
-	 * Reads an int sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * @see #getEnumSet(Class)
-	 * @param <E>       the enum type
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSetInt(Class<E> enumClass);
-
-	/**
-	 * Reads an int sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * @see #getEnumSet(Class)
-	 * @param <E>       the enum type
-	 * @param index     the index from which the bytes will be read
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSetInt(int index, Class<E> enumClass);
-
-	/**
-	 * Reads a long sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * @see #getEnumSet(Class)
-	 * @param <E>       the enum type
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSetLong(Class<E> enumClass);
-
-	/**
-	 * Reads a long sized bit vector and converts it to an {@link EnumSet}.
-	 * 
-	 * @see #getEnumSet(Class)
-	 * @param <E>       the enum type
-	 * @param index     the index from which the bytes will be read
-	 * @param enumClass the enum class used to create the EnumSet
-	 * @return the EnumSet representation of the bit vector
-	 */
-	public abstract <E extends Enum<E>> Set<E> getEnumSetLong(int index, Class<E> enumClass);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as a byte sized bit vector.
-	 * 
-	 * @param <E> the enum type of the Set
-	 * @param set the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as a byte sized bit vector.
-	 * 
-	 * @param <E>   the enum type of the Set
-	 * @param index the index at which the byte will be written
-	 * @param set   the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as a short sized bit vector.
-	 * 
-	 * @param <E> the enum type of the Set
-	 * @param set the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as a short sized bit vector.
-	 * 
-	 * @param <E>   the enum type of the Set
-	 * @param index the index at which the bytes will be written
-	 * @param set   the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as an int sized bit vector.
-	 * 
-	 * @param <E> the enum type of the Set
-	 * @param set the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as an int sized bit vector.
-	 * 
-	 * @param <E>   the enum type of the Set
-	 * @param index the index at which the bytes will be written
-	 * @param set   the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as a long sized bit vector.
-	 * 
-	 * @param <E> the enum type of the Set
-	 * @param set the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set);
-
-	/**
-	 * Writes the specified {@link Set} to the buffer as a long sized bit vector.
-	 * 
-	 * @param <E>   the enum type of the Set
-	 * @param index the index at which the bytes will be written
-	 * @param set   the enum set to write to the buffer
-	 * @return the modified IoBuffer
-	 */
-	public abstract <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set);
+    /** The allocator used to create new buffers */
+    private static IoBufferAllocator allocator = new SimpleBufferAllocator();
+
+    /** A flag indicating which type of buffer we are using : heap or direct */
+    private static boolean useDirectBuffer = false;
+
+    /**
+     * Creates a new instance. This is an empty constructor. It's protected, to
+     * forbid its usage by the users.
+     */
+    protected IoBuffer() {
+        // Do nothing
+    }
+
+    /**
+     * @return the allocator used by existing and new buffers
+     */
+    public static IoBufferAllocator getAllocator() {
+        return allocator;
+    }
+
+    /**
+     * Sets the allocator used by existing and new buffers
+     * 
+     * @param newAllocator the new allocator to use
+     */
+    public static void setAllocator(IoBufferAllocator newAllocator) {
+        if (newAllocator == null) {
+            throw new IllegalArgumentException("allocator");
+        }
+
+        IoBufferAllocator oldAllocator = allocator;
+
+        allocator = newAllocator;
+
+        if (null != oldAllocator) {
+            oldAllocator.dispose();
+        }
+    }
+
+    /**
+     * @return <tt>true</tt> if and only if a direct buffer is allocated by default
+     *         when the type of the new buffer is not specified. The default value
+     *         is <tt>false</tt>.
+     */
+    public static boolean isUseDirectBuffer() {
+        return useDirectBuffer;
+    }
+
+    /**
+     * Sets if a direct buffer should be allocated by default when the type of the
+     * new buffer is not specified. The default value is <tt>false</tt>.
+     * 
+     * @param useDirectBuffer Tells if direct buffers should be allocated
+     */
+    public static void setUseDirectBuffer(boolean useDirectBuffer) {
+        IoBuffer.useDirectBuffer = useDirectBuffer;
+    }
+
+    /**
+     * Returns the direct or heap buffer which is capable to store the specified
+     * amount of bytes.
+     * 
+     * @param capacity the capacity of the buffer
+     * @return a IoBuffer which can hold up to capacity bytes
+     * 
+     * @see #setUseDirectBuffer(boolean)
+     */
+    public static IoBuffer allocate(int capacity) {
+        return allocate(capacity, useDirectBuffer);
+    }
+
+    /**
+     * Returns a direct or heap IoBuffer which can contain the specified number of
+     * bytes.
+     * 
+     * @param capacity        the capacity of the buffer
+     * @param useDirectBuffer <tt>true</tt> to get a direct buffer, <tt>false</tt>
+     *                        to get a heap buffer.
+     * @return a direct or heap IoBuffer which can hold up to capacity bytes
+     */
+    public static IoBuffer allocate(int capacity, boolean useDirectBuffer) {
+        if (capacity < 0) {
+            throw new IllegalArgumentException("capacity: " + capacity);
+        }
+
+        return allocator.allocate(capacity, useDirectBuffer);
+    }
+
+    /**
+     * Wraps the specified NIO {@link ByteBuffer} into a MINA buffer (either direct
+     * or heap).
+     * 
+     * @param nioBuffer The {@link ByteBuffer} to wrap
+     * @return a IoBuffer containing the bytes stored in the {@link ByteBuffer}
+     */
+    public static IoBuffer wrap(ByteBuffer nioBuffer) {
+        return allocator.wrap(nioBuffer);
+    }
+
+    /**
+     * Wraps the specified byte array into a MINA heap buffer. Note that the byte
+     * array is not copied, so any modification done on it will be visible by both
+     * sides.
+     * 
+     * @param byteArray The byte array to wrap
+     * @return a heap IoBuffer containing the byte array
+     */
+    public static IoBuffer wrap(byte[] byteArray) {
+        return wrap(ByteBuffer.wrap(byteArray));
+    }
+
+    /**
+     * Wraps the specified byte array into MINA heap buffer. We just wrap the bytes
+     * starting from offset up to offset + length. Note that the byte array is not
+     * copied, so any modification done on it will be visible by both sides.
+     * 
+     * @param byteArray The byte array to wrap
+     * @param offset    The starting point in the byte array
+     * @param length    The number of bytes to store
+     * @return a heap IoBuffer containing the selected part of the byte array
+     */
+    public static IoBuffer wrap(byte[] byteArray, int offset, int length) {
+        return wrap(ByteBuffer.wrap(byteArray, offset, length));
+    }
+
+    /**
+     * Normalizes the specified capacity of the buffer to power of 2, which is often
+     * helpful for optimal memory usage and performance. If it is greater than or
+     * equal to {@link Integer#MAX_VALUE}, it returns {@link Integer#MAX_VALUE}. If
+     * it is zero, it returns zero.
+     * 
+     * @param requestedCapacity The IoBuffer capacity we want to be able to store
+     * @return The power of 2 strictly superior to the requested capacity
+     */
+    protected static int normalizeCapacity(int requestedCapacity) {
+        if (requestedCapacity < 0) {
+            return Integer.MAX_VALUE;
+        }
+
+        int newCapacity = Integer.highestOneBit(requestedCapacity);
+        newCapacity <<= (newCapacity < requestedCapacity ? 1 : 0);
+
+        return newCapacity < 0 ? Integer.MAX_VALUE : newCapacity;
+    }
+
+    /**
+     * Declares this buffer and all its derived buffers are not used anymore so that
+     * it can be reused by some {@link IoBufferAllocator} implementations. It is not
+     * mandatory to call this method, but you might want to invoke this method for
+     * maximum performance.
+     */
+    public abstract void free();
+
+    /**
+     * @return the underlying NIO {@link ByteBuffer} instance.
+     */
+    public abstract ByteBuffer buf();
+
+    /**
+     * @see ByteBuffer#isDirect()
+     * 
+     * @return <tt>True</tt> if this is a direct buffer
+     */
+    public abstract boolean isDirect();
+
+    /**
+     * @return <tt>true</tt> if and only if this buffer is derived from another
+     *         buffer via one of the {@link #duplicate()}, {@link #slice()} or
+     *         {@link #asReadOnlyBuffer()} methods.
+     */
+    public abstract boolean isDerived();
+
+    /**
+     * @see ByteBuffer#isReadOnly()
+     * 
+     * @return <tt>true</tt> if the buffer is readOnly
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * @return the minimum capacity of this buffer which is used to determine the
+     *         new capacity of the buffer shrunk by the {@link #compact()} and
+     *         {@link #shrink()} operation. The default value is the initial
+     *         capacity of the buffer.
+     */
+    public abstract int minimumCapacity();
+
+    /**
+     * Sets the minimum capacity of this buffer which is used to determine the new
+     * capacity of the buffer shrunk by {@link #compact()} and {@link #shrink()}
+     * operation. The default value is the initial capacity of the buffer.
+     * 
+     * @param minimumCapacity the wanted minimum capacity
+     * @return the underlying NIO {@link ByteBuffer} instance.
+     */
+    public abstract IoBuffer minimumCapacity(int minimumCapacity);
+
+    /**
+     * @see ByteBuffer#capacity()
+     * 
+     * @return the buffer capacity
+     */
+    public abstract int capacity();
+
+    /**
+     * Increases the capacity of this buffer. If the new capacity is less than or
+     * equal to the current capacity, this method returns the original buffer. If
+     * the new capacity is greater than the current capacity, the buffer is
+     * reallocated while retaining the position, limit, mark and the content of the
+     * buffer. <br>
+     * Note that the IoBuffer is replaced, it's not copied. <br>
+     * Assuming a buffer contains N bytes, its position is 0 and its current
+     * capacity is C, here are the resulting buffer if we set the new capacity to a
+     * value V &lt; C and V &gt; C :
+     * 
+     * <pre>
+     *  Initial buffer :
+     *   
+     *   0       L          C
+     *  +--------+----------+
+     *  |XXXXXXXX|          |
+     *  +--------+----------+
+     *   ^       ^          ^
+     *   |       |          |
+     *  pos    limit     capacity
+     *  
+     * V &lt;= C :
+     * 
+     *   0       L          C
+     *  +--------+----------+
+     *  |XXXXXXXX|          |
+     *  +--------+----------+
+     *   ^       ^          ^
+     *   |       |          |
+     *  pos    limit   newCapacity
+     *  
+     * V &gt; C :
+     * 
+     *   0       L          C            V
+     *  +--------+-----------------------+
+     *  |XXXXXXXX|          :            |
+     *  +--------+-----------------------+
+     *   ^       ^          ^            ^
+     *   |       |          |            |
+     *  pos    limit   oldCapacity  newCapacity
+     *  
+     *  The buffer has been increased.
+     * 
+     * </pre>
+     * 
+     * @param newCapacity the wanted capacity
+     * @return the underlying NIO {@link ByteBuffer} instance.
+     */
+    public abstract IoBuffer capacity(int newCapacity);
+
+    /**
+     * @return <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on.
+     */
+    public abstract boolean isAutoExpand();
+
+    /**
+     * Turns on or off <tt>autoExpand</tt>.
+     * 
+     * @param autoExpand The flag value to set
+     * @return The modified IoBuffer instance
+     */
+    public abstract IoBuffer setAutoExpand(boolean autoExpand);
+
+    /**
+     * @return <tt>true</tt> if and only if <tt>autoShrink</tt> is turned on.
+     */
+    public abstract boolean isAutoShrink();
+
+    /**
+     * Turns on or off <tt>autoShrink</tt>.
+     * 
+     * @param autoShrink The flag value to set
+     * @return The modified IoBuffer instance
+     */
+    public abstract IoBuffer setAutoShrink(boolean autoShrink);
+
+    /**
+     * Changes the capacity and limit of this buffer so this buffer get the
+     * specified <tt>expectedRemaining</tt> room from the current position. This
+     * method works even if you didn't set <tt>autoExpand</tt> to <tt>true</tt>.
+     * <br>
+     * Assuming a buffer contains N bytes, its position is P and its current
+     * capacity is C, here are the resulting buffer if we call the expand method
+     * with a expectedRemaining value V :
+     * 
+     * <pre>
+     *  Initial buffer :
+     *   
+     *   0       L          C
+     *  +--------+----------+
+     *  |XXXXXXXX|          |
+     *  +--------+----------+
+     *   ^       ^          ^
+     *   |       |          |
+     *  pos    limit     capacity
+     *  
+     * ( pos + V )  &lt;= L, no change :
+     * 
+     *   0       L          C
+     *  +--------+----------+
+     *  |XXXXXXXX|          |
+     *  +--------+----------+
+     *   ^       ^          ^
+     *   |       |          |
+     *  pos    limit   newCapacity
+     *  
+     * You can still put ( L - pos ) bytes in the buffer
+     *  
+     * ( pos + V ) &gt; L &amp; ( pos + V ) &lt;= C :
+     * 
+     *  0        L          C
+     *  +------------+------+
+     *  |XXXXXXXX:...|      |
+     *  +------------+------+
+     *   ^           ^      ^
+     *   |           |      |
+     *  pos       newlimit  newCapacity
+     *  
+     *  You can now put ( L - pos + V )  bytes in the buffer.
+     *  
+     *  
+     *  ( pos + V ) &gt; C
+     * 
+     *   0       L          C
+     *  +-------------------+----+
+     *  |XXXXXXXX:..........:....|
+     *  +------------------------+
+     *   ^                       ^
+     *   |                       |
+     *  pos                      +-- newlimit
+     *                           |
+     *                           +-- newCapacity
+     *                           
+     * You can now put ( L - pos + V ) bytes in the buffer, which limit is now
+     * equals to the capacity.
+     * </pre>
+     *
+     * Note that the expecting remaining bytes starts at the current position. In
+     * all those examples, the position is 0.
+     * 
+     * @param expectedRemaining The expected remaining bytes in the buffer
+     * @return The modified IoBuffer instance
+     */
+    public abstract IoBuffer expand(int expectedRemaining);
+
+    /**
+     * Changes the capacity and limit of this buffer so this buffer get the
+     * specified <tt>expectedRemaining</tt> room from the specified
+     * <tt>position</tt>. This method works even if you didn't set
+     * <tt>autoExpand</tt> to <tt>true</tt>. Assuming a buffer contains N bytes, its
+     * position is P and its current capacity is C, here are the resulting buffer if
+     * we call the expand method with a expectedRemaining value V :
+     * 
+     * <pre>
+     *  Initial buffer :
+     *   
+     *      P    L          C
+     *  +--------+----------+
+     *  |XXXXXXXX|          |
+     *  +--------+----------+
+     *      ^    ^          ^
+     *      |    |          |
+     *     pos limit     capacity
+     *  
+     * ( pos + V )  &lt;= L, no change :
+     * 
+     *      P    L          C
+     *  +--------+----------+
+     *  |XXXXXXXX|          |
+     *  +--------+----------+
+     *      ^    ^          ^
+     *      |    |          |
+     *     pos limit   newCapacity
+     *  
+     * You can still put ( L - pos ) bytes in the buffer
+     *  
+     * ( pos + V ) &gt; L &amp; ( pos + V ) &lt;= C :
+     * 
+     *      P    L          C
+     *  +------------+------+
+     *  |XXXXXXXX:...|      |
+     *  +------------+------+
+     *      ^        ^      ^
+     *      |        |      |
+     *     pos    newlimit  newCapacity
+     *  
+     *  You can now put ( L - pos + V)  bytes in the buffer.
+     *  
+     *  
+     *  ( pos + V ) &gt; C
+     * 
+     *      P       L          C
+     *  +-------------------+----+
+     *  |XXXXXXXX:..........:....|
+     *  +------------------------+
+     *      ^                    ^
+     *      |                    |
+     *     pos                   +-- newlimit
+     *                           |
+     *                           +-- newCapacity
+     *                           
+     * You can now put ( L - pos + V ) bytes in the buffer, which limit is now
+     * equals to the capacity.
+     * </pre>
+     *
+     * Note that the expecting remaining bytes starts at the current position. In
+     * all those examples, the position is P.
+     * 
+     * @param position          The starting position from which we want to define a
+     *                          remaining number of bytes
+     * @param expectedRemaining The expected remaining bytes in the buffer
+     * @return The modified IoBuffer instance
+     */
+    public abstract IoBuffer expand(int position, int expectedRemaining);
+
+    /**
+     * Changes the capacity of this buffer so this buffer occupies as less memory as
+     * possible while retaining the position, limit and the buffer content between
+     * the position and limit. <br>
+     * <b>The capacity of the buffer never becomes less than
+     * {@link #minimumCapacity()}</b> <br>
+     * . The mark is discarded once the capacity changes. <br>
+     * Typically, a call to this method tries to remove as much unused bytes as
+     * possible, dividing by two the initial capacity until it can't without
+     * obtaining a new capacity lower than the {@link #minimumCapacity()}. For
+     * instance, if the limit is 7 and the capacity is 36, with a minimum capacity
+     * of 8, shrinking the buffer will left a capacity of 9 (we go down from 36 to
+     * 18, then from 18 to 9).
+     * 
+     * <pre>
+     *  Initial buffer :
+     *   
+     *  +--------+----------+
+     *  |XXXXXXXX|          |
+     *  +--------+----------+
+     *      ^    ^  ^       ^
+     *      |    |  |       |
+     *     pos   |  |    capacity
+     *           |  |
+     *           |  +-- minimumCapacity
+     *           |
+     *           +-- limit
+     * 
+     * Resulting buffer :
+     * 
+     *  +--------+--+-+
+     *  |XXXXXXXX|  | |
+     *  +--------+--+-+
+     *      ^    ^  ^ ^
+     *      |    |  | |
+     *      |    |  | +-- new capacity
+     *      |    |  |
+     *     pos   |  +-- minimum capacity
+     *           |
+     *           +-- limit
+     * </pre>
+     * 
+     * @return The modified IoBuffer instance
+     */
+    public abstract IoBuffer shrink();
+
+    /**
+     * @see java.nio.Buffer#position()
+     * @return The current position in the buffer
+     */
+    public abstract int position();
+
+    /**
+     * @see java.nio.Buffer#position(int)
+     * 
+     * @param newPosition Sets the new position in the buffer
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer position(int newPosition);
+
+    /**
+     * @see java.nio.Buffer#limit()
+     * 
+     * @return the modified IoBuffer 's limit
+     */
+    public abstract int limit();
+
+    /**
+     * @see java.nio.Buffer#limit(int)
+     * 
+     * @param newLimit The new buffer's limit
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer limit(int newLimit);
+
+    /**
+     * @see java.nio.Buffer#mark()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer mark();
+
+    /**
+     * @return the position of the current mark. This method returns <tt>-1</tt> if
+     *         no mark is set.
+     */
+    public abstract int markValue();
+
+    /**
+     * @see java.nio.Buffer#reset()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer reset();
+
+    /**
+     * @see java.nio.Buffer#clear()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer clear();
+
+    /**
+     * Clears this buffer and fills its content with <tt>NUL</tt>. The position is
+     * set to zero, the limit is set to the capacity, and the mark is discarded.
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer sweep();
+
+    /**
+     * double Clears this buffer and fills its content with <tt>value</tt>. The
+     * position is set to zero, the limit is set to the capacity, and the mark is
+     * discarded.
+     *
+     * @param value The value to put in the buffer
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer sweep(byte value);
+
+    /**
+     * @see java.nio.Buffer#flip()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer flip();
+
+    /**
+     * @see java.nio.Buffer#rewind()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer rewind();
+
+    /**
+     * @see java.nio.Buffer#remaining()
+     * 
+     * @return The remaining bytes in the buffer
+     */
+    public abstract int remaining();
+
+    /**
+     * @see java.nio.Buffer#hasRemaining()
+     * 
+     * @return <tt>true</tt> if there are some remaining bytes in the buffer
+     */
+    public abstract boolean hasRemaining();
+
+    /**
+     * @see ByteBuffer#duplicate()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer duplicate();
+
+    /**
+     * @see ByteBuffer#slice()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer slice();
+
+    /**
+     * @see ByteBuffer#asReadOnlyBuffer()
+     * 
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer asReadOnlyBuffer();
+
+    /**
+     * @see ByteBuffer#hasArray()
+     * 
+     * @return <tt>true</tt> if the {@link #array()} method will return a byte[]
+     */
+    public abstract boolean hasArray();
+
+    /**
+     * @see ByteBuffer#array()
+     * 
+     * @return A byte[] if this IoBuffer supports it
+     */
+    public abstract byte[] array();
+
+    /**
+     * @see ByteBuffer#arrayOffset()
+     * 
+     * @return The offset in the returned byte[] when the {@link #array()} method is
+     *         called
+     */
+    public abstract int arrayOffset();
+
+    /**
+     * @see ByteBuffer#get()
+     * 
+     * @return The byte at the current position
+     */
+    public abstract byte get();
+
+    /**
+     * Reads one unsigned byte as a short integer.
+     * 
+     * @return the unsigned short at the current position
+     */
+    public abstract short getUnsigned();
+
+    /**
+     * @see ByteBuffer#put(byte)
+     * 
+     * @param b The byte to put in the buffer
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer put(byte b);
+
+    /**
+     * @see ByteBuffer#get(int)
+     * 
+     * @param index The position for which we want to read a byte
+     * @return the byte at the given position
+     */
+    public abstract byte get(int index);
+
+    /**
+     * Reads one byte as an unsigned short integer.
+     * 
+     * @param index The position for which we want to read an unsigned byte
+     * @return the unsigned byte at the given position
+     */
+    public abstract short getUnsigned(int index);
+
+    /**
+     * @see ByteBuffer#put(int, byte)
+     * 
+     * @param index The position where the byte will be put
+     * @param b     The byte to put
+     * @return the modified IoBuffer
+     * 
+     */
+    public abstract IoBuffer put(int index, byte b);
+
+    /**
+     * @see ByteBuffer#get(byte[], int, int)
+     * 
+     * @param dst    The destination buffer
+     * @param offset The position in the original buffer
+     * @param length The number of bytes to copy
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer get(byte[] dst, int offset, int length);
+
+    /**
+     * @see ByteBuffer#get(byte[])
+     *
+     * @param dst The byte[] that will contain the read bytes
+     * @return the IoBuffer
+     */
+    public abstract IoBuffer get(byte[] dst);
+
+    /**
+     * Get a new IoBuffer containing a slice of the current buffer
+     * 
+     * @param index  The position in the buffer
+     * @param length The number of bytes to copy
+     * @return the new IoBuffer
+     */
+    public abstract IoBuffer getSlice(int index, int length);
+
+    /**
+     * Get a new IoBuffer containing a slice of the current buffer
+     * 
+     * @param length The number of bytes to copy
+     * @return the new IoBuffer
+     */
+    public abstract IoBuffer getSlice(int length);
+
+    /**
+     * Writes the content of the specified <tt>src</tt> into this buffer.
+     * 
+     * @param src The source ByteBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer put(ByteBuffer src);
+
+    /**
+     * Writes the content of the specified <tt>src</tt> into this buffer.
+     * 
+     * @param src The source IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer put(IoBuffer src);
+
+    /**
+     * @see ByteBuffer#put(byte[], int, int)
+     * 
+     * @param src    The byte[] to put
+     * @param offset The position in the source
+     * @param length The number of bytes to copy
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer put(byte[] src, int offset, int length);
+
+    /**
+     * @see ByteBuffer#put(byte[])
+     * 
+     * @param src The byte[] to put
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer put(byte[] src);
+
+    /**
+     * @see ByteBuffer#compact()
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer compact();
+
+    /**
+     * @see ByteBuffer#order()
+     * 
+     * @return the IoBuffer ByteOrder
+     */
+    public abstract ByteOrder order();
+
+    /**
+     * @see ByteBuffer#order(ByteOrder)
+     * 
+     * @param bo The new ByteBuffer to use for this IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer order(ByteOrder bo);
+
+    /**
+     * @see ByteBuffer#getChar()
+     * 
+     * @return The char at the current position
+     */
+    public abstract char getChar();
+
+    /**
+     * @see ByteBuffer#putChar(char)
+     * 
+     * @param value The char to put at the current position
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putChar(char value);
+
+    /**
+     * @see ByteBuffer#getChar(int)
+     * 
+     * @param index The index in the IoBuffer where we will read a char from
+     * @return the char at 'index' position
+     */
+    public abstract char getChar(int index);
+
+    /**
+     * @see ByteBuffer#putChar(int, char)
+     * 
+     * @param index The index in the IoBuffer where we will put a char in
+     * @param value The char to put at the current position
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putChar(int index, char value);
+
+    /**
+     * @see ByteBuffer#asCharBuffer()
+     * 
+     * @return a new CharBuffer
+     */
+    public abstract CharBuffer asCharBuffer();
+
+    /**
+     * @see ByteBuffer#getShort()
+     * 
+     * @return The read short
+     */
+    public abstract short getShort();
+
+    /**
+     * Reads two bytes unsigned integer.
+     * 
+     * @return The read unsigned short
+     */
+    public abstract int getUnsignedShort();
+
+    /**
+     * @see ByteBuffer#putShort(short)
+     * 
+     * @param value The short to put at the current position
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putShort(short value);
+
+    /**
+     * @see ByteBuffer#getShort()
+     * 
+     * @param index The index in the IoBuffer where we will read a short from
+     * @return The read short
+     */
+    public abstract short getShort(int index);
+
+    /**
+     * Reads two bytes unsigned integer.
+     * 
+     * @param index The index in the IoBuffer where we will read an unsigned short
+     *              from
+     * @return the unsigned short at the given position
+     */
+    public abstract int getUnsignedShort(int index);
+
+    /**
+     * @see ByteBuffer#putShort(int, short)
+     * 
+     * @param index The position at which the short should be written
+     * @param value The short to put at the current position
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putShort(int index, short value);
+
+    /**
+     * @see ByteBuffer#asShortBuffer()
+     * 
+     * @return A ShortBuffer from this IoBuffer
+     */
+    public abstract ShortBuffer asShortBuffer();
+
+    /**
+     * @see ByteBuffer#getInt()
+     * 
+     * @return The int read
+     */
+    public abstract int getInt();
+
+    /**
+     * Reads four bytes unsigned integer.
+     * 
+     * @return The unsigned int read
+     */
+    public abstract long getUnsignedInt();
+
+    /**
+     * Relative <i>get</i> method for reading a medium int value.
+     * 
+     * <p>
+     * Reads the next three bytes at this buffer's current position, composing them
+     * into an int value according to the current byte order, and then increments
+     * the position by three.
+     * 
+     * @return The medium int value at the buffer's current position
+     */
+    public abstract int getMediumInt();
+
+    /**
+     * Relative <i>get</i> method for reading an unsigned medium int value.
+     * 
+     * <p>
+     * Reads the next three bytes at this buffer's current position, composing them
+     * into an int value according to the current byte order, and then increments
+     * the position by three.
+     * 
+     * @return The unsigned medium int value at the buffer's current position
+     */
+    public abstract int getUnsignedMediumInt();
+
+    /**
+     * Absolute <i>get</i> method for reading a medium int value.
+     * 
+     * <p>
+     * Reads the next three bytes at this buffer's current position, composing them
+     * into an int value according to the current byte order.
+     * 
+     * @param index The index from which the medium int will be read
+     * @return The medium int value at the given index
+     * 
+     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative or not
+     *                                   smaller than the buffer's limit
+     */
+    public abstract int getMediumInt(int index);
+
+    /**
+     * Absolute <i>get</i> method for reading an unsigned medium int value.
+     * 
+     * <p>
+     * Reads the next three bytes at this buffer's current position, composing them
+     * into an int value according to the current byte order.
+     * 
+     * @param index The index from which the unsigned medium int will be read
+     * @return The unsigned medium int value at the given index
+     * 
+     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative or not
+     *                                   smaller than the buffer's limit
+     */
+    public abstract int getUnsignedMediumInt(int index);
+
+    /**
+     * Relative <i>put</i> method for writing a medium int value.
+     * 
+     * <p>
+     * Writes three bytes containing the given int value, in the current byte order,
+     * into this buffer at the current position, and then increments the position by
+     * three.
+     * 
+     * @param value The medium int value to be written
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putMediumInt(int value);
+
+    /**
+     * Absolute <i>put</i> method for writing a medium int value.
+     * 
+     * <p>
+     * Writes three bytes containing the given int value, in the current byte order,
+     * into this buffer at the given index.
+     * 
+     * @param index The index at which the bytes will be written
+     * 
+     * @param value The medium int value to be written
+     * 
+     * @return the modified IoBuffer
+     * 
+     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative or not
+     *                                   smaller than the buffer's limit, minus
+     *                                   three
+     */
+    public abstract IoBuffer putMediumInt(int index, int value);
+
+    /**
+     * @see ByteBuffer#putInt(int)
+     * 
+     * @param value The int to put at the current position
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putInt(int value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer
+     * 
+     * @param value the byte to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(byte value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the byte to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(int index, byte value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer
+     * 
+     * @param value the short to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(short value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the short to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(int index, short value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer
+     * 
+     * @param value the int to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(int value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the int to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(int index, int value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer
+     * 
+     * @param value the long to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(long value);
+
+    /**
+     * Writes an unsigned byte into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the long to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsigned(int index, long value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer
+     * 
+     * @param value the byte to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(byte value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the byte to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(int index, byte value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer
+     * 
+     * @param value the short to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(short value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the short to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(int index, short value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer
+     * 
+     * @param value the int to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(int value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the int to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(int index, int value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer
+     * 
+     * @param value the long to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(long value);
+
+    /**
+     * Writes an unsigned int into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the long to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedInt(int index, long value);
+
+    /**
+     * Writes an unsigned short into the ByteBuffer
+     * 
+     * @param value the byte to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(byte value);
+
+    /**
+     * Writes an unsigned Short into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the byte to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(int index, byte value);
+
+    /**
+     * Writes an unsigned Short into the ByteBuffer
+     * 
+     * @param value the short to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(short value);
+
+    /**
+     * Writes an unsigned Short into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the unsigned short
+     * @param value the unsigned short to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(int index, short value);
+
+    /**
+     * Writes an unsigned Short into the ByteBuffer
+     * 
+     * @param value the int to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(int value);
+
+    /**
+     * Writes an unsigned Short into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the value
+     * @param value the int to write
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(int index, int value);
+
+    /**
+     * Writes an unsigned Short into the ByteBuffer
+     * 
+     * @param value the long to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(long value);
+
+    /**
+     * Writes an unsigned Short into the ByteBuffer at a specified position
+     * 
+     * @param index the position in the buffer to write the short
+     * @param value the long to write
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putUnsignedShort(int index, long value);
+
+    /**
+     * @see ByteBuffer#getInt(int)
+     * @param index The index in the IoBuffer where we will read an int from
+     * @return the int at the given position
+     */
+    public abstract int getInt(int index);
+
+    /**
+     * Reads four bytes unsigned integer.
+     * 
+     * @param index The index in the IoBuffer where we will read an unsigned int
+     *              from
+     * @return The long at the given position
+     */
+    public abstract long getUnsignedInt(int index);
+
+    /**
+     * @see ByteBuffer#putInt(int, int)
+     * 
+     * @param index The position where to put the int
+     * @param value The int to put in the IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putInt(int index, int value);
+
+    /**
+     * @see ByteBuffer#asIntBuffer()
+     * 
+     * @return the modified IoBuffer
+     */
+    public abstract IntBuffer asIntBuffer();
+
+    /**
+     * @see ByteBuffer#getLong()
+     * 
+     * @return The long at the current position
+     */
+    public abstract long getLong();
+
+    /**
+     * @see ByteBuffer#putLong(int, long)
+     * 
+     * @param value The log to put in the IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putLong(long value);
+
+    /**
+     * @see ByteBuffer#getLong(int)
+     * 
+     * @param index The index in the IoBuffer where we will read a long from
+     * @return the long at the given position
+     */
+    public abstract long getLong(int index);
+
+    /**
+     * @see ByteBuffer#putLong(int, long)
+     * 
+     * @param index The position where to put the long
+     * @param value The long to put in the IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putLong(int index, long value);
+
+    /**
+     * @see ByteBuffer#asLongBuffer()
+     * 
+     * @return a LongBuffer from this IoBffer
+     */
+    public abstract LongBuffer asLongBuffer();
+
+    /**
+     * @see ByteBuffer#getFloat()
+     * 
+     * @return the float at the current position
+     */
+    public abstract float getFloat();
+
+    /**
+     * @see ByteBuffer#putFloat(float)
+     *
+     * @param value The float to put in the IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putFloat(float value);
+
+    /**
+     * @see ByteBuffer#getFloat(int)
+     * 
+     * @param index The index in the IoBuffer where we will read a float from
+     * @return The float at the given position
+     */
+    public abstract float getFloat(int index);
+
+    /**
+     * @see ByteBuffer#putFloat(int, float)
+     * 
+     * @param index The position where to put the float
+     * @param value The float to put in the IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putFloat(int index, float value);
+
+    /**
+     * @see ByteBuffer#asFloatBuffer()
+     * 
+     * @return A FloatBuffer from this IoBuffer
+     */
+    public abstract FloatBuffer asFloatBuffer();
+
+    /**
+     * @see ByteBuffer#getDouble()
+     * 
+     * @return the double at the current position
+     */
+    public abstract double getDouble();
+
+    /**
+     * @see ByteBuffer#putDouble(double)
+     * 
+     * @param value The double to put at the IoBuffer current position
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putDouble(double value);
+
+    /**
+     * @see ByteBuffer#getDouble(int)
+     * 
+     * @param index The position where to get the double from
+     * @return The double at the given position
+     */
+    public abstract double getDouble(int index);
+
+    /**
+     * @see ByteBuffer#putDouble(int, double)
+     * 
+     * @param index The position where to put the double
+     * @param value The double to put in the IoBuffer
+     * @return the modified IoBuffer
+     */
+    public abstract IoBuffer putDouble(int index, double value);
+
+    /**
+     * @see ByteBuffer#asDoubleBuffer()
+     * 
+     * @return A buffer containing Double
+     */
+    public abstract DoubleBuffer asDoubleBuffer();
+
+    /**
+     * @return 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 abstract InputStream asInputStream();
+
+    /**
+     * @return 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 abstract OutputStream asOutputStream();
+
+    /**
+     * Returns hexdump of this buffer. The data and pointer are not changed as a
+     * result of this method call.
+     * 
+     * @return hexidecimal representation of this buffer
+     */
+    public String getHexDump() {
+        return this.getHexDump(this.remaining(), false);
+    }
+
+    /**
+     * Returns hexdump of this buffer. The data and pointer are not changed as a
+     * result of this method call.
+     * 
+     * @return hexidecimal representation of this buffer
+     */
+    public String getHexDump(boolean pretty) {
+        return getHexDump(this.remaining(), pretty);
+    }
+
+    /**
+     * Return hexdump of this buffer with limited length.
+     * 
+     * @param length The maximum number of bytes to dump from the current buffer
+     *               position.
+     * @return hexidecimal representation of this buffer
+     */
+    public String getHexDump(int length) {
+        return getHexDump(length, false);
+    }
+
+    /**
+     * Return hexdump of this buffer with limited length.
+     * 
+     * @param length The maximum number of bytes to dump from the current buffer
+     *               position.
+     * @return hexidecimal representation of this buffer
+     */
+    public String getHexDump(int length, boolean pretty) {
+        return (pretty) ? IoBufferHexDumper.getPrettyHexDumpSlice(this, this.position(), Math.min(this.remaining(), length))
+                : IoBufferHexDumper.getHexDumpSlice(this, this.position(), Math.min(this.remaining(), length));
+    }
+
+    // //////////////////////////////
+    // 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.
+     * 
+     * @param decoder The {@link CharsetDecoder} to use
+     * @return the read String
+     * @exception CharacterCodingException Thrown when an error occurred while
+     *                                     decoding the buffer
+     */
+    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
+     * @param decoder   The {@link CharsetDecoder} to use
+     * @return the read String
+     * @exception CharacterCodingException Thrown when an error occurred while
+     *                                     decoding the buffer
+     */
+    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.
+     * 
+     * @param val     The CharSequence to put in the IoBuffer
+     * @param encoder The CharsetEncoder to use
+     * @return The modified IoBuffer
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  String
+     */
+    public abstract IoBuffer putString(CharSequence val, 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 val       The CharSequence to put in the IoBuffer
+     * @param fieldSize the maximum number of bytes to write
+     * @param encoder   The CharsetEncoder to use
+     * @return The modified IoBuffer
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  String
+     */
+    public abstract IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder)
+            throws CharacterCodingException;
+
+    /**
+     * Reads a string which has a 16-bit length field before the actual encoded
+     * string, using the specified <code>decoder</code> and returns it. This method
+     * is a shortcut for <tt>getPrefixedString(2, decoder)</tt>.
+     * 
+     * @param decoder The CharsetDecoder to use
+     * @return The read String
+     * 
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  String
+     */
+    public abstract String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException;
+
+    /**
+     * Reads a string which has a length field before the actual encoded string,
+     * using the specified <code>decoder</code> and returns it.
+     * 
+     * @param prefixLength the length of the length field (1, 2, or 4)
+     * @param decoder      The CharsetDecoder to use
+     * @return The read String
+     * 
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  String
+     */
+    public abstract String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException;
+
+    /**
+     * Writes the content of <code>in</code> into this buffer as a string which has
+     * a 16-bit length field before the actual encoded string, using the specified
+     * <code>encoder</code>. This method is a shortcut for
+     * <tt>putPrefixedString(in, 2, 0, encoder)</tt>.
+     * 
+     * @param in      The CharSequence to put in the IoBuffer
+     * @param encoder The CharsetEncoder to use
+     * @return The modified IoBuffer
+     * 
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  CharSequence
+     */
+    public abstract IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException;
+
+    /**
+     * Writes the content of <code>in</code> into this buffer as a string which has
+     * a 16-bit length field before the actual encoded string, using the specified
+     * <code>encoder</code>. This method is a shortcut for
+     * <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>.
+     * 
+     * @param in           The CharSequence to put in the IoBuffer
+     * @param prefixLength the length of the length field (1, 2, or 4)
+     * @param encoder      The CharsetEncoder to use
+     * @return The modified IoBuffer
+     * 
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  CharSequence
+     */
+    public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
+            throws CharacterCodingException;
+
+    /**
+     * Writes the content of <code>in</code> into this buffer as a string which has
+     * a 16-bit length field before the actual encoded string, using the specified
+     * <code>encoder</code>. This method is a shortcut for
+     * <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>
+     * 
+     * @param in           The CharSequence to put in the IoBuffer
+     * @param prefixLength the length of the length field (1, 2, or 4)
+     * @param padding      the number of padded <tt>NUL</tt>s (1 (or 0), 2, or 4)
+     * @param encoder      The CharsetEncoder to use
+     * @return The modified IoBuffer
+     * 
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  CharSequence
+     */
+    public abstract IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder)
+            throws CharacterCodingException;
+
+    /**
+     * Writes the content of <code>val</code> into this buffer as a string which has
+     * a 16-bit length field before the actual encoded string, using the specified
+     * <code>encoder</code>.
+     * 
+     * @param val          The CharSequence to put in teh IoBuffer
+     * @param prefixLength the length of the length field (1, 2, or 4)
+     * @param padding      the number of padded bytes (1 (or 0), 2, or 4)
+     * @param padValue     the value of padded bytes
+     * @param encoder      The CharsetEncoder to use
+     * @return The modified IoBuffer
+     * @throws CharacterCodingException When we have an error while decoding the
+     *                                  CharSequence
+     */
+    public abstract IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue,
+            CharsetEncoder encoder) throws CharacterCodingException;
+
+    /**
+     * Reads a Java object from the buffer using the context {@link ClassLoader} of
+     * the current thread.
+     * 
+     * @return The read Object
+     * @throws ClassNotFoundException thrown when we can't find the Class to use
+     */
+    public abstract Object getObject() throws ClassNotFoundException;
+
+    /**
+     * Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
+     * 
+     * @param classLoader The classLoader to use to read an Object from the IoBuffer
+     * @return The read Object
+     * @throws ClassNotFoundException thrown when we can't find the Class to use
+     */
+    public abstract Object getObject(final ClassLoader classLoader) throws ClassNotFoundException;
+
+    /**
+     * Writes the specified Java object to the buffer.
+     * 
+     * @param o The Object to write in the IoBuffer
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer putObject(Object o);
+
+    /**
+     * 
+     * @param prefixLength the length of the prefix field (1, 2, or 4)
+     * @return <tt>true</tt> if this buffer contains a data which has a data length
+     *         as a prefix and the buffer has remaining data as enough as specified
+     *         in the data length field. This method is identical with
+     *         <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>.
+     *         Please not that using this method can allow DoS (Denial of Service)
+     *         attack in case the remote peer sends too big data length value. It is
+     *         recommended to use {@link #prefixedDataAvailable(int, int)} instead.
+     * @throws IllegalArgumentException if prefixLength is wrong
+     * @throws BufferDataException      if data length is negative
+     */
+    public abstract boolean prefixedDataAvailable(int prefixLength);
+
+    /**
+     * @param prefixLength  the length of the prefix field (1, 2, or 4)
+     * @param maxDataLength the allowed maximum of the read data length
+     * @return <tt>true</tt> if this buffer contains a data which has a data length
+     *         as a prefix and the buffer has remaining data as enough as specified
+     *         in the data length field.
+     * @throws IllegalArgumentException if prefixLength is wrong
+     * @throws BufferDataException      if data length is negative or greater then
+     *                                  <tt>maxDataLength</tt>
+     */
+    public abstract boolean prefixedDataAvailable(int prefixLength, int maxDataLength);
+
+    // ///////////////////
+    // IndexOf methods //
+    // ///////////////////
+
+    /**
+     * Returns the first occurrence position of the specified byte from the current
+     * position to the current limit.
+     *
+     * @param b The byte we are looking for
+     * @return <tt>-1</tt> if the specified byte is not found
+     */
+    public abstract int indexOf(byte b);
+
+    // ////////////////////////
+    // Skip or fill methods //
+    // ////////////////////////
+
+    /**
+     * Forwards the position of this buffer as the specified <code>size</code>
+     * bytes.
+     * 
+     * @param size The added size
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer skip(int size);
+
+    /**
+     * Fills this buffer with the specified value. This method moves buffer position
+     * forward.
+     * 
+     * @param value The value to fill the IoBuffer with
+     * @param size  The added size
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer fill(byte value, int size);
+
+    /**
+     * Fills this buffer with the specified value. This method does not change
+     * buffer position.
+     *
+     * @param value The value to fill the IoBuffer with
+     * @param size  The added size
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer fillAndReset(byte value, int size);
+
+    /**
+     * Fills this buffer with <code>NUL (0x00)</code>. This method moves buffer
+     * position forward.
+     * 
+     * @param size The added size
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer fill(int size);
+
+    /**
+     * Fills this buffer with <code>NUL (0x00)</code>. This method does not change
+     * buffer position.
+     * 
+     * @param size The added size
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer fillAndReset(int size);
+
+    // ////////////////////////
+    // Enum methods //
+    // ////////////////////////
+
+    /**
+     * Reads a byte from the buffer and returns the correlating enum constant
+     * defined by the specified enum type.
+     * 
+     * @param <E>       The enum type to return
+     * @param enumClass The enum's class object
+     * @return The correlated enum constant
+     */
+    public abstract <E extends Enum<E>> E getEnum(Class<E> enumClass);
+
+    /**
+     * Reads a byte from the buffer and returns the correlating enum constant
+     * defined by the specified enum type.
+     * 
+     * @param <E>       The enum type to return
+     * @param index     the index from which the byte will be read
+     * @param enumClass The enum's class object
+     * @return The correlated enum constant
+     */
+    public abstract <E extends Enum<E>> E getEnum(int index, Class<E> enumClass);
+
+    /**
+     * Reads a short from the buffer and returns the correlating enum constant
+     * defined by the specified enum type.
+     * 
+     * @param <E>       The enum type to return
+     * @param enumClass The enum's class object
+     * @return The correlated enum constant
+     */
+    public abstract <E extends Enum<E>> E getEnumShort(Class<E> enumClass);
+
+    /**
+     * Reads a short from the buffer and returns the correlating enum constant
+     * defined by the specified enum type.
+     * 
+     * @param <E>       The enum type to return
+     * @param index     the index from which the bytes will be read
+     * @param enumClass The enum's class object
+     * @return The correlated enum constant
+     */
+    public abstract <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass);
+
+    /**
+     * Reads an int from the buffer and returns the correlating enum constant
+     * defined by the specified enum type.
+     * 
+     * @param <E>       The enum type to return
+     * @param enumClass The enum's class object
+     * @return The correlated enum constant
+     */
+    public abstract <E extends Enum<E>> E getEnumInt(Class<E> enumClass);
+
+    /**
+     * Reads an int from the buffer and returns the correlating enum constant
+     * defined by the specified enum type.
+     * 
+     * @param <E>       The enum type to return
+     * @param index     the index from which the bytes will be read
+     * @param enumClass The enum's class object
+     * @return The correlated enum constant
+     */
+    public abstract <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass);
+
+    /**
+     * Writes an enum's ordinal value to the buffer as a byte.
+     * 
+     * @param e The enum to write to the buffer
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer putEnum(Enum<?> e);
+
+    /**
+     * Writes an enum's ordinal value to the buffer as a byte.
+     * 
+     * @param index The index at which the byte will be written
+     * @param e     The enum to write to the buffer
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer putEnum(int index, Enum<?> e);
+
+    /**
+     * Writes an enum's ordinal value to the buffer as a short.
+     * 
+     * @param e The enum to write to the buffer
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer putEnumShort(Enum<?> e);
+
+    /**
+     * Writes an enum's ordinal value to the buffer as a short.
+     * 
+     * @param index The index at which the bytes will be written
+     * @param e     The enum to write to the buffer
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer putEnumShort(int index, Enum<?> e);
+
+    /**
+     * Writes an enum's ordinal value to the buffer as an integer.
+     * 
+     * @param e The enum to write to the buffer
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer putEnumInt(Enum<?> e);
+
+    /**
+     * Writes an enum's ordinal value to the buffer as an integer.
+     * 
+     * @param index The index at which the bytes will be written
+     * @param e     The enum to write to the buffer
+     * @return The modified IoBuffer
+     */
+    public abstract IoBuffer putEnumInt(int index, Enum<?> e);
+
+    // ////////////////////////
+    // EnumSet methods //
+    // ////////////////////////
+
+    /**
+     * Reads a byte sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * <p>
+     * Each bit is mapped to a value in the specified enum. The least significant
+     * bit maps to the first entry in the specified enum and each subsequent bit
+     * maps to each subsequent bit as mapped to the subsequent enum value.
+     * 
+     * @param <E>       the enum type
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSet(Class<E> enumClass);
+
+    /**
+     * Reads a byte sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * @see #getEnumSet(Class)
+     * @param <E>       the enum type
+     * @param index     the index from which the byte will be read
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSet(int index, Class<E> enumClass);
+
+    /**
+     * Reads a short sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * @see #getEnumSet(Class)
+     * @param <E>       the enum type
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSetShort(Class<E> enumClass);
+
+    /**
+     * Reads a short sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * @see #getEnumSet(Class)
+     * @param <E>       the enum type
+     * @param index     the index from which the bytes will be read
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSetShort(int index, Class<E> enumClass);
+
+    /**
+     * Reads an int sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * @see #getEnumSet(Class)
+     * @param <E>       the enum type
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSetInt(Class<E> enumClass);
+
+    /**
+     * Reads an int sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * @see #getEnumSet(Class)
+     * @param <E>       the enum type
+     * @param index     the index from which the bytes will be read
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSetInt(int index, Class<E> enumClass);
+
+    /**
+     * Reads a long sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * @see #getEnumSet(Class)
+     * @param <E>       the enum type
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSetLong(Class<E> enumClass);
+
+    /**
+     * Reads a long sized bit vector and converts it to an {@link EnumSet}.
+     * 
+     * @see #getEnumSet(Class)
+     * @param <E>       the enum type
+     * @param index     the index from which the bytes will be read
+     * @param enumClass the enum class used to create the EnumSet
+     * @return the EnumSet representation of the bit vector
+     */
+    public abstract <E extends Enum<E>> Set<E> getEnumSetLong(int index, Class<E> enumClass);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as a byte sized bit vector.
+     * 
+     * @param <E> the enum type of the Set
+     * @param set the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as a byte sized bit vector.
+     * 
+     * @param <E>   the enum type of the Set
+     * @param index the index at which the byte will be written
+     * @param set   the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as a short sized bit vector.
+     * 
+     * @param <E> the enum type of the Set
+     * @param set the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as a short sized bit vector.
+     * 
+     * @param <E>   the enum type of the Set
+     * @param index the index at which the bytes will be written
+     * @param set   the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as an int sized bit vector.
+     * 
+     * @param <E> the enum type of the Set
+     * @param set the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as an int sized bit vector.
+     * 
+     * @param <E>   the enum type of the Set
+     * @param index the index at which the bytes will be written
+     * @param set   the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as a long sized bit vector.
+     * 
+     * @param <E> the enum type of the Set
+     * @param set the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set);
+
+    /**
+     * Writes the specified {@link Set} to the buffer as a long sized bit vector.
+     * 
+     * @param <E>   the enum type of the Set
+     * @param index the index at which the bytes will be written
+     * @param set   the enum set to write to the buffer
+     * @return the modified IoBuffer
+     */
+    public abstract <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set);
 }
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java
index ef02ed3..3c31629 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java
@@ -29,206 +29,206 @@ import java.io.UnsupportedEncodingException;
  */
 class IoBufferHexDumper {
 
-	/**
-	 * Dumps an {@link IoBuffer} to a hex formatted string.
-	 * 
-	 * @param buf    the buffer to dump
-	 * @param offset the starting position to begin reading the hex dump
-	 * @param length the number of bytes to dump
-	 * @return a hex formatted string representation of the <i>in</i>
-	 *         {@link IoBuffer}.
-	 */
-	public static String getHexDumpSlice(final IoBuffer buf, final int offset, final int length) {
-		if (buf == null) {
-			throw new IllegalArgumentException();
-		}
-
-		if (length < 0 || offset < 0 || offset + length > buf.limit()) {
-			throw new IndexOutOfBoundsException();
-		}
-
-		int pos = offset;
-		int items = Math.min(offset + length, offset + buf.limit()) - pos;
-
-		if (items <= 0) {
-			return "";
-		}
-
-		int lim = pos + items;
-
-		StringBuilder out = new StringBuilder((items * 3) + 6);
-
-		for (;;) {
-			int byteValue = buf.get(pos++) & 0xFF;
-			out.append((char) hexDigit[(byteValue >> 4) & 0x0F]);
-			out.append((char) hexDigit[byteValue & 0xf]);
-
-			if (pos < lim) {
-				out.append(' ');
-			} else {
-				break;
-			}
-		}
-
-		return out.toString();
-	}
-
-	/**
-	 * Produces a verbose hex dump
-	 *
-	 * @param offset initial position which to read bytes
-	 *
-	 * @param length number of bytes to display
-	 *
-	 * @return The formatted String representing the content between (offset) and
-	 *         (offset+count)
-	 */
-	public static final String getPrettyHexDumpSlice(final IoBuffer buf, final int offset, final int length) {
-		if (buf == null) {
-			throw new IllegalArgumentException();
-		}
-
-		if (length < 0 || offset < 0 || offset + length > buf.limit()) {
-			throw new IndexOutOfBoundsException();
-		}
-
-		final int len = Math.min(length, buf.limit() - offset);
-		final byte[] bytes = new byte[len];
-
-		int o = offset;
-
-		for (int i = 0; i < len; i++) {
-			bytes[i] = buf.get(o++);
-		}
-
-		final StringBuilder sb = new StringBuilder();
-
-		sb.append("Source ");
-		sb.append(buf);
-		sb.append(" showing index ");
-		sb.append(offset);
-		sb.append(" through ");
-		sb.append((offset + length));
-		sb.append("\n");
-		sb.append(toPrettyHexDump(bytes, 0, bytes.length));
-
-		return sb.toString();
-	}
-
-	/**
-	 * Generates a hex dump with line numbers, hex, volumes, and ascii
-	 * representation
-	 *
-	 * @param data source data to read for the hex dump
-	 *
-	 * @param pos  index position to begin reading
-	 *
-	 * @param len  number of bytes to read
-	 *
-	 * @return string hex dump
-	 */
-	public static final String toPrettyHexDump(final byte[] data, final int pos, final int len) {
-		if (data == null) {
-			throw new IllegalArgumentException();
-		}
-
-		if (len < 0 || pos < 0 || pos + len > data.length) {
-			throw new IndexOutOfBoundsException();
-		}
-
-		final StringBuilder b = new StringBuilder();
-
-		// Process every byte in the data.
-
-		for (int i = pos, c = 0, line = 16; i < len; i += line) {
-			b.append(String.format("%06d", Integer.valueOf(c)) + "  ");
-			b.append(toPrettyHexDumpLine(data, i, Math.min((pos + len) - i, line), 8, line));
-
-			if ((i + line) < len) {
-				b.append("\n");
-			}
-
-			c += line;
-		}
-
-		return b.toString();
-
-	}
-
-	/**
-	 * Generates the hex dump line with hex values, columns, and ascii
-	 * representation
-	 *
-	 * @param data source data to read for the hex dump
-	 *
-	 * @param pos  index position to begin reading
-	 *
-	 * @param len  number of bytes to read; this can be less than the <tt>line</tt>
-	 *             width
-	 *
-	 * @param col  number of bytes in a column
-	 *
-	 * @param line line width in bytes which pads the output if <tt>len</tt> is less
-	 *             than <tt>line</tt>
-	 *
-	 * @return string hex dump
-	 */
-	private static final String toPrettyHexDumpLine(final byte[] data, final int pos, final int len, final int col,
-			final int line) {
-		if ((line % 2) != 0) {
-			throw new IllegalArgumentException("length must be multiple of 2");
-		}
-
-		final StringBuilder b = new StringBuilder();
-
-		for (int i = pos, t = Math.min(data.length - pos, len) + pos; i < t;) {
-			for (int x = 0; (x < col) && (i < t); i++, x++) {
-				b.append(toHex(data[i]));
-				b.append(" ");
-			}
-
-			b.append(" ");
-		}
-
-		int cl = (line * 3) + (line / col);
-
-		if (b.length() != cl) // check if we need to pad the output
-		{
-			cl -= b.length();
-
-			while (cl > 0) {
-				b.append(" ");
-				cl--;
-			}
-		}
-
-		try {
-			String p = new String(data, pos, Math.min(data.length - pos, len), "Cp1252").replace("\r\n", "..")
-					.replace("\n", ".").replace("\\", ".");
-
-			final char[] ch = p.toCharArray();
-
-			for (int m = 0; m < ch.length; m++) {
-				if (ch[m] < 32) {
-					ch[m] = (char) 46; // add dots for whitespace chars
-				}
-			}
-
-			b.append(ch);
-		} catch (final UnsupportedEncodingException e) {
-			e.printStackTrace();
-		}
-
-		return b.toString();
-	}
-
-	private static final char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
-			'F' };
-
-	public static final String toHex(final byte b) {
-		// Returns hex String representation of byte
-
-		final char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
-		return new String(array);
-	}
-}
\ No newline at end of file
+    /**
+     * Dumps an {@link IoBuffer} to a hex formatted string.
+     * 
+     * @param buf    the buffer to dump
+     * @param offset the starting position to begin reading the hex dump
+     * @param length the number of bytes to dump
+     * @return a hex formatted string representation of the <i>in</i>
+     *         {@link IoBuffer}.
+     */
+    public static String getHexDumpSlice(final IoBuffer buf, final int offset, final int length) {
+        if (buf == null) {
+            throw new IllegalArgumentException();
+        }
+
+        if (length < 0 || offset < 0 || offset + length > buf.limit()) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        int pos = offset;
+        int items = Math.min(offset + length, offset + buf.limit()) - pos;
+
+        if (items <= 0) {
+            return "";
+        }
+
+        int lim = pos + items;
+
+        StringBuilder out = new StringBuilder((items * 3) + 6);
+
+        for (;;) {
+            int byteValue = buf.get(pos++) & 0xFF;
+            out.append((char) hexDigit[(byteValue >> 4) & 0x0F]);
+            out.append((char) hexDigit[byteValue & 0xf]);
+
+            if (pos < lim) {
+                out.append(' ');
+            } else {
+                break;
+            }
+        }
+
+        return out.toString();
+    }
+
+    /**
+     * Produces a verbose hex dump
+     *
+     * @param offset initial position which to read bytes
+     *
+     * @param length number of bytes to display
+     *
+     * @return The formatted String representing the content between (offset) and
+     *         (offset+count)
+     */
+    public static final String getPrettyHexDumpSlice(final IoBuffer buf, final int offset, final int length) {
+        if (buf == null) {
+            throw new IllegalArgumentException();
+        }
+
+        if (length < 0 || offset < 0 || offset + length > buf.limit()) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        final int len = Math.min(length, buf.limit() - offset);
+        final byte[] bytes = new byte[len];
+
+        int o = offset;
+
+        for (int i = 0; i < len; i++) {
+            bytes[i] = buf.get(o++);
+        }
+
+        final StringBuilder sb = new StringBuilder();
+
+        sb.append("Source ");
+        sb.append(buf);
+        sb.append(" showing index ");
+        sb.append(offset);
+        sb.append(" through ");
+        sb.append((offset + length));
+        sb.append("\n");
+        sb.append(toPrettyHexDump(bytes, 0, bytes.length));
+
+        return sb.toString();
+    }
+
+    /**
+     * Generates a hex dump with line numbers, hex, volumes, and ascii
+     * representation
+     *
+     * @param data source data to read for the hex dump
+     *
+     * @param pos  index position to begin reading
+     *
+     * @param len  number of bytes to read
+     *
+     * @return string hex dump
+     */
+    public static final String toPrettyHexDump(final byte[] data, final int pos, final int len) {
+        if (data == null) {
+            throw new IllegalArgumentException();
+        }
+
+        if (len < 0 || pos < 0 || pos + len > data.length) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        final StringBuilder b = new StringBuilder();
+
+        // Process every byte in the data.
+
+        for (int i = pos, c = 0, line = 16; i < len; i += line) {
+            b.append(String.format("%06d", Integer.valueOf(c)) + "  ");
+            b.append(toPrettyHexDumpLine(data, i, Math.min((pos + len) - i, line), 8, line));
+
+            if ((i + line) < len) {
+                b.append("\n");
+            }
+
+            c += line;
+        }
+
+        return b.toString();
+
+    }
+
+    /**
+     * Generates the hex dump line with hex values, columns, and ascii
+     * representation
+     *
+     * @param data source data to read for the hex dump
+     *
+     * @param pos  index position to begin reading
+     *
+     * @param len  number of bytes to read; this can be less than the <tt>line</tt>
+     *             width
+     *
+     * @param col  number of bytes in a column
+     *
+     * @param line line width in bytes which pads the output if <tt>len</tt> is less
+     *             than <tt>line</tt>
+     *
+     * @return string hex dump
+     */
+    private static final String toPrettyHexDumpLine(final byte[] data, final int pos, final int len, final int col,
+            final int line) {
+        if ((line % 2) != 0) {
+            throw new IllegalArgumentException("length must be multiple of 2");
+        }
+
+        final StringBuilder b = new StringBuilder();
+
+        for (int i = pos, t = Math.min(data.length - pos, len) + pos; i < t;) {
+            for (int x = 0; (x < col) && (i < t); i++, x++) {
+                b.append(toHex(data[i]));
+                b.append(" ");
+            }
+
+            b.append(" ");
+        }
+
+        int cl = (line * 3) + (line / col);
+
+        if (b.length() != cl) // check if we need to pad the output
+        {
+            cl -= b.length();
+
+            while (cl > 0) {
+                b.append(" ");
+                cl--;
+            }
+        }
+
+        try {
+            String p = new String(data, pos, Math.min(data.length - pos, len), "Cp1252").replace("\r\n", "..")
+                    .replace("\n", ".").replace("\\", ".");
+
+            final char[] ch = p.toCharArray();
+
+            for (int m = 0; m < ch.length; m++) {
+                if (ch[m] < 32) {
+                    ch[m] = (char) 46; // add dots for whitespace chars
+                }
+            }
+
+            b.append(ch);
+        } catch (final UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+
+        return b.toString();
+    }
+
+    private static final char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
+            'F' };
+
+    public static final String toHex(final byte b) {
+        // Returns hex String representation of byte
+
+        final char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
+        return new String(array);
+    }
+}
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
index 49a1201..437483f 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
@@ -46,1493 +46,1493 @@ import java.util.Set;
  */
 public class IoBufferWrapper extends IoBuffer {
 
-	/**
-	 * The buffer proxied by this proxy.
-	 */
-	private final IoBuffer buf;
-
-	/**
-	 * Create a new instance.
-	 * 
-	 * @param buf the buffer to be proxied
-	 */
-	protected IoBufferWrapper(IoBuffer buf) {
-		if (buf == null) {
-			throw new IllegalArgumentException("buf");
-		}
-		this.buf = buf;
-	}
-
-	/**
-	 * @return the parent buffer that this buffer wrapped.
-	 */
-	public IoBuffer getParentBuffer() {
-		return buf;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public boolean isDirect() {
-		return buf.isDirect();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public ByteBuffer buf() {
-		return buf.buf();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int capacity() {
-		return buf.capacity();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int position() {
-		return buf.position();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer position(int newPosition) {
-		buf.position(newPosition);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int limit() {
-		return buf.limit();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer limit(int newLimit) {
-		buf.limit(newLimit);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer mark() {
-		buf.mark();
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer reset() {
-		buf.reset();
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer clear() {
-		buf.clear();
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer sweep() {
-		buf.sweep();
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer sweep(byte value) {
-		buf.sweep(value);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer flip() {
-		buf.flip();
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer rewind() {
-		buf.rewind();
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int remaining() {
-		return buf.remaining();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public boolean hasRemaining() {
-		return buf.hasRemaining();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public byte get() {
-		return buf.get();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public short getUnsigned() {
-		return buf.getUnsigned();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public IoBuffer put(byte b) {
-		buf.put(b);
-		return this;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public byte get(int index) {
-		return buf.get(index);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public short getUnsigned(int index) {
-		return buf.getUnsigned(index);
-	}
... 11364 lines suppressed ...