View Javadoc

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