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