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