View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.common;
    21
    22  import java.io.EOFException;
    23  import java.io.IOException;
    24  import java.io.InputStream;
    25  import java.io.ObjectInputStream;
    26  import java.io.ObjectOutputStream;
    27  import java.io.ObjectStreamClass;
    28  import java.io.OutputStream;
    29  import java.io.StreamCorruptedException;
    30  import java.nio.BufferOverflowException;
    31  import java.nio.BufferUnderflowException;
    32  import java.nio.ByteOrder;
    33  import java.nio.CharBuffer;
    34  import java.nio.DoubleBuffer;
    35  import java.nio.FloatBuffer;
    36  import java.nio.IntBuffer;
    37  import java.nio.LongBuffer;
    38  import java.nio.ShortBuffer;
    39  import java.nio.charset.CharacterCodingException;
    40  import java.nio.charset.CharsetDecoder;
    41  import java.nio.charset.CharsetEncoder;
    42  import java.nio.charset.CoderResult;
    43  import java.util.HashSet;
    44  import java.util.Set;
    45
    46  import org.apache.mina.common.support.ByteBufferHexDumper;
    47  import org.apache.mina.filter.codec.ProtocolEncoderOutput;
    48
    49  /**
    50   * A byte buffer used by MINA applications.
    51   * <p>
    52   * This is a replacement for {@link java.nio.ByteBuffer}. Please refer to
    53   * {@link java.nio.ByteBuffer} and {@link java.nio.Buffer} documentation for
    54   * usage.  MINA does not use NIO {@link java.nio.ByteBuffer} directly for two
    55   * reasons:
    56   * <ul>
    57   * <li>It doesn't provide useful getters and putters such as
    58   * <code>fill</code>, <code>get/putString</code>, and
    59   * <code>get/putAsciiInt()</code> enough.</li>
    60   * <li>It is hard to distinguish if the buffer is created from MINA buffer
    61   * pool or not.  MINA have to return used buffers back to pool.</li>
    62   * <li>It is difficult to write variable-length data due to its fixed
    63   * capacity</li>
    64   * </ul>
    65   * </p>
    66   *
    67   * <h2>Allocation</h2>
    68   * <p>
    69   * You can get a heap buffer from buffer pool:
    70   * <pre>
    71   * ByteBuffer buf = ByteBuffer.allocate(1024, false);
    72   * </pre>
    73   * you can also get a direct buffer from buffer pool:
    74   * <pre>
    75   * ByteBuffer buf = ByteBuffer.allocate(1024, true);
    76   * </pre>
    77   * or you can let MINA choose:
    78   * <pre>
    79   * ByteBuffer buf = ByteBuffer.allocate(1024);
    80   * </pre>
    81   * </p>
    82   *
    83   * <h2>Acquire/Release</h2>
    84   * <p>
    85   * <b>Please note that you never need to release the allocated buffer</b>
    86   * because MINA will release it automatically when:
    87   * <ul>
    88   * <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li>
    89   * <li>You pass the buffer by calling {@link IoFilter.NextFilter#filterWrite(IoSession,IoFilter.WriteRequest)}.</li>
    90   * <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li>
    91   * </ul>
    92   * And, you don't need to release any {@link ByteBuffer} which is passed as a parameter
    93   * of {@link IoHandler#messageReceived(IoSession, Object)} method.  They are released
    94   * automatically when the method returns.
    95   * <p>
    96   * You have to release buffers manually by calling {@link #release()} when:
    97   * <ul>
    98   * <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li>
    99   * <li>You called {@link #acquire()} to prevent the buffer from being released.</li>
    100  * </ul>
    101  * </p>
    102  *
    103  * <h2>Wrapping existing NIO buffers and arrays</h2>
    104  * <p>
    105  * This class provides a few <tt>wrap(...)</tt> methods that wraps
    106  * any NIO buffers and byte arrays.  Wrapped MINA buffers are not returned
    107  * to the buffer pool by default to prevent unexpected memory leakage by default.
    108  * In case you want to make it pooled, you can call {@link #setPooled(boolean)}
    109  * with <tt>true</tt> flag to enable pooling.
    110  *
    111  * <h2>AutoExpand</h2>
    112  * <p>
    113  * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really
    114  * easy, and it is because its size is fixed.  MINA <tt>ByteBuffer</tt>
    115  * introduces <tt>autoExpand</tt> property.  If <tt>autoExpand</tt> property
    116  * is true, you never get {@link BufferOverflowException} or
    117  * {@link IndexOutOfBoundsException} (except when index is negative).
    118  * It automatically expands its capacity and limit value.  For example:
    119  * <pre>
    120  * String greeting = messageBundle.getMessage( "hello" );
    121  * ByteBuffer buf = ByteBuffer.allocate( 16 );
    122  * // Turn on autoExpand (it is off by default)
    123  * buf.setAutoExpand( true );
    124  * buf.putString( greeting, utf8encoder );
    125  * </pre>
    126  * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind
    127  * the scene if the encoded data is larger than 16 bytes.  Its capacity will
    128  * increase by two times, and its limit will increase to the last position
    129  * the string is written.
    130  * </p>
    131  *
    132  * <h2>Derived Buffers</h2>
    133  * <p>
    134  * Derived buffers are the buffers which were created by
    135  * {@link #duplicate()}, {@link #slice()}, or {@link #asReadOnlyBuffer()}.
    136  * They are useful especially when you broadcast the same messages to
    137  * multiple {@link IoSession}s.  Please note that the derived buffers are
    138  * neither pooled nor auto-expandable.  Trying to expand a derived buffer will
    139  * raise {@link IllegalStateException}.
    140  * </p>
    141  *
    142  * <h2>Changing Buffer Allocation and Management Policy</h2>
    143  * <p>
    144  * MINA provides a {@link ByteBufferAllocator} interface to let you override
    145  * the default buffer management behavior.  There are two allocators provided
    146  * out-of-the-box:
    147  * <ul>
    148  * <li>{@link PooledByteBufferAllocator} (Default)</li>
    149  * <li>{@link SimpleByteBufferAllocator}</li>
    150  * </ul>
    151  * You can change the allocator by calling {@link #setAllocator(ByteBufferAllocator)}.
    152  * </p>
    153  *
    154  * @author The Apache Directory Project (mina-dev@directory.apache.org)
    155  * @version $Rev: 601962 $, $Date: 2007-12-07 03:45:54 +0100 (Fri, 07 Dec 2007) $
    156  * @noinspection StaticNonFinalField
    157  * @see ByteBufferAllocator
    158  */
    159 public abstract class ByteBuffer implements Comparable<ByteBuffer> {
    160     private static ByteBufferAllocator allocator = new PooledByteBufferAllocator();
    161
    162     private static boolean useDirectBuffers = true;
    163
    164     /**
    165      * Returns the current allocator which manages the allocated buffers.
    166      */
    167     public static ByteBufferAllocator getAllocator() {
    168         return allocator;
    169     }
    170
    171     /**
    172      * Changes the current allocator with the specified one to manage
    173      * the allocated buffers from now.
    174      */
    175     public static void setAllocator(ByteBufferAllocator newAllocator) {
    176         if (newAllocator == null) {
    177             throw new NullPointerException("allocator");
    178         }
    179
    180         ByteBufferAllocator oldAllocator = allocator;
    181
    182         allocator = newAllocator;
    183
    184         if (null != oldAllocator) {
    185             oldAllocator.dispose();
    186         }
    187     }
    188
    189     public static boolean isUseDirectBuffers() {
    190         return useDirectBuffers;
    191     }
    192
    193     public static void setUseDirectBuffers(boolean useDirectBuffers) {
    194         ByteBuffer.useDirectBuffers = useDirectBuffers;
    195     }
    196
    197     /**
    198      * Returns the direct or heap buffer which is capable of the specified
    199      * size.  This method tries to allocate direct buffer first, and then
    200      * tries heap buffer if direct buffer memory is exhausted.  Please use
    201      * {@link #allocate(int, boolean)} to allocate buffers of specific type.
    202      *
    203      * @param capacity the capacity of the buffer
    204      */
    205     public static ByteBuffer allocate(int capacity) {
    206         if (useDirectBuffers) {
    207             try {
    208                 // first try to allocate direct buffer
    209                 return allocate(capacity, true);
    210             } catch (OutOfMemoryError e) {
    211                 // fall through to heap buffer
    212             }
    213         }
    214
    215         return allocate(capacity, false);
    216     }
    217
    218     /**
    219      * Returns the buffer which is capable of the specified size.
    220      *
    221      * @param capacity the capacity of the buffer
    222      * @param direct   <tt>true</tt> to get a direct buffer,
    223      *                 <tt>false</tt> to get a heap buffer.
    224      */
    225     public static ByteBuffer allocate(int capacity, boolean direct) {
    226         return allocator.allocate(capacity, direct);
    227     }
    228
    229     /**
    230      * Wraps the specified NIO {@link java.nio.ByteBuffer} into MINA buffer.
    231      */
    232     public static ByteBuffer wrap(java.nio.ByteBuffer nioBuffer) {
    233         return allocator.wrap(nioBuffer);
    234     }
    235
    236     /**
    237      * Wraps the specified byte array into MINA heap buffer.
    238      */
    239     public static ByteBuffer wrap(byte[] byteArray) {
    240         return wrap(java.nio.ByteBuffer.wrap(byteArray));
    241     }
    242
    243     /**
    244      * Wraps the specified byte array into MINA heap buffer.
    245      * Please note that MINA buffers are going to be pooled, and
    246      * therefore there can be waste of memory if you wrap
    247      * your byte array specifying <tt>offset</tt> and <tt>length</tt>.
    248      */
    249     public static ByteBuffer wrap(byte[] byteArray, int offset, int length) {
    250         return wrap(java.nio.ByteBuffer.wrap(byteArray, offset, length));
    251     }
    252
    253     private static final Set<String> primitiveTypeNames = new HashSet<String>();
    254
    255     static {
    256         primitiveTypeNames.add("void");
    257         primitiveTypeNames.add("boolean");
    258         primitiveTypeNames.add("byte");
    259         primitiveTypeNames.add("char");
    260         primitiveTypeNames.add("short");
    261         primitiveTypeNames.add("int");
    262         primitiveTypeNames.add("long");
    263         primitiveTypeNames.add("float");
    264         primitiveTypeNames.add("double");
    265     }
    266
    267     protected ByteBuffer() {
    268     }
    269
    270     /**
    271      * Increases the internal reference count of this buffer to defer
    272      * automatic release.  You have to invoke {@link #release()} as many
    273      * as you invoked this method to release this buffer.
    274      *
    275      * @throws IllegalStateException if you attempt to acquire already
    276      *                               released buffer.
    277      */
    278     public abstract void acquire();
    279
    280     /**
    281      * Releases the specified buffer to buffer pool.
    282      *
    283      * @throws IllegalStateException if you attempt to release already
    284      *                               released buffer.
    285      */
    286     public abstract void release();
    287
    288     /**
    289      * Returns the underlying NIO buffer instance.
    290      */
    291     public abstract java.nio.ByteBuffer buf();
    292
    293     /**
    294      * @see java.nio.ByteBuffer#isDirect()
    295      */
    296     public abstract boolean isDirect();
    297
    298     /**
    299      * @see java.nio.ByteBuffer#isReadOnly()
    300      */
    301     public abstract boolean isReadOnly();
    302
    303     /**
    304      * @see java.nio.ByteBuffer#capacity()
    305      */
    306     public abstract int capacity();
    307
    308     /**
    309      * Changes the capacity of this buffer.
    310      */
    311     public abstract ByteBuffer capacity(int newCapacity);
    312
    313     /**
    314      * Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on.
    315      */
    316     public abstract boolean isAutoExpand();
    317
    318     /**
    319      * Turns on or off <tt>autoExpand</tt>.
    320      */
    321     public abstract ByteBuffer setAutoExpand(boolean autoExpand);
    322
    323     /**
    324      * Changes the capacity and limit of this buffer so this buffer get
    325      * the specified <tt>expectedRemaining</tt> room from the current position.
    326      * This method works even if you didn't set <tt>autoExpand</tt> to
    327      * <tt>true</tt>.
    328      */
    329     public ByteBuffer expand(int expectedRemaining) {
    330         return expand(position(), expectedRemaining);
    331     }
    332
    333     /**
    334      * Changes the capacity and limit of this buffer so this buffer get
    335      * the specified <tt>expectedRemaining</tt> room from the specified
    336      * <tt>pos</tt>.
    337      * This method works even if you didn't set <tt>autoExpand</tt> to
    338      * <tt>true</tt>.
    339      */
    340     public abstract ByteBuffer expand(int pos, int expectedRemaining);
    341
    342     /**
    343      * Returns <tt>true</tt> if and only if this buffer is returned back
    344      * to the buffer pool when released.
    345      * <p>
    346      * The default value of this property is <tt>true</tt> if and only if you
    347      * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
    348      * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
    349      * and {@link #wrap(java.nio.ByteBuffer)})
    350      */
    351     public abstract boolean isPooled();
    352
    353     /**
    354      * Sets whether this buffer is returned back to the buffer pool when released.
    355      * <p>
    356      * The default value of this property is <tt>true</tt> if and only if you
    357      * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
    358      * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
    359      * and {@link #wrap(java.nio.ByteBuffer)})
    360      */
    361     public abstract void setPooled(boolean pooled);
    362
    363     /**
    364      * @see java.nio.Buffer#position()
    365      */
    366     public abstract int position();
    367
    368     /**
    369      * @see java.nio.Buffer#position(int)
    370      */
    371     public abstract ByteBuffer position(int newPosition);
    372
    373     /**
    374      * @see java.nio.Buffer#limit()
    375      */
    376     public abstract int limit();
    377
    378     /**
    379      * @see java.nio.Buffer#limit(int)
    380      */
    381     public abstract ByteBuffer limit(int newLimit);
    382
    383     /**
    384      * @see java.nio.Buffer#mark()
    385      */
    386     public abstract ByteBuffer mark();
    387
    388     /**
    389      * Returns the position of the current mark.  This method returns <tt>-1</tt> if no
    390      * mark is set.
    391      */
    392     public abstract int markValue();
    393
    394     /**
    395      * @see java.nio.Buffer#reset()
    396      */
    397     public abstract ByteBuffer reset();
    398
    399     /**
    400      * @see java.nio.Buffer#clear()
    401      */
    402     public abstract ByteBuffer clear();
    403
    404     /**
    405      * Clears this buffer and fills its content with <tt>NUL</tt>.
    406      * The position is set to zero, the limit is set to the capacity,
    407      * and the mark is discarded.
    408      */
    409     public ByteBuffer sweep() {
    410         clear();
    411         return fillAndReset(remaining());
    412     }
    413
    414     /**
    415      * Clears this buffer and fills its content with <tt>value</tt>.
    416      * The position is set to zero, the limit is set to the capacity,
    417      * and the mark is discarded.
    418      */
    419     public ByteBuffer sweep(byte value) {
    420         clear();
    421         return fillAndReset(value, remaining());
    422     }
    423
    424     /**
    425      * @see java.nio.Buffer#flip()
    426      */
    427     public abstract ByteBuffer flip();
    428
    429     /**
    430      * @see java.nio.Buffer#rewind()
    431      */
    432     public abstract ByteBuffer rewind();
    433
    434     /**
    435      * @see java.nio.Buffer#remaining()
    436      */
    437     public int remaining() {
    438         return limit() - position();
    439     }
    440
    441     /**
    442      * @see java.nio.Buffer#hasRemaining()
    443      */
    444     public boolean hasRemaining() {
    445         return remaining() > 0;
    446     }
    447
    448     /**
    449      * @see java.nio.ByteBuffer#duplicate()
    450      */
    451     public abstract ByteBuffer duplicate();
    452
    453     /**
    454      * @see java.nio.ByteBuffer#slice()
    455      */
    456     public abstract ByteBuffer slice();
    457
    458     /**
    459      * @see java.nio.ByteBuffer#asReadOnlyBuffer()
    460      */
    461     public abstract ByteBuffer asReadOnlyBuffer();
    462
    463     /**
    464      * @see java.nio.ByteBuffer#array()
    465      */
    466     public abstract byte[] array();
    467
    468     /**
    469      * @see java.nio.ByteBuffer#arrayOffset()
    470      */
    471     public abstract int arrayOffset();
    472
    473     /**
    474      * @see java.nio.ByteBuffer#get()
    475      */
    476     public abstract byte get();
    477
    478     /**
    479      * Reads one unsigned byte as a short integer.
    480      */
    481     public short getUnsigned() {
    482         return (short) (get() & 0xff);
    483     }
    484
    485     /**
    486      * @see java.nio.ByteBuffer#put(byte)
    487      */
    488     public abstract ByteBuffer put(byte b);
    489
    490     /**
    491      * @see java.nio.ByteBuffer#get(int)
    492      */
    493     public abstract byte get(int index);
    494
    495     /**
    496      * Reads one byte as an unsigned short integer.
    497      */
    498     public short getUnsigned(int index) {
    499         return (short) (get(index) & 0xff);
    500     }
    501
    502     /**
    503      * @see java.nio.ByteBuffer#put(int, byte)
    504      */
    505     public abstract ByteBuffer put(int index, byte b);
    506
    507     /**
    508      * @see java.nio.ByteBuffer#get(byte[], int, int)
    509      */
    510     public abstract ByteBuffer get(byte[] dst, int offset, int length);
    511
    512     /**
    513      * @see java.nio.ByteBuffer#get(byte[])
    514      */
    515     public ByteBuffer get(byte[] dst) {
    516         return get(dst, 0, dst.length);
    517     }
    518
    519     /**
    520      * Writes the content of the specified <tt>src</tt> into this buffer.
    521      */
    522     public abstract ByteBuffer put(java.nio.ByteBuffer src);
    523
    524     /**
    525      * Writes the content of the specified <tt>src</tt> into this buffer.
    526      */
    527     public ByteBuffer put(ByteBuffer src) {
    528         return put(src.buf());
    529     }
    530
    531     /**
    532      * @see java.nio.ByteBuffer#put(byte[], int, int)
    533      */
    534     public abstract ByteBuffer put(byte[] src, int offset, int length);
    535
    536     /**
    537      * @see java.nio.ByteBuffer#put(byte[])
    538      */
    539     public ByteBuffer put(byte[] src) {
    540         return put(src, 0, src.length);
    541     }
    542
    543     /**
    544      * @see java.nio.ByteBuffer#compact()
    545      */
    546     public abstract ByteBuffer compact();
    547
    548     @Override
    549     public String toString() {
    550         StringBuffer buf = new StringBuffer();
    551         if (isDirect()) {
    552             buf.append("DirectBuffer");
    553         } else {
    554             buf.append("HeapBuffer");
    555         }
    556         buf.append("[pos=");
    557         buf.append(position());
    558         buf.append(" lim=");
    559         buf.append(limit());
    560         buf.append(" cap=");
    561         buf.append(capacity());
    562         buf.append(": ");
    563         buf.append(getHexDump());
    564         buf.append(']');
    565         return buf.toString();
    566     }
    567
    568     @Override
    569     public int hashCode() {
    570         int h = 1;
    571         int p = position();
    572         for (int i = limit() - 1; i >= p; i--) {
    573             h = 31 * h + get(i);
    574         }
    575         return h;
    576     }
    577
    578     @Override
    579     public boolean equals(Object o) {
    580         if (!(o instanceof ByteBuffer)) {
    581             return false;
    582         }
    583
    584         ByteBuffer that = (ByteBuffer) o;
    585         if (this.remaining() != that.remaining()) {
    586             return false;
    587         }
    588
    589         int p = this.position();
    590         for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
    591             byte v1 = this.get(i);
    592             byte v2 = that.get(j);
    593             if (v1 != v2) {
    594                 return false;
    595             }
    596         }
    597         return true;
    598     }
    599
    600     public int compareTo(ByteBuffer that) {
    601         int n = this.position() + Math.min(this.remaining(), that.remaining());
    602         for (int i = this.position(), j = that.position(); i < n; i++, j++) {
    603             byte v1 = this.get(i);
    604             byte v2 = that.get(j);
    605             if (v1 == v2) {
    606                 continue;
    607             }
    608             if (v1 < v2) {
    609                 return -1;
    610             }
    611
    612             return +1;
    613         }
    614         return this.remaining() - that.remaining();
    615     }
    616
    617     /**
    618      * @see java.nio.ByteBuffer#order()
    619      */
    620     public abstract ByteOrder order();
    621
    622     /**
    623      * @see java.nio.ByteBuffer#order(ByteOrder)
    624      */
    625     public abstract ByteBuffer order(ByteOrder bo);
    626
    627     /**
    628      * @see java.nio.ByteBuffer#getChar()
    629      */
    630     public abstract char getChar();
    631
    632     /**
    633      * @see java.nio.ByteBuffer#putChar(char)
    634      */
    635     public abstract ByteBuffer putChar(char value);
    636
    637     /**
    638      * @see java.nio.ByteBuffer#getChar(int)
    639      */
    640     public abstract char getChar(int index);
    641
    642     /**
    643      * @see java.nio.ByteBuffer#putChar(int, char)
    644      */
    645     public abstract ByteBuffer putChar(int index, char value);
    646
    647     /**
    648      * @see java.nio.ByteBuffer#asCharBuffer()
    649      */
    650     public abstract CharBuffer asCharBuffer();
    651
    652     /**
    653      * @see java.nio.ByteBuffer#getShort()
    654      */
    655     public abstract short getShort();
    656
    657     /**
    658      * Reads two bytes unsigned integer.
    659      */
    660     public int getUnsignedShort() {
    661         return getShort() & 0xffff;
    662     }
    663
    664     /**
    665      * @see java.nio.ByteBuffer#putShort(short)
    666      */
    667     public abstract ByteBuffer putShort(short value);
    668
    669     /**
    670      * @see java.nio.ByteBuffer#getShort()
    671      */
    672     public abstract short getShort(int index);
    673
    674     /**
    675      * Reads two bytes unsigned integer.
    676      */
    677     public int getUnsignedShort(int index) {
    678         return getShort(index) & 0xffff;
    679     }
    680
    681     /**
    682      * @see java.nio.ByteBuffer#putShort(int, short)
    683      */
    684     public abstract ByteBuffer putShort(int index, short value);
    685
    686     /**
    687      * @see java.nio.ByteBuffer#asShortBuffer()
    688      */
    689     public abstract ShortBuffer asShortBuffer();
    690
    691     /**
    692      * @see java.nio.ByteBuffer#getInt()
    693      */
    694     public abstract int getInt();
    695
    696     /**
    697      * Reads four bytes unsigned integer.
    698      */
    699     public long getUnsignedInt() {
    700         return getInt() & 0xffffffffL;
    701     }
    702
    703     /**
    704      * @see java.nio.ByteBuffer#putInt(int)
    705      */
    706     public abstract ByteBuffer putInt(int value);
    707
    708     /**
    709      * @see java.nio.ByteBuffer#getInt(int)
    710      */
    711     public abstract int getInt(int index);
    712
    713     /**
    714      * Reads four bytes unsigned integer.
    715      */
    716     public long getUnsignedInt(int index) {
    717         return getInt(index) & 0xffffffffL;
    718     }
    719
    720     /**
    721      * @see java.nio.ByteBuffer#putInt(int, int)
    722      */
    723     public abstract ByteBuffer putInt(int index, int value);
    724
    725     /**
    726      * @see java.nio.ByteBuffer#asIntBuffer()
    727      */
    728     public abstract IntBuffer asIntBuffer();
    729
    730     /**
    731      * @see java.nio.ByteBuffer#getLong()
    732      */
    733     public abstract long getLong();
    734
    735     /**
    736      * @see java.nio.ByteBuffer#putLong(int, long)
    737      */
    738     public abstract ByteBuffer putLong(long value);
    739
    740     /**
    741      * @see java.nio.ByteBuffer#getLong(int)
    742      */
    743     public abstract long getLong(int index);
    744
    745     /**
    746      * @see java.nio.ByteBuffer#putLong(int, long)
    747      */
    748     public abstract ByteBuffer putLong(int index, long value);
    749
    750     /**
    751      * @see java.nio.ByteBuffer#asLongBuffer()
    752      */
    753     public abstract LongBuffer asLongBuffer();
    754
    755     /**
    756      * @see java.nio.ByteBuffer#getFloat()
    757      */
    758     public abstract float getFloat();
    759
    760     /**
    761      * @see java.nio.ByteBuffer#putFloat(float)
    762      */
    763     public abstract ByteBuffer putFloat(float value);
    764
    765     /**
    766      * @see java.nio.ByteBuffer#getFloat(int)
    767      */
    768     public abstract float getFloat(int index);
    769
    770     /**
    771      * @see java.nio.ByteBuffer#putFloat(int, float)
    772      */
    773     public abstract ByteBuffer putFloat(int index, float value);
    774
    775     /**
    776      * @see java.nio.ByteBuffer#asFloatBuffer()
    777      */
    778     public abstract FloatBuffer asFloatBuffer();
    779
    780     /**
    781      * @see java.nio.ByteBuffer#getDouble()
    782      */
    783     public abstract double getDouble();
    784
    785     /**
    786      * @see java.nio.ByteBuffer#putDouble(double)
    787      */
    788     public abstract ByteBuffer putDouble(double value);
    789
    790     /**
    791      * @see java.nio.ByteBuffer#getDouble(int)
    792      */
    793     public abstract double getDouble(int index);
    794
    795     /**
    796      * @see java.nio.ByteBuffer#putDouble(int, double)
    797      */
    798     public abstract ByteBuffer putDouble(int index, double value);
    799
    800     /**
    801      * @see java.nio.ByteBuffer#asDoubleBuffer()
    802      */
    803     public abstract DoubleBuffer asDoubleBuffer();
    804
    805     /**
    806      * Returns an {@link InputStream} that reads the data from this buffer.
    807      * {@link InputStream#read()} returns <tt>-1</tt> if the buffer position
    808      * reaches to the limit.
    809      */
    810     public InputStream asInputStream() {
    811         return new InputStream() {
    812             @Override
    813             public int available() {
    814                 return ByteBuffer.this.remaining();
    815             }
    816
    817             @Override
    818             public synchronized void mark(int readlimit) {
    819                 ByteBuffer.this.mark();
    820             }
    821
    822             @Override
    823             public boolean markSupported() {
    824                 return true;
    825             }
    826
    827             @Override
    828             public int read() {
    829                 if (ByteBuffer.this.hasRemaining()) {
    830                     return ByteBuffer.this.get() & 0xff;
    831                 } else {
    832                     return -1;
    833                 }
    834             }
    835
    836             @Override
    837             public int read(byte[] b, int off, int len) {
    838                 int remaining = ByteBuffer.this.remaining();
    839                 if (remaining > 0) {
    840                     int readBytes = Math.min(remaining, len);
    841                     ByteBuffer.this.get(b, off, readBytes);
    842                     return readBytes;
    843                 } else {
    844                     return -1;
    845                 }
    846             }
    847
    848             @Override
    849             public synchronized void reset() {
    850                 ByteBuffer.this.reset();
    851             }
    852
    853             @Override
    854             public long skip(long n) {
    855                 int bytes;
    856                 if (n > Integer.MAX_VALUE) {
    857                     bytes = ByteBuffer.this.remaining();
    858                 } else {
    859                     bytes = Math.min(ByteBuffer.this.remaining(), (int) n);
    860                 }
    861                 ByteBuffer.this.skip(bytes);
    862                 return bytes;
    863             }
    864         };
    865     }
    866
    867     /**
    868      * Returns an {@link OutputStream} that appends the data into this buffer.
    869      * Please note that the {@link OutputStream#write(int)} will throw a
    870      * {@link BufferOverflowException} instead of an {@link IOException}
    871      * in case of buffer overflow.  Please set <tt>autoExpand</tt> property by
    872      * calling {@link #setAutoExpand(boolean)} to prevent the unexpected runtime
    873      * exception.
    874      */
    875     public OutputStream asOutputStream() {
    876         return new OutputStream() {
    877             @Override
    878             public void write(byte[] b, int off, int len) {
    879                 ByteBuffer.this.put(b, off, len);
    880             }
    881
    882             @Override
    883             public void write(int b) {
    884                 ByteBuffer.this.put((byte) b);
    885             }
    886         };
    887     }
    888
    889     /**
    890      * Returns hexdump of this buffer.
    891      */
    892     public String getHexDump() {
    893         return ByteBufferHexDumper.getHexdump(this);
    894     }
    895
    896     ////////////////////////////////
    897     // String getters and putters //
    898     ////////////////////////////////
    899
    900     /**
    901      * Reads a <code>NUL</code>-terminated string from this buffer using the
    902      * specified <code>decoder</code> and returns it.  This method reads
    903      * until the limit of this buffer if no <tt>NUL</tt> is found.
    904      */
    905     public String getString(CharsetDecoder decoder)
    906             throws CharacterCodingException {
    907         if (!hasRemaining()) {
    908             return "";
    909         }
    910
    911         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
    912
    913         int oldPos = position();
    914         int oldLimit = limit();
    915         int end;
    916
    917         if (!utf16) {
    918             while (hasRemaining()) {
    919                 if (get() == 0) {
    920                     break;
    921                 }
    922             }
    923
    924             end = position();
    925             if (end == oldLimit && get(end - 1) != 0) {
    926                 limit(end);
    927             } else {
    928                 limit(end - 1);
    929             }
    930         } else {
    931             while (remaining() >= 2) {
    932                 boolean highZero = (get() == 0);
    933                 boolean lowZero = (get() == 0);
    934                 if (highZero && lowZero) {
    935                     break;
    936                 }
    937             }
    938
    939             end = position();
    940             if (end == oldLimit || end == oldLimit - 1) {
    941                 limit(end);
    942             } else {
    943                 limit(end - 2);
    944             }
    945         }
    946
    947         position(oldPos);
    948         if (!hasRemaining()) {
    949             limit(oldLimit);
    950             position(end);
    951             return "";
    952         }
    953         decoder.reset();
    954
    955         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
    956         CharBuffer out = CharBuffer.allocate(expectedLength);
    957         for (;;) {
    958             CoderResult cr;
    959             if (hasRemaining()) {
    960                 cr = decoder.decode(buf(), out, true);
    961             } else {
    962                 cr = decoder.flush(out);
    963             }
    964
    965             if (cr.isUnderflow()) {
    966                 break;
    967             }
    968
    969             if (cr.isOverflow()) {
    970                 CharBuffer o = CharBuffer.allocate(out.capacity()
    971                         + expectedLength);
    972                 out.flip();
    973                 o.put(out);
    974                 out = o;
    975                 continue;
    976             }
    977
    978             if (cr.isError()) {
    979                 // Revert the buffer back to the previous state.
    980                 limit(oldLimit);
    981                 position(oldPos);
    982                 cr.throwException();
    983             }
    984         }
    985
    986         limit(oldLimit);
    987         position(end);
    988         return out.flip().toString();
    989     }
    990
    991     /**
    992      * Reads a <code>NUL</code>-terminated string from this buffer using the
    993      * specified <code>decoder</code> and returns it.
    994      *
    995      * @param fieldSize the maximum number of bytes to read
    996      */
    997     public String getString(int fieldSize, CharsetDecoder decoder)
    998             throws CharacterCodingException {
    999         checkFieldSize(fieldSize);
    1000
    1001         if (fieldSize == 0) {
    1002             return "";
    1003         }
    1004
    1005         if (!hasRemaining()) {
    1006             return "";
    1007         }
    1008
    1009         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
    1010
    1011         if (utf16 && ((fieldSize & 1) != 0)) {
    1012             throw new IllegalArgumentException("fieldSize is not even.");
    1013         }
    1014
    1015         int oldPos = position();
    1016         int oldLimit = limit();
    1017         int end = position() + fieldSize;
    1018
    1019         if (oldLimit < end) {
    1020             throw new BufferUnderflowException();
    1021         }
    1022
    1023         int i;
    1024
    1025         if (!utf16) {
    1026             for (i = 0; i < fieldSize; i++) {
    1027                 if (get() == 0) {
    1028                     break;
    1029                 }
    1030             }
    1031
    1032             if (i == fieldSize) {
    1033                 limit(end);
    1034             } else {
    1035                 limit(position() - 1);
    1036             }
    1037         } else {
    1038             for (i = 0; i < fieldSize; i += 2) {
    1039                 boolean highZero = (get() == 0);
    1040                 boolean lowZero = (get() == 0);
    1041                 if (highZero && lowZero) {
    1042                     break;
    1043                 }
    1044             }
    1045
    1046             if (i == fieldSize) {
    1047                 limit(end);
    1048             } else {
    1049                 limit(position() - 2);
    1050             }
    1051         }
    1052
    1053         position(oldPos);
    1054         if (!hasRemaining()) {
    1055             limit(oldLimit);
    1056             position(end);
    1057             return "";
    1058         }
    1059         decoder.reset();
    1060
    1061         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
    1062         CharBuffer out = CharBuffer.allocate(expectedLength);
    1063         for (;;) {
    1064             CoderResult cr;
    1065             if (hasRemaining()) {
    1066                 cr = decoder.decode(buf(), out, true);
    1067             } else {
    1068                 cr = decoder.flush(out);
    1069             }
    1070
    1071             if (cr.isUnderflow()) {
    1072                 break;
    1073             }
    1074
    1075             if (cr.isOverflow()) {
    1076                 CharBuffer o = CharBuffer.allocate(out.capacity()
    1077                         + expectedLength);
    1078                 out.flip();
    1079                 o.put(out);
    1080                 out = o;
    1081                 continue;
    1082             }
    1083
    1084             if (cr.isError()) {
    1085                 // Revert the buffer back to the previous state.
    1086                 limit(oldLimit);
    1087                 position(oldPos);
    1088                 cr.throwException();
    1089             }
    1090         }
    1091
    1092         limit(oldLimit);
    1093         position(end);
    1094         return out.flip().toString();
    1095     }
    1096
    1097     /**
    1098      * Writes the content of <code>in</code> into this buffer using the
    1099      * specified <code>encoder</code>.  This method doesn't terminate
    1100      * string with <tt>NUL</tt>.  You have to do it by yourself.
    1101      *
    1102      * @throws BufferOverflowException if the specified string doesn't fit
    1103      */
    1104     public ByteBuffer putString(CharSequence val, CharsetEncoder encoder)
    1105             throws CharacterCodingException {
    1106         if (val.length() == 0) {
    1107             return this;
    1108         }
    1109
    1110         CharBuffer in = CharBuffer.wrap(val);
    1111         encoder.reset();
    1112
    1113         int expandedState = 0;
    1114
    1115         for (;;) {
    1116             CoderResult cr;
    1117             if (in.hasRemaining()) {
    1118                 cr = encoder.encode(in, buf(), true);
    1119             } else {
    1120                 cr = encoder.flush(buf());
    1121             }
    1122
    1123             if (cr.isUnderflow()) {
    1124                 break;
    1125             }
    1126             if (cr.isOverflow()) {
    1127                 if (isAutoExpand()) {
    1128                     switch (expandedState) {
    1129                     case 0:
    1130                         autoExpand((int) Math.ceil(in.remaining()
    1131                                 * encoder.averageBytesPerChar()));
    1132                         expandedState++;
    1133                         break;
    1134                     case 1:
    1135                         autoExpand((int) Math.ceil(in.remaining()
    1136                                 * encoder.maxBytesPerChar()));
    1137                         expandedState++;
    1138                         break;
    1139                     default:
    1140                         throw new RuntimeException("Expanded by "
    1141                                 + (int) Math.ceil(in.remaining()
    1142                                         * encoder.maxBytesPerChar())
    1143                                 + " but that wasn't enough for '" + val + "'");
    1144                     }
    1145                     continue;
    1146                 }
    1147             } else {
    1148                 expandedState = 0;
    1149             }
    1150             cr.throwException();
    1151         }
    1152         return this;
    1153     }
    1154
    1155     /**
    1156      * Writes the content of <code>in</code> into this buffer as a
    1157      * <code>NUL</code>-terminated string using the specified
    1158      * <code>encoder</code>.
    1159      * <p>
    1160      * If the charset name of the encoder is UTF-16, you cannot specify
    1161      * odd <code>fieldSize</code>, and this method will append two
    1162      * <code>NUL</code>s as a terminator.
    1163      * <p>
    1164      * Please note that this method doesn't terminate with <code>NUL</code>
    1165      * if the input string is longer than <tt>fieldSize</tt>.
    1166      *
    1167      * @param fieldSize the maximum number of bytes to write
    1168      */
    1169     public ByteBuffer putString(CharSequence val, int fieldSize,
    1170             CharsetEncoder encoder) throws CharacterCodingException {
    1171         checkFieldSize(fieldSize);
    1172
    1173         if (fieldSize == 0)
    1174             return this;
    1175
    1176         autoExpand(fieldSize);
    1177
    1178         boolean utf16 = encoder.charset().name().startsWith("UTF-16");
    1179
    1180         if (utf16 && ((fieldSize & 1) != 0)) {
    1181             throw new IllegalArgumentException("fieldSize is not even.");
    1182         }
    1183
    1184         int oldLimit = limit();
    1185         int end = position() + fieldSize;
    1186
    1187         if (oldLimit < end) {
    1188             throw new BufferOverflowException();
    1189         }
    1190
    1191         if (val.length() == 0) {
    1192             if (!utf16) {
    1193                 put((byte) 0x00);
    1194             } else {
    1195                 put((byte) 0x00);
    1196                 put((byte) 0x00);
    1197             }
    1198             position(end);
    1199             return this;
    1200         }
    1201
    1202         CharBuffer in = CharBuffer.wrap(val);
    1203         limit(end);
    1204         encoder.reset();
    1205
    1206         for (;;) {
    1207             CoderResult cr;
    1208             if (in.hasRemaining()) {
    1209                 cr = encoder.encode(in, buf(), true);
    1210             } else {
    1211                 cr = encoder.flush(buf());
    1212             }
    1213
    1214             if (cr.isUnderflow() || cr.isOverflow()) {
    1215                 break;
    1216             }
    1217             cr.throwException();
    1218         }
    1219
    1220         limit(oldLimit);
    1221
    1222         if (position() < end) {
    1223             if (!utf16) {
    1224                 put((byte) 0x00);
    1225             } else {
    1226                 put((byte) 0x00);
    1227                 put((byte) 0x00);
    1228             }
    1229         }
    1230
    1231         position(end);
    1232         return this;
    1233     }
    1234
    1235     /**
    1236      * Reads a string which has a 16-bit length field before the actual
    1237      * encoded string, using the specified <code>decoder</code> and returns it.
    1238      * This method is a shortcut for <tt>getPrefixedString(2, decoder)</tt>.
    1239      */
    1240     public String getPrefixedString(CharsetDecoder decoder)
    1241             throws CharacterCodingException {
    1242         return getPrefixedString(2, decoder);
    1243     }
    1244
    1245     /**
    1246      * Reads a string which has a length field before the actual
    1247      * encoded string, using the specified <code>decoder</code> and returns it.
    1248      *
    1249      * @param prefixLength the length of the length field (1, 2, or 4)
    1250      */
    1251     public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
    1252             throws CharacterCodingException {
    1253         if (!prefixedDataAvailable(prefixLength)) {
    1254             throw new BufferUnderflowException();
    1255         }
    1256
    1257         int fieldSize = 0;
    1258
    1259         switch (prefixLength) {
    1260         case 1:
    1261             fieldSize = getUnsigned();
    1262             break;
    1263         case 2:
    1264             fieldSize = getUnsignedShort();
    1265             break;
    1266         case 4:
    1267             fieldSize = getInt();
    1268             break;
    1269         }
    1270
    1271         if (fieldSize == 0) {
    1272             return "";
    1273         }
    1274
    1275         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
    1276
    1277         if (utf16 && ((fieldSize & 1) != 0)) {
    1278             throw new BufferDataException(
    1279                     "fieldSize is not even for a UTF-16 string.");
    1280         }
    1281
    1282         int oldLimit = limit();
    1283         int end = position() + fieldSize;
    1284
    1285         if (oldLimit < end) {
    1286             throw new BufferUnderflowException();
    1287         }
    1288
    1289         limit(end);
    1290         decoder.reset();
    1291
    1292         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
    1293         CharBuffer out = CharBuffer.allocate(expectedLength);
    1294         for (;;) {
    1295             CoderResult cr;
    1296             if (hasRemaining()) {
    1297                 cr = decoder.decode(buf(), out, true);
    1298             } else {
    1299                 cr = decoder.flush(out);
    1300             }
    1301
    1302             if (cr.isUnderflow()) {
    1303                 break;
    1304             }
    1305
    1306             if (cr.isOverflow()) {
    1307                 CharBuffer o = CharBuffer.allocate(out.capacity()
    1308                         + expectedLength);
    1309                 out.flip();
    1310                 o.put(out);
    1311                 out = o;
    1312                 continue;
    1313             }
    1314
    1315             cr.throwException();
    1316         }
    1317
    1318         limit(oldLimit);
    1319         position(end);
    1320         return out.flip().toString();
    1321     }
    1322
    1323     /**
    1324      * Writes the content of <code>in</code> into this buffer as a
    1325      * string which has a 16-bit length field before the actual
    1326      * encoded string, using the specified <code>encoder</code>.
    1327      * This method is a shortcut for <tt>putPrefixedString(in, 2, 0, encoder)</tt>.
    1328      *
    1329      * @throws BufferOverflowException if the specified string doesn't fit
    1330      */
    1331     public ByteBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
    1332             throws CharacterCodingException {
    1333         return putPrefixedString(in, 2, 0, encoder);
    1334     }
    1335
    1336     /**
    1337      * Writes the content of <code>in</code> into this buffer as a
    1338      * string which has a 16-bit length field before the actual
    1339      * encoded string, using the specified <code>encoder</code>.
    1340      * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>.
    1341      *
    1342      * @param prefixLength the length of the length field (1, 2, or 4)
    1343      *
    1344      * @throws BufferOverflowException if the specified string doesn't fit
    1345      */
    1346     public ByteBuffer putPrefixedString(CharSequence in, int prefixLength,
    1347             CharsetEncoder encoder) throws CharacterCodingException {
    1348         return putPrefixedString(in, prefixLength, 0, encoder);
    1349     }
    1350
    1351     /**
    1352      * Writes the content of <code>in</code> into this buffer as a
    1353      * string which has a 16-bit length field before the actual
    1354      * encoded string, using the specified <code>encoder</code>.
    1355      * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>.
    1356      *
    1357      * @param prefixLength the length of the length field (1, 2, or 4)
    1358      * @param padding      the number of padded <tt>NUL</tt>s (1 (or 0), 2, or 4)
    1359      *
    1360      * @throws BufferOverflowException if the specified string doesn't fit
    1361      */
    1362     public ByteBuffer putPrefixedString(CharSequence in, int prefixLength,
    1363             int padding, CharsetEncoder encoder)
    1364             throws CharacterCodingException {
    1365         return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
    1366     }
    1367
    1368     /**
    1369      * Writes the content of <code>in</code> into this buffer as a
    1370      * string which has a 16-bit length field before the actual
    1371      * encoded string, using the specified <code>encoder</code>.
    1372      *
    1373      * @param prefixLength the length of the length field (1, 2, or 4)
    1374      * @param padding      the number of padded bytes (1 (or 0), 2, or 4)
    1375      * @param padValue     the value of padded bytes
    1376      *
    1377      * @throws BufferOverflowException if the specified string doesn't fit
    1378      */
    1379     public ByteBuffer putPrefixedString(CharSequence val, int prefixLength,
    1380             int padding, byte padValue, CharsetEncoder encoder)
    1381             throws CharacterCodingException {
    1382         int maxLength;
    1383         switch (prefixLength) {
    1384         case 1:
    1385             maxLength = 255;
    1386             break;
    1387         case 2:
    1388             maxLength = 65535;
    1389             break;
    1390         case 4:
    1391             maxLength = Integer.MAX_VALUE;
    1392             break;
    1393         default:
    1394             throw new IllegalArgumentException("prefixLength: " + prefixLength);
    1395         }
    1396
    1397         if (val.length() > maxLength) {
    1398             throw new IllegalArgumentException(
    1399                     "The specified string is too long.");
    1400         }
    1401         if (val.length() == 0) {
    1402             switch (prefixLength) {
    1403             case 1:
    1404                 put((byte) 0);
    1405                 break;
    1406             case 2:
    1407                 putShort((short) 0);
    1408                 break;
    1409             case 4:
    1410                 putInt(0);
    1411                 break;
    1412             }
    1413             return this;
    1414         }
    1415
    1416         int padMask;
    1417         switch (padding) {
    1418         case 0:
    1419         case 1:
    1420             padMask = 0;
    1421             break;
    1422         case 2:
    1423             padMask = 1;
    1424             break;
    1425         case 4:
    1426             padMask = 3;
    1427             break;
    1428         default:
    1429             throw new IllegalArgumentException("padding: " + padding);
    1430         }
    1431
    1432         CharBuffer in = CharBuffer.wrap(val);
    1433         int expectedLength = (int) (in.remaining() * encoder
    1434                 .averageBytesPerChar()) + 1;
    1435
    1436         skip(prefixLength); // make a room for the length field
    1437         int oldPos = position();
    1438         encoder.reset();
    1439
    1440         for (;;) {
    1441             CoderResult cr;
    1442             if (in.hasRemaining()) {
    1443                 cr = encoder.encode(in, buf(), true);
    1444             } else {
    1445                 cr = encoder.flush(buf());
    1446             }
    1447
    1448             if (position() - oldPos > maxLength) {
    1449                 throw new IllegalArgumentException(
    1450                         "The specified string is too long.");
    1451             }
    1452
    1453             if (cr.isUnderflow()) {
    1454                 break;
    1455             }
    1456             if (cr.isOverflow() && isAutoExpand()) {
    1457                 autoExpand(expectedLength);
    1458                 continue;
    1459             }
    1460             cr.throwException();
    1461         }
    1462
    1463         // Write the length field
    1464         fill(padValue, padding - ((position() - oldPos) & padMask));
    1465         int length = position() - oldPos;
    1466         switch (prefixLength) {
    1467         case 1:
    1468             put(oldPos - 1, (byte) length);
    1469             break;
    1470         case 2:
    1471             putShort(oldPos - 2, (short) length);
    1472             break;
    1473         case 4:
    1474             putInt(oldPos - 4, length);
    1475             break;
    1476         }
    1477         return this;
    1478     }
    1479
    1480     /**
    1481      * Reads a Java object from the buffer using the context {@link ClassLoader}
    1482      * of the current thread.
    1483      */
    1484     public Object getObject() throws ClassNotFoundException {
    1485         return getObject(Thread.currentThread().getContextClassLoader());
    1486     }
    1487
    1488     /**
    1489      * Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
    1490      */
    1491     public Object getObject(final ClassLoader classLoader)
    1492             throws ClassNotFoundException {
    1493         if (!prefixedDataAvailable(4)) {
    1494             throw new BufferUnderflowException();
    1495         }
    1496
    1497         int length = getInt();
    1498         if (length <= 4) {
    1499             throw new BufferDataException(
    1500                     "Object length should be greater than 4: " + length);
    1501         }
    1502
    1503         int oldLimit = limit();
    1504         limit(position() + length);
    1505         try {
    1506             ObjectInputStream in = new ObjectInputStream(asInputStream()) {
    1507                 @Override
    1508                 protected ObjectStreamClass readClassDescriptor()
    1509                         throws IOException, ClassNotFoundException {
    1510                     int type = read();
    1511                     if (type < 0) {
    1512                         throw new EOFException();
    1513                     }
    1514                     switch (type) {
    1515                     case 0: // Primitive types
    1516                         return super.readClassDescriptor();
    1517                     case 1: // Non-primitive types
    1518                         String className = readUTF();
    1519                         Class<?> clazz =
    1520                             Class.forName(className, true, classLoader);
    1521                         return ObjectStreamClass.lookup(clazz);
    1522                     default:
    1523                         throw new StreamCorruptedException(
    1524                                 "Unexpected class descriptor type: " + type);
    1525                     }
    1526                 }
    1527
    1528                 @Override
    1529                 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
    1530                     String name = desc.getName();
    1531                     try {
    1532                         return Class.forName(name, false, classLoader);
    1533                     } catch (ClassNotFoundException ex) {
    1534                         return super.resolveClass(desc);
    1535                     }
    1536                 }
    1537             };
    1538             return in.readObject();
    1539         } catch (IOException e) {
    1540             throw new BufferDataException(e);
    1541         } finally {
    1542             limit(oldLimit);
    1543         }
    1544     }
    1545
    1546     /**
    1547      * Writes the specified Java object to the buffer.
    1548      */
    1549     public ByteBuffer putObject(Object o) {
    1550         int oldPos = position();
    1551         skip(4); // Make a room for the length field.
    1552         try {
    1553             ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
    1554                 @Override
    1555                 protected void writeClassDescriptor(ObjectStreamClass desc)
    1556                         throws IOException {
    1557                     String className = desc.getName();
    1558                     if (primitiveTypeNames.contains(className)) {
    1559                         write(0);
    1560                         super.writeClassDescriptor(desc);
    1561                     } else {
    1562                         write(1);
    1563                         writeUTF(desc.getName());
    1564                     }
    1565                 }
    1566             };
    1567             out.writeObject(o);
    1568             out.flush();
    1569         } catch (IOException e) {
    1570             throw new BufferDataException(e);
    1571         }
    1572
    1573         // Fill the length field
    1574         int newPos = position();
    1575         position(oldPos);
    1576         putInt(newPos - oldPos - 4);
    1577         position(newPos);
    1578         return this;
    1579     }
    1580
    1581     /**
    1582      * Returns <tt>true</tt> if this buffer contains a data which has a data
    1583      * length as a prefix and the buffer has remaining data as enough as
    1584      * specified in the data length field.  This method is identical with
    1585      * <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>.
    1586      * Please not that using this method can allow DoS (Denial of Service)
    1587      * attack in case the remote peer sends too big data length value.
    1588      * It is recommended to use {@link #prefixedDataAvailable(int, int)}
    1589      * instead.
    1590      *
    1591      * @param prefixLength the length of the prefix field (1, 2, or 4)
    1592      *
    1593      * @throws IllegalArgumentException if prefixLength is wrong
    1594      * @throws BufferDataException      if data length is negative
    1595      */
    1596     public boolean prefixedDataAvailable(int prefixLength) {
    1597         return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
    1598     }
    1599
    1600     /**
    1601      * Returns <tt>true</tt> if this buffer contains a data which has a data
    1602      * length as a prefix and the buffer has remaining data as enough as
    1603      * specified in the data length field.
    1604      *
    1605      * @param prefixLength  the length of the prefix field (1, 2, or 4)
    1606      * @param maxDataLength the allowed maximum of the read data length
    1607      *
    1608      * @throws IllegalArgumentException if prefixLength is wrong
    1609      * @throws BufferDataException      if data length is negative or greater then <tt>maxDataLength</tt>
    1610      */
    1611     public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
    1612         if (remaining() < prefixLength) {
    1613             return false;
    1614         }
    1615
    1616         int dataLength;
    1617         switch (prefixLength) {
    1618         case 1:
    1619             dataLength = getUnsigned(position());
    1620             break;
    1621         case 2:
    1622             dataLength = getUnsignedShort(position());
    1623             break;
    1624         case 4:
    1625             dataLength = getInt(position());
    1626             break;
    1627         default:
    1628             throw new IllegalArgumentException("prefixLength: " + prefixLength);
    1629         }
    1630
    1631         if (dataLength < 0 || dataLength > maxDataLength) {
    1632             throw new BufferDataException("dataLength: " + dataLength);
    1633         }
    1634
    1635         return remaining() - prefixLength >= dataLength;
    1636     }
    1637
    1638     //////////////////////////
    1639     // Skip or fill methods //
    1640     //////////////////////////
    1641
    1642     /**
    1643      * Forwards the position of this buffer as the specified <code>size</code>
    1644      * bytes.
    1645      */
    1646     public ByteBuffer skip(int size) {
    1647         autoExpand(size);
    1648         return position(position() + size);
    1649     }
    1650
    1651     /**
    1652      * Fills this buffer with the specified value.
    1653      * This method moves buffer position forward.
    1654      */
    1655     public ByteBuffer fill(byte value, int size) {
    1656         autoExpand(size);
    1657         int q = size >>> 3;
    1658         int r = size & 7;
    1659
    1660         if (q > 0) {
    1661             int intValue = value | (value << 8) | (value << 16) | (value << 24);
    1662             long longValue = intValue;
    1663             longValue <<= 32;
    1664             longValue |= intValue;
    1665
    1666             for (int i = q; i > 0; i--) {
    1667                 putLong(longValue);
    1668             }
    1669         }
    1670
    1671         q = r >>> 2;
    1672         r = r & 3;
    1673
    1674         if (q > 0) {
    1675             int intValue = value | (value << 8) | (value << 16) | (value << 24);
    1676             putInt(intValue);
    1677         }
    1678
    1679         q = r >> 1;
    1680         r = r & 1;
    1681
    1682         if (q > 0) {
    1683             short shortValue = (short) (value | (value << 8));
    1684             putShort(shortValue);
    1685         }
    1686
    1687         if (r > 0) {
    1688             put(value);
    1689         }
    1690
    1691         return this;
    1692     }
    1693
    1694     /**
    1695      * Fills this buffer with the specified value.
    1696      * This method does not change buffer position.
    1697      */
    1698     public ByteBuffer fillAndReset(byte value, int size) {
    1699         autoExpand(size);
    1700         int pos = position();
    1701         try {
    1702             fill(value, size);
    1703         } finally {
    1704             position(pos);
    1705         }
    1706         return this;
    1707     }
    1708
    1709     /**
    1710      * Fills this buffer with <code>NUL (0x00)</code>.
    1711      * This method moves buffer position forward.
    1712      */
    1713     public ByteBuffer fill(int size) {
    1714         autoExpand(size);
    1715         int q = size >>> 3;
    1716         int r = size & 7;
    1717
    1718         for (int i = q; i > 0; i--) {
    1719             putLong(0L);
    1720         }
    1721
    1722         q = r >>> 2;
    1723         r = r & 3;
    1724
    1725         if (q > 0) {
    1726             putInt(0);
    1727         }
    1728
    1729         q = r >> 1;
    1730         r = r & 1;
    1731
    1732         if (q > 0) {
    1733             putShort((short) 0);
    1734         }
    1735
    1736         if (r > 0) {
    1737             put((byte) 0);
    1738         }
    1739
    1740         return this;
    1741     }
    1742
    1743     /**
    1744      * Fills this buffer with <code>NUL (0x00)</code>.
    1745      * This method does not change buffer position.
    1746      */
    1747     public ByteBuffer fillAndReset(int size) {
    1748         autoExpand(size);
    1749         int pos = position();
    1750         try {
    1751             fill(size);
    1752         } finally {
    1753             position(pos);
    1754         }
    1755
    1756         return this;
    1757     }
    1758
    1759     /**
    1760      * This method forwards the call to {@link #expand(int)} only when
    1761      * <tt>autoExpand</tt> property is <tt>true</tt>.
    1762      */
    1763     protected ByteBuffer autoExpand(int expectedRemaining) {
    1764         if (isAutoExpand()) {
    1765             expand(expectedRemaining);
    1766         }
    1767         return this;
    1768     }
    1769
    1770     /**
    1771      * This method forwards the call to {@link #expand(int)} only when
    1772      * <tt>autoExpand</tt> property is <tt>true</tt>.
    1773      */
    1774     protected ByteBuffer autoExpand(int pos, int expectedRemaining) {
    1775         if (isAutoExpand()) {
    1776             expand(pos, expectedRemaining);
    1777         }
    1778         return this;
    1779     }
    1780
    1781     private static void checkFieldSize(int fieldSize) {
    1782         if (fieldSize < 0) {
    1783             throw new IllegalArgumentException("fieldSize cannot be negative: "
    1784                     + fieldSize);
    1785         }
    1786     }
    1787 }