View Javadoc

1   /*
2    *   @(#) $Id: ByteBuffer.java 332218 2005-11-10 03:52:42Z 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: 332218 $, $Date: 2005-11-10 12:52:42 +0900 $
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             decoder.reset();
1088 
1089             int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
1090             CharBuffer out = CharBuffer.allocate( expectedLength );
1091             for( ;; )
1092             {
1093                 CoderResult cr;
1094                 if ( buf.hasRemaining() )
1095                 {
1096                     cr = decoder.decode( buf, out, true );
1097                 }
1098                 else
1099                 {
1100                     cr = decoder.flush( out );
1101                 }
1102                 
1103                 if ( cr.isUnderflow() )
1104                 {
1105                     break;
1106                 }
1107                 
1108                 if ( cr.isOverflow() )
1109                 {
1110                     CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1111                     out.flip();
1112                     o.put(out);
1113                     out = o;
1114                     continue;
1115                 }
1116 
1117                 cr.throwException();
1118             }
1119             
1120             buf.limit( oldLimit );
1121             buf.position( end );
1122             return out.flip().toString();
1123         }
1124         
1125         public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException
1126         {
1127             checkFieldSize( fieldSize );
1128 
1129             if( fieldSize == 0 )
1130             {
1131                 return "";
1132             }
1133 
1134             if( !buf.hasRemaining() )
1135             {
1136                 return "";
1137             }
1138 
1139             boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
1140 
1141             if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1142             {
1143                 throw new IllegalArgumentException( "fieldSize is not even." );
1144             }
1145 
1146             int i;
1147             int oldPos = buf.position();
1148             int oldLimit = buf.limit();
1149             int end = buf.position() + fieldSize;
1150 
1151             if( oldLimit < end )
1152             {
1153                 throw new BufferUnderflowException();
1154             }
1155 
1156             if( !utf16 )
1157             {
1158                 for( i = 0; i < fieldSize; i ++ )
1159                 {
1160                     if( buf.get() == 0 )
1161                     {
1162                         break;
1163                     }
1164                 }
1165 
1166                 if( i == fieldSize )
1167                 {
1168                     buf.limit( end );
1169                 }
1170                 else
1171                 {
1172                     buf.limit( buf.position() - 1 );
1173                 }
1174             }
1175             else
1176             {
1177                 for( i = 0; i < fieldSize; i += 2 )
1178                 {
1179                     if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
1180                     {
1181                         break;
1182                     }
1183                 }
1184 
1185                 if( i == fieldSize )
1186                 {
1187                     buf.limit( end );
1188                 }
1189                 else
1190                 {
1191                     buf.limit( buf.position() - 2 );
1192                 }
1193             }
1194 
1195             buf.position( oldPos );
1196             decoder.reset();
1197 
1198             int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
1199             CharBuffer out = CharBuffer.allocate( expectedLength );
1200             for( ;; )
1201             {
1202                 CoderResult cr;
1203                 if ( buf.hasRemaining() )
1204                 {
1205                     cr = decoder.decode( buf, out, true );
1206                 }
1207                 else
1208                 {
1209                     cr = decoder.flush( out );
1210                 }
1211                 
1212                 if ( cr.isUnderflow() )
1213                 {
1214                     break;
1215                 }
1216                 
1217                 if ( cr.isOverflow() )
1218                 {
1219                     CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1220                     out.flip();
1221                     o.put(out);
1222                     out = o;
1223                     continue;
1224                 }
1225 
1226                 cr.throwException();
1227             }
1228             
1229             buf.limit( oldLimit );
1230             buf.position( end );
1231             return out.flip().toString();
1232         }
1233 
1234         public ByteBuffer putString(
1235                 CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException
1236         {
1237             checkFieldSize( fieldSize );
1238 
1239             if( fieldSize == 0 )
1240                 return this;
1241             
1242             autoExpand( fieldSize );
1243             
1244             boolean utf16 = encoder.charset().name().startsWith( "UTF-16" );
1245 
1246             if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1247             {
1248                 throw new IllegalArgumentException( "fieldSize is not even." );
1249             }
1250 
1251             int oldLimit = buf.limit();
1252             int end = buf.position() + fieldSize;
1253 
1254             if( oldLimit < end )
1255             {
1256                 throw new BufferOverflowException();
1257             }
1258 
1259             if( val.length() == 0 )
1260             {
1261                 if( !utf16 )
1262                 {
1263                     buf.put( ( byte ) 0x00 );
1264                 }
1265                 else
1266                 {
1267                     buf.put( ( byte ) 0x00 );
1268                     buf.put( ( byte ) 0x00 );
1269                 }
1270                 buf.position( end );
1271                 return this;
1272             }
1273             
1274             CharBuffer in = CharBuffer.wrap( val ); 
1275             buf.limit( end );
1276             encoder.reset();
1277 
1278             for (;;) {
1279                 CoderResult cr;
1280                 if( in.hasRemaining() )
1281                 {
1282                     cr = encoder.encode( in, buf(), true );
1283                 }
1284                 else
1285                 {
1286                     cr = encoder.flush( buf() );
1287                 }
1288                 
1289                 if( cr.isUnderflow() || cr.isOverflow() )
1290                 {
1291                     break;
1292                 }
1293                 cr.throwException();
1294             }
1295 
1296             buf.limit( oldLimit );
1297 
1298             if( buf.position() < end )
1299             {
1300                 if( !utf16 )
1301                 {
1302                     buf.put( ( byte ) 0x00 );
1303                 }
1304                 else
1305                 {
1306                     buf.put( ( byte ) 0x00 );
1307                     buf.put( ( byte ) 0x00 );
1308                 }
1309             }
1310 
1311             buf.position( end );
1312             return this;
1313         }
1314 
1315         public ByteBuffer putString(
1316                 CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException
1317         {
1318             if( val.length() == 0 )
1319             {
1320                 return this;
1321             }
1322             
1323             CharBuffer in = CharBuffer.wrap( val ); 
1324             int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar());
1325 
1326             encoder.reset();
1327 
1328             for (;;) {
1329                 CoderResult cr;
1330                 if( in.hasRemaining() )
1331                 {
1332                     cr = encoder.encode( in, buf(), true );
1333                 }
1334                 else
1335                 {
1336                     cr = encoder.flush( buf() );
1337                 }
1338                 
1339                 if( cr.isUnderflow() )
1340                 {
1341                     break;
1342                 }
1343                 if( cr.isOverflow() && autoExpand )
1344                 {
1345                     autoExpand( expectedLength );
1346                     continue;
1347                 }
1348                 cr.throwException();
1349             }
1350             return this;
1351         }
1352         
1353         public ByteBuffer skip( int size )
1354         {
1355             autoExpand( size );
1356             return position( position() + size );
1357         }
1358 
1359         public ByteBuffer fill( byte value, int size )
1360         {
1361             autoExpand( size );
1362             int q = size >>> 3;
1363             int r = size & 7;
1364 
1365             if( q > 0 )
1366             {
1367                 int intValue = value | ( value << 8 ) | ( value << 16 )
1368                                | ( value << 24 );
1369                 long longValue = intValue;
1370                 longValue <<= 32;
1371                 longValue |= intValue;
1372 
1373                 for( int i = q; i > 0; i -- )
1374                 {
1375                     buf.putLong( longValue );
1376                 }
1377             }
1378 
1379             q = r >>> 2;
1380             r = r & 3;
1381 
1382             if( q > 0 )
1383             {
1384                 int intValue = value | ( value << 8 ) | ( value << 16 )
1385                                | ( value << 24 );
1386                 buf.putInt( intValue );
1387             }
1388 
1389             q = r >> 1;
1390             r = r & 1;
1391 
1392             if( q > 0 )
1393             {
1394                 short shortValue = ( short ) ( value | ( value << 8 ) );
1395                 buf.putShort( shortValue );
1396             }
1397 
1398             if( r > 0 )
1399             {
1400                 buf.put( value );
1401             }
1402 
1403             return this;
1404         }
1405 
1406         public ByteBuffer fillAndReset( byte value, int size )
1407         {
1408             autoExpand( size );
1409             int pos = buf.position();
1410             try
1411             {
1412                 fill( value, size );
1413             }
1414             finally
1415             {
1416                 buf.position( pos );
1417             }
1418             return this;
1419         }
1420 
1421         public ByteBuffer fill( int size )
1422         {
1423             autoExpand( size );
1424             int q = size >>> 3;
1425             int r = size & 7;
1426 
1427             for( int i = q; i > 0; i -- )
1428             {
1429                 buf.putLong( 0L );
1430             }
1431 
1432             q = r >>> 2;
1433             r = r & 3;
1434 
1435             if( q > 0 )
1436             {
1437                 buf.putInt( 0 );
1438             }
1439 
1440             q = r >> 1;
1441             r = r & 1;
1442 
1443             if( q > 0 )
1444             {
1445                 buf.putShort( ( short ) 0 );
1446             }
1447 
1448             if( r > 0 )
1449             {
1450                 buf.put( ( byte ) 0 );
1451             }
1452 
1453             return this;
1454         }
1455 
1456         public ByteBuffer fillAndReset( int size )
1457         {
1458             autoExpand( size );
1459             int pos = buf.position();
1460             try
1461             {
1462                 fill( size );
1463             }
1464             finally
1465             {
1466                 buf.position( pos );
1467             }
1468 
1469             return this;
1470         }
1471 
1472         private void autoExpand( int delta )
1473         {
1474             if( autoExpand )
1475             {
1476                 int pos = buf.position();
1477                 int limit = buf.limit();
1478                 int end = pos + delta;
1479                 if( end > limit ) {
1480                     ensureCapacity( end );
1481                     buf.limit( end );
1482                 }
1483             }
1484         }
1485         
1486         private void autoExpand( int pos, int delta )
1487         {
1488             if( autoExpand )
1489             {
1490                 int limit = buf.limit();
1491                 int end = pos + delta;
1492                 if( end > limit ) {
1493                     ensureCapacity( end ); // expand by 50%
1494                     buf.limit( end );
1495                 }
1496             }
1497         }
1498         
1499         private void ensureCapacity( int requestedCapacity )
1500         {
1501             if( requestedCapacity <= buf.capacity() )
1502             {
1503                 return;
1504             }
1505             
1506             int newCapacity = MINIMUM_CAPACITY;
1507             while( newCapacity < requestedCapacity )
1508             {
1509                 newCapacity <<= 1;
1510             }
1511             
1512             java.nio.ByteBuffer oldBuf = this.buf;
1513             java.nio.ByteBuffer newBuf = allocate0( newCapacity, isDirect() );
1514             newBuf.clear();
1515             newBuf.order( oldBuf.order() );
1516 
1517             int pos = oldBuf.position();
1518             int limit = oldBuf.limit();
1519             oldBuf.clear();
1520             newBuf.put( oldBuf );
1521             newBuf.position( 0 );
1522             newBuf.limit( limit );
1523             newBuf.position( pos );
1524             this.buf = newBuf;
1525             release0( oldBuf );
1526         }
1527         
1528         private static void checkFieldSize( int fieldSize )
1529         {
1530             if( fieldSize < 0 )
1531             {
1532                 throw new IllegalArgumentException(
1533                         "fieldSize cannot be negative: " + fieldSize );
1534             }
1535         }
1536         
1537     }
1538 }