View Javadoc

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