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: 595517 $, $Date: 2007-11-16 10:31:56 +0900 (금, 16 11월 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             return in.readObject();
1529         } catch (IOException e) {
1530             throw new BufferDataException(e);
1531         } finally {
1532             limit(oldLimit);
1533         }
1534     }
1535 
1536     /**
1537      * Writes the specified Java object to the buffer.
1538      */
1539     public ByteBuffer putObject(Object o) {
1540         int oldPos = position();
1541         skip(4); // Make a room for the length field.
1542         try {
1543             ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
1544                 @Override
1545                 protected void writeClassDescriptor(ObjectStreamClass desc)
1546                         throws IOException {
1547                     String className = desc.getName();
1548                     if (primitiveTypeNames.contains(className)) {
1549                         write(0);
1550                         super.writeClassDescriptor(desc);
1551                     } else {
1552                         write(1);
1553                         writeUTF(desc.getName());
1554                     }
1555                 }
1556             };
1557             out.writeObject(o);
1558             out.flush();
1559         } catch (IOException e) {
1560             throw new BufferDataException(e);
1561         }
1562 
1563         // Fill the length field
1564         int newPos = position();
1565         position(oldPos);
1566         putInt(newPos - oldPos - 4);
1567         position(newPos);
1568         return this;
1569     }
1570 
1571     /**
1572      * Returns <tt>true</tt> if this buffer contains a data which has a data
1573      * length as a prefix and the buffer has remaining data as enough as
1574      * specified in the data length field.  This method is identical with
1575      * <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>.
1576      * Please not that using this method can allow DoS (Denial of Service)
1577      * attack in case the remote peer sends too big data length value.
1578      * It is recommended to use {@link #prefixedDataAvailable(int, int)}
1579      * instead.
1580      *
1581      * @param prefixLength the length of the prefix field (1, 2, or 4)
1582      *
1583      * @throws IllegalArgumentException if prefixLength is wrong
1584      * @throws BufferDataException      if data length is negative
1585      */
1586     public boolean prefixedDataAvailable(int prefixLength) {
1587         return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
1588     }
1589 
1590     /**
1591      * Returns <tt>true</tt> if this buffer contains a data which has a data
1592      * length as a prefix and the buffer has remaining data as enough as
1593      * specified in the data length field.
1594      *
1595      * @param prefixLength  the length of the prefix field (1, 2, or 4)
1596      * @param maxDataLength the allowed maximum of the read data length
1597      *
1598      * @throws IllegalArgumentException if prefixLength is wrong
1599      * @throws BufferDataException      if data length is negative or greater then <tt>maxDataLength</tt>
1600      */
1601     public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
1602         if (remaining() < prefixLength) {
1603             return false;
1604         }
1605 
1606         int dataLength;
1607         switch (prefixLength) {
1608         case 1:
1609             dataLength = getUnsigned(position());
1610             break;
1611         case 2:
1612             dataLength = getUnsignedShort(position());
1613             break;
1614         case 4:
1615             dataLength = getInt(position());
1616             break;
1617         default:
1618             throw new IllegalArgumentException("prefixLength: " + prefixLength);
1619         }
1620 
1621         if (dataLength < 0 || dataLength > maxDataLength) {
1622             throw new BufferDataException("dataLength: " + dataLength);
1623         }
1624 
1625         return remaining() - prefixLength >= dataLength;
1626     }
1627 
1628     //////////////////////////
1629     // Skip or fill methods //
1630     //////////////////////////
1631 
1632     /**
1633      * Forwards the position of this buffer as the specified <code>size</code>
1634      * bytes.
1635      */
1636     public ByteBuffer skip(int size) {
1637         autoExpand(size);
1638         return position(position() + size);
1639     }
1640 
1641     /**
1642      * Fills this buffer with the specified value.
1643      * This method moves buffer position forward.
1644      */
1645     public ByteBuffer fill(byte value, int size) {
1646         autoExpand(size);
1647         int q = size >>> 3;
1648         int r = size & 7;
1649 
1650         if (q > 0) {
1651             int intValue = value | (value << 8) | (value << 16) | (value << 24);
1652             long longValue = intValue;
1653             longValue <<= 32;
1654             longValue |= intValue;
1655 
1656             for (int i = q; i > 0; i--) {
1657                 putLong(longValue);
1658             }
1659         }
1660 
1661         q = r >>> 2;
1662         r = r & 3;
1663 
1664         if (q > 0) {
1665             int intValue = value | (value << 8) | (value << 16) | (value << 24);
1666             putInt(intValue);
1667         }
1668 
1669         q = r >> 1;
1670         r = r & 1;
1671 
1672         if (q > 0) {
1673             short shortValue = (short) (value | (value << 8));
1674             putShort(shortValue);
1675         }
1676 
1677         if (r > 0) {
1678             put(value);
1679         }
1680 
1681         return this;
1682     }
1683 
1684     /**
1685      * Fills this buffer with the specified value.
1686      * This method does not change buffer position.
1687      */
1688     public ByteBuffer fillAndReset(byte value, int size) {
1689         autoExpand(size);
1690         int pos = position();
1691         try {
1692             fill(value, size);
1693         } finally {
1694             position(pos);
1695         }
1696         return this;
1697     }
1698 
1699     /**
1700      * Fills this buffer with <code>NUL (0x00)</code>.
1701      * This method moves buffer position forward.
1702      */
1703     public ByteBuffer fill(int size) {
1704         autoExpand(size);
1705         int q = size >>> 3;
1706         int r = size & 7;
1707 
1708         for (int i = q; i > 0; i--) {
1709             putLong(0L);
1710         }
1711 
1712         q = r >>> 2;
1713         r = r & 3;
1714 
1715         if (q > 0) {
1716             putInt(0);
1717         }
1718 
1719         q = r >> 1;
1720         r = r & 1;
1721 
1722         if (q > 0) {
1723             putShort((short) 0);
1724         }
1725 
1726         if (r > 0) {
1727             put((byte) 0);
1728         }
1729 
1730         return this;
1731     }
1732 
1733     /**
1734      * Fills this buffer with <code>NUL (0x00)</code>.
1735      * This method does not change buffer position.
1736      */
1737     public ByteBuffer fillAndReset(int size) {
1738         autoExpand(size);
1739         int pos = position();
1740         try {
1741             fill(size);
1742         } finally {
1743             position(pos);
1744         }
1745 
1746         return this;
1747     }
1748 
1749     /**
1750      * This method forwards the call to {@link #expand(int)} only when
1751      * <tt>autoExpand</tt> property is <tt>true</tt>.
1752      */
1753     protected ByteBuffer autoExpand(int expectedRemaining) {
1754         if (isAutoExpand()) {
1755             expand(expectedRemaining);
1756         }
1757         return this;
1758     }
1759 
1760     /**
1761      * This method forwards the call to {@link #expand(int)} only when
1762      * <tt>autoExpand</tt> property is <tt>true</tt>.
1763      */
1764     protected ByteBuffer autoExpand(int pos, int expectedRemaining) {
1765         if (isAutoExpand()) {
1766             expand(pos, expectedRemaining);
1767         }
1768         return this;
1769     }
1770 
1771     private static void checkFieldSize(int fieldSize) {
1772         if (fieldSize < 0) {
1773             throw new IllegalArgumentException("fieldSize cannot be negative: "
1774                     + fieldSize);
1775         }
1776     }
1777 }