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