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 {
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 primitiveTypeNames = new HashSet();
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     public String toString() {
548         StringBuffer buf = new StringBuffer();
549         if (isDirect()) {
550             buf.append("DirectBuffer");
551         } else {
552             buf.append("HeapBuffer");
553         }
554         buf.append("[pos=");
555         buf.append(position());
556         buf.append(" lim=");
557         buf.append(limit());
558         buf.append(" cap=");
559         buf.append(capacity());
560         buf.append(": ");
561         buf.append(getHexDump());
562         buf.append(']');
563         return buf.toString();
564     }
565 
566     public int hashCode() {
567         int h = 1;
568         int p = position();
569         for (int i = limit() - 1; i >= p; i--) {
570             h = 31 * h + get(i);
571         }
572         return h;
573     }
574 
575     public boolean equals(Object o) {
576         if (!(o instanceof ByteBuffer)) {
577             return false;
578         }
579 
580         ByteBuffer that = (ByteBuffer) o;
581         if (this.remaining() != that.remaining()) {
582             return false;
583         }
584 
585         int p = this.position();
586         for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
587             byte v1 = this.get(i);
588             byte v2 = that.get(j);
589             if (v1 != v2) {
590                 return false;
591             }
592         }
593         return true;
594     }
595 
596     public int compareTo(Object o) {
597         ByteBuffer that = (ByteBuffer) o;
598         int n = this.position() + Math.min(this.remaining(), that.remaining());
599         for (int i = this.position(), j = that.position(); i < n; i++, j++) {
600             byte v1 = this.get(i);
601             byte v2 = that.get(j);
602             if (v1 == v2) {
603                 continue;
604             }
605             if (v1 < v2) {
606                 return -1;
607             }
608 
609             return +1;
610         }
611         return this.remaining() - that.remaining();
612     }
613 
614     /**
615      * @see java.nio.ByteBuffer#order()
616      */
617     public abstract ByteOrder order();
618 
619     /**
620      * @see java.nio.ByteBuffer#order(ByteOrder)
621      */
622     public abstract ByteBuffer order(ByteOrder bo);
623 
624     /**
625      * @see java.nio.ByteBuffer#getChar()
626      */
627     public abstract char getChar();
628 
629     /**
630      * @see java.nio.ByteBuffer#putChar(char)
631      */
632     public abstract ByteBuffer putChar(char value);
633 
634     /**
635      * @see java.nio.ByteBuffer#getChar(int)
636      */
637     public abstract char getChar(int index);
638 
639     /**
640      * @see java.nio.ByteBuffer#putChar(int, char)
641      */
642     public abstract ByteBuffer putChar(int index, char value);
643 
644     /**
645      * @see java.nio.ByteBuffer#asCharBuffer()
646      */
647     public abstract CharBuffer asCharBuffer();
648 
649     /**
650      * @see java.nio.ByteBuffer#getShort()
651      */
652     public abstract short getShort();
653 
654     /**
655      * Reads two bytes unsigned integer.
656      */
657     public int getUnsignedShort() {
658         return getShort() & 0xffff;
659     }
660 
661     /**
662      * @see java.nio.ByteBuffer#putShort(short)
663      */
664     public abstract ByteBuffer putShort(short value);
665 
666     /**
667      * @see java.nio.ByteBuffer#getShort()
668      */
669     public abstract short getShort(int index);
670 
671     /**
672      * Reads two bytes unsigned integer.
673      */
674     public int getUnsignedShort(int index) {
675         return getShort(index) & 0xffff;
676     }
677 
678     /**
679      * @see java.nio.ByteBuffer#putShort(int, short)
680      */
681     public abstract ByteBuffer putShort(int index, short value);
682 
683     /**
684      * @see java.nio.ByteBuffer#asShortBuffer()
685      */
686     public abstract ShortBuffer asShortBuffer();
687 
688     /**
689      * @see java.nio.ByteBuffer#getInt()
690      */
691     public abstract int getInt();
692 
693     /**
694      * Reads four bytes unsigned integer.
695      */
696     public long getUnsignedInt() {
697         return getInt() & 0xffffffffL;
698     }
699 
700     /**
701      * @see java.nio.ByteBuffer#putInt(int)
702      */
703     public abstract ByteBuffer putInt(int value);
704 
705     /**
706      * @see java.nio.ByteBuffer#getInt(int)
707      */
708     public abstract int getInt(int index);
709 
710     /**
711      * Reads four bytes unsigned integer.
712      */
713     public long getUnsignedInt(int index) {
714         return getInt(index) & 0xffffffffL;
715     }
716 
717     /**
718      * @see java.nio.ByteBuffer#putInt(int, int)
719      */
720     public abstract ByteBuffer putInt(int index, int value);
721 
722     /**
723      * @see java.nio.ByteBuffer#asIntBuffer()
724      */
725     public abstract IntBuffer asIntBuffer();
726 
727     /**
728      * @see java.nio.ByteBuffer#getLong()
729      */
730     public abstract long getLong();
731 
732     /**
733      * @see java.nio.ByteBuffer#putLong(int, long)
734      */
735     public abstract ByteBuffer putLong(long value);
736 
737     /**
738      * @see java.nio.ByteBuffer#getLong(int)
739      */
740     public abstract long getLong(int index);
741 
742     /**
743      * @see java.nio.ByteBuffer#putLong(int, long)
744      */
745     public abstract ByteBuffer putLong(int index, long value);
746 
747     /**
748      * @see java.nio.ByteBuffer#asLongBuffer()
749      */
750     public abstract LongBuffer asLongBuffer();
751 
752     /**
753      * @see java.nio.ByteBuffer#getFloat()
754      */
755     public abstract float getFloat();
756 
757     /**
758      * @see java.nio.ByteBuffer#putFloat(float)
759      */
760     public abstract ByteBuffer putFloat(float value);
761 
762     /**
763      * @see java.nio.ByteBuffer#getFloat(int)
764      */
765     public abstract float getFloat(int index);
766 
767     /**
768      * @see java.nio.ByteBuffer#putFloat(int, float)
769      */
770     public abstract ByteBuffer putFloat(int index, float value);
771 
772     /**
773      * @see java.nio.ByteBuffer#asFloatBuffer()
774      */
775     public abstract FloatBuffer asFloatBuffer();
776 
777     /**
778      * @see java.nio.ByteBuffer#getDouble()
779      */
780     public abstract double getDouble();
781 
782     /**
783      * @see java.nio.ByteBuffer#putDouble(double)
784      */
785     public abstract ByteBuffer putDouble(double value);
786 
787     /**
788      * @see java.nio.ByteBuffer#getDouble(int)
789      */
790     public abstract double getDouble(int index);
791 
792     /**
793      * @see java.nio.ByteBuffer#putDouble(int, double)
794      */
795     public abstract ByteBuffer putDouble(int index, double value);
796 
797     /**
798      * @see java.nio.ByteBuffer#asDoubleBuffer()
799      */
800     public abstract DoubleBuffer asDoubleBuffer();
801 
802     /**
803      * Returns an {@link InputStream} that reads the data from this buffer.
804      * {@link InputStream#read()} returns <tt>-1</tt> if the buffer position
805      * reaches to the limit.
806      */
807     public InputStream asInputStream() {
808         return new InputStream() {
809             public int available() {
810                 return ByteBuffer.this.remaining();
811             }
812 
813             public synchronized void mark(int readlimit) {
814                 ByteBuffer.this.mark();
815             }
816 
817             public boolean markSupported() {
818                 return true;
819             }
820 
821             public int read() {
822                 if (ByteBuffer.this.hasRemaining()) {
823                     return ByteBuffer.this.get() & 0xff;
824                 } else {
825                     return -1;
826                 }
827             }
828 
829             public int read(byte[] b, int off, int len) {
830                 int remaining = ByteBuffer.this.remaining();
831                 if (remaining > 0) {
832                     int readBytes = Math.min(remaining, len);
833                     ByteBuffer.this.get(b, off, readBytes);
834                     return readBytes;
835                 } else {
836                     return -1;
837                 }
838             }
839 
840             public synchronized void reset() {
841                 ByteBuffer.this.reset();
842             }
843 
844             public long skip(long n) {
845                 int bytes;
846                 if (n > Integer.MAX_VALUE) {
847                     bytes = ByteBuffer.this.remaining();
848                 } else {
849                     bytes = Math.min(ByteBuffer.this.remaining(), (int) n);
850                 }
851                 ByteBuffer.this.skip(bytes);
852                 return bytes;
853             }
854         };
855     }
856 
857     /**
858      * Returns an {@link OutputStream} that appends the data into this buffer.
859      * Please note that the {@link OutputStream#write(int)} will throw a
860      * {@link BufferOverflowException} instead of an {@link IOException}
861      * in case of buffer overflow.  Please set <tt>autoExpand</tt> property by
862      * calling {@link #setAutoExpand(boolean)} to prevent the unexpected runtime
863      * exception.
864      */
865     public OutputStream asOutputStream() {
866         return new OutputStream() {
867             public void write(byte[] b, int off, int len) {
868                 ByteBuffer.this.put(b, off, len);
869             }
870 
871             public void write(int b) {
872                 ByteBuffer.this.put((byte) b);
873             }
874         };
875     }
876 
877     /**
878      * Returns hexdump of this buffer.
879      */
880     public String getHexDump() {
881         return ByteBufferHexDumper.getHexdump(this);
882     }
883 
884     ////////////////////////////////
885     // String getters and putters //
886     ////////////////////////////////
887 
888     /**
889      * Reads a <code>NUL</code>-terminated string from this buffer using the
890      * specified <code>decoder</code> and returns it.  This method reads
891      * until the limit of this buffer if no <tt>NUL</tt> is found.
892      */
893     public String getString(CharsetDecoder decoder)
894             throws CharacterCodingException {
895         if (!hasRemaining()) {
896             return "";
897         }
898 
899         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
900 
901         int oldPos = position();
902         int oldLimit = limit();
903         int end;
904 
905         if (!utf16) {
906             while (hasRemaining()) {
907                 if (get() == 0) {
908                     break;
909                 }
910             }
911 
912             end = position();
913             if (end == oldLimit && get(end - 1) != 0) {
914                 limit(end);
915             } else {
916                 limit(end - 1);
917             }
918         } else {
919             while (remaining() >= 2) {
920                 boolean highZero = (get() == 0);
921                 boolean lowZero = (get() == 0);
922                 if (highZero && lowZero) {
923                     break;
924                 }
925             }
926 
927             end = position();
928             if (end == oldLimit || end == oldLimit - 1) {
929                 limit(end);
930             } else {
931                 limit(end - 2);
932             }
933         }
934 
935         position(oldPos);
936         if (!hasRemaining()) {
937             limit(oldLimit);
938             position(end);
939             return "";
940         }
941         decoder.reset();
942 
943         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
944         CharBuffer out = CharBuffer.allocate(expectedLength);
945         for (;;) {
946             CoderResult cr;
947             if (hasRemaining()) {
948                 cr = decoder.decode(buf(), out, true);
949             } else {
950                 cr = decoder.flush(out);
951             }
952 
953             if (cr.isUnderflow()) {
954                 break;
955             }
956 
957             if (cr.isOverflow()) {
958                 CharBuffer o = CharBuffer.allocate(out.capacity()
959                         + expectedLength);
960                 out.flip();
961                 o.put(out);
962                 out = o;
963                 continue;
964             }
965 
966             if (cr.isError()) {
967                 // Revert the buffer back to the previous state.
968                 limit(oldLimit);
969                 position(oldPos);
970                 cr.throwException();
971             }
972         }
973 
974         limit(oldLimit);
975         position(end);
976         return out.flip().toString();
977     }
978 
979     /**
980      * Reads a <code>NUL</code>-terminated string from this buffer using the
981      * specified <code>decoder</code> and returns it.
982      *
983      * @param fieldSize the maximum number of bytes to read
984      */
985     public String getString(int fieldSize, CharsetDecoder decoder)
986             throws CharacterCodingException {
987         checkFieldSize(fieldSize);
988 
989         if (fieldSize == 0) {
990             return "";
991         }
992 
993         if (!hasRemaining()) {
994             return "";
995         }
996 
997         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
998 
999         if (utf16 && ((fieldSize & 1) != 0)) {
1000             throw new IllegalArgumentException("fieldSize is not even.");
1001         }
1002 
1003         int oldPos = position();
1004         int oldLimit = limit();
1005         int end = position() + fieldSize;
1006 
1007         if (oldLimit < end) {
1008             throw new BufferUnderflowException();
1009         }
1010 
1011         int i;
1012 
1013         if (!utf16) {
1014             for (i = 0; i < fieldSize; i++) {
1015                 if (get() == 0) {
1016                     break;
1017                 }
1018             }
1019 
1020             if (i == fieldSize) {
1021                 limit(end);
1022             } else {
1023                 limit(position() - 1);
1024             }
1025         } else {
1026             for (i = 0; i < fieldSize; i += 2) {
1027                 boolean highZero = (get() == 0);
1028                 boolean lowZero = (get() == 0);
1029                 if (highZero && lowZero) {
1030                     break;
1031                 }
1032             }
1033 
1034             if (i == fieldSize) {
1035                 limit(end);
1036             } else {
1037                 limit(position() - 2);
1038             }
1039         }
1040 
1041         position(oldPos);
1042         if (!hasRemaining()) {
1043             limit(oldLimit);
1044             position(end);
1045             return "";
1046         }
1047         decoder.reset();
1048 
1049         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1050         CharBuffer out = CharBuffer.allocate(expectedLength);
1051         for (;;) {
1052             CoderResult cr;
1053             if (hasRemaining()) {
1054                 cr = decoder.decode(buf(), out, true);
1055             } else {
1056                 cr = decoder.flush(out);
1057             }
1058 
1059             if (cr.isUnderflow()) {
1060                 break;
1061             }
1062 
1063             if (cr.isOverflow()) {
1064                 CharBuffer o = CharBuffer.allocate(out.capacity()
1065                         + expectedLength);
1066                 out.flip();
1067                 o.put(out);
1068                 out = o;
1069                 continue;
1070             }
1071 
1072             if (cr.isError()) {
1073                 // Revert the buffer back to the previous state.
1074                 limit(oldLimit);
1075                 position(oldPos);
1076                 cr.throwException();
1077             }
1078         }
1079 
1080         limit(oldLimit);
1081         position(end);
1082         return out.flip().toString();
1083     }
1084 
1085     /**
1086      * Writes the content of <code>in</code> into this buffer using the
1087      * specified <code>encoder</code>.  This method doesn't terminate
1088      * string with <tt>NUL</tt>.  You have to do it by yourself.
1089      *
1090      * @throws BufferOverflowException if the specified string doesn't fit
1091      */
1092     public ByteBuffer putString(CharSequence val, CharsetEncoder encoder)
1093             throws CharacterCodingException {
1094         if (val.length() == 0) {
1095             return this;
1096         }
1097 
1098         CharBuffer in = CharBuffer.wrap(val);
1099         encoder.reset();
1100 
1101         int expandedState = 0;
1102 
1103         for (;;) {
1104             CoderResult cr;
1105             if (in.hasRemaining()) {
1106                 cr = encoder.encode(in, buf(), true);
1107             } else {
1108                 cr = encoder.flush(buf());
1109             }
1110 
1111             if (cr.isUnderflow()) {
1112                 break;
1113             }
1114             if (cr.isOverflow()) {
1115                 if (isAutoExpand()) {
1116                     switch (expandedState) {
1117                     case 0:
1118                         autoExpand((int) Math.ceil(in.remaining()
1119                                 * encoder.averageBytesPerChar()));
1120                         expandedState++;
1121                         break;
1122                     case 1:
1123                         autoExpand((int) Math.ceil(in.remaining()
1124                                 * encoder.maxBytesPerChar()));
1125                         expandedState++;
1126                         break;
1127                     default:
1128                         throw new RuntimeException("Expanded by "
1129                                 + (int) Math.ceil(in.remaining()
1130                                         * encoder.maxBytesPerChar())
1131                                 + " but that wasn't enough for '" + val + "'");
1132                     }
1133                     continue;
1134                 }
1135             } else {
1136                 expandedState = 0;
1137             }
1138             cr.throwException();
1139         }
1140         return this;
1141     }
1142 
1143     /**
1144      * Writes the content of <code>in</code> into this buffer as a
1145      * <code>NUL</code>-terminated string using the specified
1146      * <code>encoder</code>.
1147      * <p>
1148      * If the charset name of the encoder is UTF-16, you cannot specify
1149      * odd <code>fieldSize</code>, and this method will append two
1150      * <code>NUL</code>s as a terminator.
1151      * <p>
1152      * Please note that this method doesn't terminate with <code>NUL</code>
1153      * if the input string is longer than <tt>fieldSize</tt>.
1154      *
1155      * @param fieldSize the maximum number of bytes to write
1156      */
1157     public ByteBuffer putString(CharSequence val, int fieldSize,
1158             CharsetEncoder encoder) throws CharacterCodingException {
1159         checkFieldSize(fieldSize);
1160 
1161         if (fieldSize == 0)
1162             return this;
1163 
1164         autoExpand(fieldSize);
1165 
1166         boolean utf16 = encoder.charset().name().startsWith("UTF-16");
1167 
1168         if (utf16 && ((fieldSize & 1) != 0)) {
1169             throw new IllegalArgumentException("fieldSize is not even.");
1170         }
1171 
1172         int oldLimit = limit();
1173         int end = position() + fieldSize;
1174 
1175         if (oldLimit < end) {
1176             throw new BufferOverflowException();
1177         }
1178 
1179         if (val.length() == 0) {
1180             if (!utf16) {
1181                 put((byte) 0x00);
1182             } else {
1183                 put((byte) 0x00);
1184                 put((byte) 0x00);
1185             }
1186             position(end);
1187             return this;
1188         }
1189 
1190         CharBuffer in = CharBuffer.wrap(val);
1191         limit(end);
1192         encoder.reset();
1193 
1194         for (;;) {
1195             CoderResult cr;
1196             if (in.hasRemaining()) {
1197                 cr = encoder.encode(in, buf(), true);
1198             } else {
1199                 cr = encoder.flush(buf());
1200             }
1201 
1202             if (cr.isUnderflow() || cr.isOverflow()) {
1203                 break;
1204             }
1205             cr.throwException();
1206         }
1207 
1208         limit(oldLimit);
1209 
1210         if (position() < end) {
1211             if (!utf16) {
1212                 put((byte) 0x00);
1213             } else {
1214                 put((byte) 0x00);
1215                 put((byte) 0x00);
1216             }
1217         }
1218 
1219         position(end);
1220         return this;
1221     }
1222 
1223     /**
1224      * Reads a string which has a 16-bit length field before the actual
1225      * encoded string, using the specified <code>decoder</code> and returns it.
1226      * This method is a shortcut for <tt>getPrefixedString(2, decoder)</tt>.
1227      */
1228     public String getPrefixedString(CharsetDecoder decoder)
1229             throws CharacterCodingException {
1230         return getPrefixedString(2, decoder);
1231     }
1232 
1233     /**
1234      * Reads a string which has a length field before the actual
1235      * encoded string, using the specified <code>decoder</code> and returns it.
1236      *
1237      * @param prefixLength the length of the length field (1, 2, or 4)
1238      */
1239     public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
1240             throws CharacterCodingException {
1241         if (!prefixedDataAvailable(prefixLength)) {
1242             throw new BufferUnderflowException();
1243         }
1244 
1245         int fieldSize = 0;
1246 
1247         switch (prefixLength) {
1248         case 1:
1249             fieldSize = getUnsigned();
1250             break;
1251         case 2:
1252             fieldSize = getUnsignedShort();
1253             break;
1254         case 4:
1255             fieldSize = getInt();
1256             break;
1257         }
1258 
1259         if (fieldSize == 0) {
1260             return "";
1261         }
1262 
1263         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1264 
1265         if (utf16 && ((fieldSize & 1) != 0)) {
1266             throw new BufferDataException(
1267                     "fieldSize is not even for a UTF-16 string.");
1268         }
1269 
1270         int oldLimit = limit();
1271         int end = position() + fieldSize;
1272 
1273         if (oldLimit < end) {
1274             throw new BufferUnderflowException();
1275         }
1276 
1277         limit(end);
1278         decoder.reset();
1279 
1280         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1281         CharBuffer out = CharBuffer.allocate(expectedLength);
1282         for (;;) {
1283             CoderResult cr;
1284             if (hasRemaining()) {
1285                 cr = decoder.decode(buf(), out, true);
1286             } else {
1287                 cr = decoder.flush(out);
1288             }
1289 
1290             if (cr.isUnderflow()) {
1291                 break;
1292             }
1293 
1294             if (cr.isOverflow()) {
1295                 CharBuffer o = CharBuffer.allocate(out.capacity()
1296                         + expectedLength);
1297                 out.flip();
1298                 o.put(out);
1299                 out = o;
1300                 continue;
1301             }
1302 
1303             cr.throwException();
1304         }
1305 
1306         limit(oldLimit);
1307         position(end);
1308         return out.flip().toString();
1309     }
1310 
1311     /**
1312      * Writes the content of <code>in</code> into this buffer as a
1313      * string which has a 16-bit length field before the actual
1314      * encoded string, using the specified <code>encoder</code>.
1315      * This method is a shortcut for <tt>putPrefixedString(in, 2, 0, encoder)</tt>.
1316      *
1317      * @throws BufferOverflowException if the specified string doesn't fit
1318      */
1319     public ByteBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
1320             throws CharacterCodingException {
1321         return putPrefixedString(in, 2, 0, encoder);
1322     }
1323 
1324     /**
1325      * Writes the content of <code>in</code> into this buffer as a
1326      * string which has a 16-bit length field before the actual
1327      * encoded string, using the specified <code>encoder</code>.
1328      * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>.
1329      *
1330      * @param prefixLength the length of the length field (1, 2, or 4)
1331      *
1332      * @throws BufferOverflowException if the specified string doesn't fit
1333      */
1334     public ByteBuffer putPrefixedString(CharSequence in, int prefixLength,
1335             CharsetEncoder encoder) throws CharacterCodingException {
1336         return putPrefixedString(in, prefixLength, 0, encoder);
1337     }
1338 
1339     /**
1340      * Writes the content of <code>in</code> into this buffer as a
1341      * string which has a 16-bit length field before the actual
1342      * encoded string, using the specified <code>encoder</code>.
1343      * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>.
1344      *
1345      * @param prefixLength the length of the length field (1, 2, or 4)
1346      * @param padding      the number of padded <tt>NUL</tt>s (1 (or 0), 2, or 4)
1347      *
1348      * @throws BufferOverflowException if the specified string doesn't fit
1349      */
1350     public ByteBuffer putPrefixedString(CharSequence in, int prefixLength,
1351             int padding, CharsetEncoder encoder)
1352             throws CharacterCodingException {
1353         return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
1354     }
1355 
1356     /**
1357      * Writes the content of <code>in</code> into this buffer as a
1358      * string which has a 16-bit length field before the actual
1359      * encoded string, using the specified <code>encoder</code>.
1360      *
1361      * @param prefixLength the length of the length field (1, 2, or 4)
1362      * @param padding      the number of padded bytes (1 (or 0), 2, or 4)
1363      * @param padValue     the value of padded bytes
1364      *
1365      * @throws BufferOverflowException if the specified string doesn't fit
1366      */
1367     public ByteBuffer putPrefixedString(CharSequence val, int prefixLength,
1368             int padding, byte padValue, CharsetEncoder encoder)
1369             throws CharacterCodingException {
1370         int maxLength;
1371         switch (prefixLength) {
1372         case 1:
1373             maxLength = 255;
1374             break;
1375         case 2:
1376             maxLength = 65535;
1377             break;
1378         case 4:
1379             maxLength = Integer.MAX_VALUE;
1380             break;
1381         default:
1382             throw new IllegalArgumentException("prefixLength: " + prefixLength);
1383         }
1384 
1385         if (val.length() > maxLength) {
1386             throw new IllegalArgumentException(
1387                     "The specified string is too long.");
1388         }
1389         if (val.length() == 0) {
1390             switch (prefixLength) {
1391             case 1:
1392                 put((byte) 0);
1393                 break;
1394             case 2:
1395                 putShort((short) 0);
1396                 break;
1397             case 4:
1398                 putInt(0);
1399                 break;
1400             }
1401             return this;
1402         }
1403 
1404         int padMask;
1405         switch (padding) {
1406         case 0:
1407         case 1:
1408             padMask = 0;
1409             break;
1410         case 2:
1411             padMask = 1;
1412             break;
1413         case 4:
1414             padMask = 3;
1415             break;
1416         default:
1417             throw new IllegalArgumentException("padding: " + padding);
1418         }
1419 
1420         CharBuffer in = CharBuffer.wrap(val);
1421         int expectedLength = (int) (in.remaining() * encoder
1422                 .averageBytesPerChar()) + 1;
1423 
1424         skip(prefixLength); // make a room for the length field
1425         int oldPos = position();
1426         encoder.reset();
1427 
1428         for (;;) {
1429             CoderResult cr;
1430             if (in.hasRemaining()) {
1431                 cr = encoder.encode(in, buf(), true);
1432             } else {
1433                 cr = encoder.flush(buf());
1434             }
1435 
1436             if (position() - oldPos > maxLength) {
1437                 throw new IllegalArgumentException(
1438                         "The specified string is too long.");
1439             }
1440 
1441             if (cr.isUnderflow()) {
1442                 break;
1443             }
1444             if (cr.isOverflow() && isAutoExpand()) {
1445                 autoExpand(expectedLength);
1446                 continue;
1447             }
1448             cr.throwException();
1449         }
1450 
1451         // Write the length field
1452         fill(padValue, padding - ((position() - oldPos) & padMask));
1453         int length = position() - oldPos;
1454         switch (prefixLength) {
1455         case 1:
1456             put(oldPos - 1, (byte) length);
1457             break;
1458         case 2:
1459             putShort(oldPos - 2, (short) length);
1460             break;
1461         case 4:
1462             putInt(oldPos - 4, length);
1463             break;
1464         }
1465         return this;
1466     }
1467 
1468     /**
1469      * Reads a Java object from the buffer using the context {@link ClassLoader}
1470      * of the current thread.
1471      */
1472     public Object getObject() throws ClassNotFoundException {
1473         return getObject(Thread.currentThread().getContextClassLoader());
1474     }
1475 
1476     /**
1477      * Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
1478      */
1479     public Object getObject(final ClassLoader classLoader)
1480             throws ClassNotFoundException {
1481         if (!prefixedDataAvailable(4)) {
1482             throw new BufferUnderflowException();
1483         }
1484 
1485         int length = getInt();
1486         if (length <= 4) {
1487             throw new BufferDataException(
1488                     "Object length should be greater than 4: " + length);
1489         }
1490 
1491         int oldLimit = limit();
1492         limit(position() + length);
1493         try {
1494             ObjectInputStream in = new ObjectInputStream(asInputStream()) {
1495                 protected ObjectStreamClass readClassDescriptor()
1496                         throws IOException, ClassNotFoundException {
1497                     int type = read();
1498                     if (type < 0) {
1499                         throw new EOFException();
1500                     }
1501                     switch (type) {
1502                     case 0: // Primitive types
1503                         return super.readClassDescriptor();
1504                     case 1: // Non-primitive types
1505                         String className = readUTF();
1506                         Class clazz =
1507                             Class.forName(className, true, classLoader);
1508                         return ObjectStreamClass.lookup(clazz);
1509                     default:
1510                         throw new StreamCorruptedException(
1511                                 "Unexpected class descriptor type: " + type);
1512                     }
1513                 }
1514                 
1515                 protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
1516                     String name = desc.getName();
1517                     try {
1518                         return Class.forName(name, false, classLoader);
1519                     } catch (ClassNotFoundException ex) {
1520                         return super.resolveClass(desc);
1521                     }
1522                 }
1523             };
1524             return in.readObject();
1525         } catch (IOException e) {
1526             throw new BufferDataException(e);
1527         } finally {
1528             limit(oldLimit);
1529         }
1530     }
1531 
1532     /**
1533      * Writes the specified Java object to the buffer.
1534      */
1535     public ByteBuffer putObject(Object o) {
1536         int oldPos = position();
1537         skip(4); // Make a room for the length field.
1538         try {
1539             ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
1540                 protected void writeClassDescriptor(ObjectStreamClass desc)
1541                         throws IOException {
1542                     String className = desc.getName();
1543                     if (primitiveTypeNames.contains(className)) {
1544                         write(0);
1545                         super.writeClassDescriptor(desc);
1546                     } else {
1547                         write(1);
1548                         writeUTF(desc.getName());
1549                     }
1550                 }
1551             };
1552             out.writeObject(o);
1553             out.flush();
1554         } catch (IOException e) {
1555             throw new BufferDataException(e);
1556         }
1557 
1558         // Fill the length field
1559         int newPos = position();
1560         position(oldPos);
1561         putInt(newPos - oldPos - 4);
1562         position(newPos);
1563         return this;
1564     }
1565 
1566     /**
1567      * Returns <tt>true</tt> if this buffer contains a data which has a data
1568      * length as a prefix and the buffer has remaining data as enough as
1569      * specified in the data length field.  This method is identical with
1570      * <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>.
1571      * Please not that using this method can allow DoS (Denial of Service)
1572      * attack in case the remote peer sends too big data length value.
1573      * It is recommended to use {@link #prefixedDataAvailable(int, int)}
1574      * instead.
1575      *
1576      * @param prefixLength the length of the prefix field (1, 2, or 4)
1577      *
1578      * @throws IllegalArgumentException if prefixLength is wrong
1579      * @throws BufferDataException      if data length is negative
1580      */
1581     public boolean prefixedDataAvailable(int prefixLength) {
1582         return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
1583     }
1584 
1585     /**
1586      * Returns <tt>true</tt> if this buffer contains a data which has a data
1587      * length as a prefix and the buffer has remaining data as enough as
1588      * specified in the data length field.
1589      *
1590      * @param prefixLength  the length of the prefix field (1, 2, or 4)
1591      * @param maxDataLength the allowed maximum of the read data length
1592      *
1593      * @throws IllegalArgumentException if prefixLength is wrong
1594      * @throws BufferDataException      if data length is negative or greater then <tt>maxDataLength</tt>
1595      */
1596     public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
1597         if (remaining() < prefixLength) {
1598             return false;
1599         }
1600 
1601         int dataLength;
1602         switch (prefixLength) {
1603         case 1:
1604             dataLength = getUnsigned(position());
1605             break;
1606         case 2:
1607             dataLength = getUnsignedShort(position());
1608             break;
1609         case 4:
1610             dataLength = getInt(position());
1611             break;
1612         default:
1613             throw new IllegalArgumentException("prefixLength: " + prefixLength);
1614         }
1615 
1616         if (dataLength < 0 || dataLength > maxDataLength) {
1617             throw new BufferDataException("dataLength: " + dataLength);
1618         }
1619 
1620         return remaining() - prefixLength >= dataLength;
1621     }
1622 
1623     //////////////////////////
1624     // Skip or fill methods //
1625     //////////////////////////
1626 
1627     /**
1628      * Forwards the position of this buffer as the specified <code>size</code>
1629      * bytes.
1630      */
1631     public ByteBuffer skip(int size) {
1632         autoExpand(size);
1633         return position(position() + size);
1634     }
1635 
1636     /**
1637      * Fills this buffer with the specified value.
1638      * This method moves buffer position forward.
1639      */
1640     public ByteBuffer fill(byte value, int size) {
1641         autoExpand(size);
1642         int q = size >>> 3;
1643         int r = size & 7;
1644 
1645         if (q > 0) {
1646             int intValue = value | (value << 8) | (value << 16) | (value << 24);
1647             long longValue = intValue;
1648             longValue <<= 32;
1649             longValue |= intValue;
1650 
1651             for (int i = q; i > 0; i--) {
1652                 putLong(longValue);
1653             }
1654         }
1655 
1656         q = r >>> 2;
1657         r = r & 3;
1658 
1659         if (q > 0) {
1660             int intValue = value | (value << 8) | (value << 16) | (value << 24);
1661             putInt(intValue);
1662         }
1663 
1664         q = r >> 1;
1665         r = r & 1;
1666 
1667         if (q > 0) {
1668             short shortValue = (short) (value | (value << 8));
1669             putShort(shortValue);
1670         }
1671 
1672         if (r > 0) {
1673             put(value);
1674         }
1675 
1676         return this;
1677     }
1678 
1679     /**
1680      * Fills this buffer with the specified value.
1681      * This method does not change buffer position.
1682      */
1683     public ByteBuffer fillAndReset(byte value, int size) {
1684         autoExpand(size);
1685         int pos = position();
1686         try {
1687             fill(value, size);
1688         } finally {
1689             position(pos);
1690         }
1691         return this;
1692     }
1693 
1694     /**
1695      * Fills this buffer with <code>NUL (0x00)</code>.
1696      * This method moves buffer position forward.
1697      */
1698     public ByteBuffer fill(int size) {
1699         autoExpand(size);
1700         int q = size >>> 3;
1701         int r = size & 7;
1702 
1703         for (int i = q; i > 0; i--) {
1704             putLong(0L);
1705         }
1706 
1707         q = r >>> 2;
1708         r = r & 3;
1709 
1710         if (q > 0) {
1711             putInt(0);
1712         }
1713 
1714         q = r >> 1;
1715         r = r & 1;
1716 
1717         if (q > 0) {
1718             putShort((short) 0);
1719         }
1720 
1721         if (r > 0) {
1722             put((byte) 0);
1723         }
1724 
1725         return this;
1726     }
1727 
1728     /**
1729      * Fills this buffer with <code>NUL (0x00)</code>.
1730      * This method does not change buffer position.
1731      */
1732     public ByteBuffer fillAndReset(int size) {
1733         autoExpand(size);
1734         int pos = position();
1735         try {
1736             fill(size);
1737         } finally {
1738             position(pos);
1739         }
1740 
1741         return this;
1742     }
1743 
1744     /**
1745      * This method forwards the call to {@link #expand(int)} only when
1746      * <tt>autoExpand</tt> property is <tt>true</tt>.
1747      */
1748     protected ByteBuffer autoExpand(int expectedRemaining) {
1749         if (isAutoExpand()) {
1750             expand(expectedRemaining);
1751         }
1752         return this;
1753     }
1754 
1755     /**
1756      * This method forwards the call to {@link #expand(int)} only when
1757      * <tt>autoExpand</tt> property is <tt>true</tt>.
1758      */
1759     protected ByteBuffer autoExpand(int pos, int expectedRemaining) {
1760         if (isAutoExpand()) {
1761             expand(pos, expectedRemaining);
1762         }
1763         return this;
1764     }
1765 
1766     private static void checkFieldSize(int fieldSize) {
1767         if (fieldSize < 0) {
1768             throw new IllegalArgumentException("fieldSize cannot be negative: "
1769                     + fieldSize);
1770         }
1771     }
1772 }