View Javadoc

1   /*
2    *   @(#) $Id: ByteBuffer.java 210062 2005-07-11 03:52:38Z 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.  But please be careful and use these
94   * methods at your own risk.  Using those methods can cause memory leakage
95   * if you keep wrapping new NIO buffers and arrays because even wrapped
96   * MINA buffers are going to be pooled when they are released by MINA.
97   * <p>
98   * To resolve this issue, please do not keeping wrapping NIO buffers if
99   * possible.  If you're working with any third party component that keeps
100  * creating NIO buffers, please call {@link #acquire()} once more and
101  * don't call {@link #release()} for it, then it will not be returned to
102  * the pool and GC'd eventually.  Here's the example:
103  * <pre>
104  * import org.apache.mina.common.*;
105  * import org.apache.mina.io.*;
106  *
107  * IoSession session = ...;
108  * for (;;) {
109  *     // readData() returns a newly allocate NIO buffer.
110  *     java.nio.ByteBuffer newBuffer = otherApplication.readData();
111  *     
112  *     // Wrap it.
113  *     ByteBuffer wrappedBuffer = ByteBuffer.wrap(newBuffer);
114  *     // Acquire once and don't call release to prevent MINA from pooling it. 
115  *     wrappedBuffer.acquire();
116  *     session.write(wrappedBuffer, marker);
117  * }
118  * </pre>
119  * 
120  * <h2>AutoExpand</h2>
121  * <p>
122  * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really
123  * easy, and it is because its size is fixed.  MINA <tt>ByteBuffer</tt>
124  * introduces <tt>autoExpand</tt> property.  If <tt>autoExpand</tt> property
125  * is true, you never get {@link BufferOverflowException} or
126  * {@link IndexOutOfBoundsException} (except when index is negative).
127  * It automatically expands its capacity and limit value.  For example:
128  * <pre>
129  * String greeting = messageBundle.getMessage( "hello" );
130  * ByteBuffer buf = ByteBuffer.allocate( 16 );
131  * // Turn on autoExpand (it is off by default)
132  * buf.setAutoExpand( true );
133  * buf.putString( greeting, utf8encoder );
134  * </pre>
135  * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind
136  * the scene if the encoded data is larger than 16 bytes.  Its capacity will
137  * increase by two times, and its limit will increase to the last position
138  * the string is written.
139  * 
140  * @author Trustin Lee (trustin@apache.org)
141  * @version $Rev: 210062 $, $Date: 2005-07-11 12:52:38 +0900 $
142  */
143 public abstract class ByteBuffer
144 {
145     private static final int MINIMUM_CAPACITY = 1;
146 
147     private static final Stack containerStack = new Stack();
148 
149     private static final Stack[] heapBufferStacks = new Stack[] {
150             new Stack(), new Stack(), new Stack(), new Stack(),
151             new Stack(), new Stack(), new Stack(), new Stack(),
152             new Stack(), new Stack(), new Stack(), new Stack(),
153             new Stack(), new Stack(), new Stack(), new Stack(),
154             new Stack(), new Stack(), new Stack(), new Stack(),
155             new Stack(), new Stack(), new Stack(), new Stack(),
156             new Stack(), new Stack(), new Stack(), new Stack(),
157             new Stack(), new Stack(), new Stack(), new Stack(), };
158     
159     private static final Stack[] directBufferStacks = new Stack[] {
160             new Stack(), new Stack(), new Stack(), new Stack(),
161             new Stack(), new Stack(), new Stack(), new Stack(),
162             new Stack(), new Stack(), new Stack(), new Stack(),
163             new Stack(), new Stack(), new Stack(), new Stack(),
164             new Stack(), new Stack(), new Stack(), new Stack(),
165             new Stack(), new Stack(), new Stack(), new Stack(),
166             new Stack(), new Stack(), new Stack(), new Stack(),
167             new Stack(), new Stack(), new Stack(), new Stack(), };
168     
169     /***
170      * Returns the direct or heap buffer which is capable of the specified
171      * size.  This method tries to allocate direct buffer first, and then
172      * tries heap buffer if direct buffer memory is exhausted.  Please use
173      * {@link #allocate(int, boolean)} to allocate buffers of specific type.
174      * 
175      * @param capacity the capacity of the buffer
176      */
177     public static ByteBuffer allocate( int capacity )
178     {
179         try
180         {
181             // first try to allocate direct buffer
182             return allocate( capacity, true );
183         }
184         catch( OutOfMemoryError e )
185         {
186             // if failed, try heap
187             return allocate( capacity, false );
188         }
189     }
190     
191     /***
192      * Returns the buffer which is capable of the specified size.
193      * 
194      * @param capacity the capacity of the buffer
195      * @param direct <tt>true</tt> to get a direct buffer,
196      *               <tt>false</tt> to get a heap buffer.
197      */
198     public static ByteBuffer allocate( int capacity, boolean direct )
199     {
200         java.nio.ByteBuffer nioBuffer = allocate0( capacity, direct );
201         DefaultByteBuffer buf = allocateContainer();
202         buf.init( nioBuffer );
203         return buf;
204     }
205 
206     private static DefaultByteBuffer allocateContainer()
207     {
208         DefaultByteBuffer buf;
209         synchronized( containerStack )
210         {
211             buf = ( DefaultByteBuffer ) containerStack.pop();
212         }
213         
214         if( buf == null )
215         {
216             buf = new DefaultByteBuffer();
217         }
218         return buf;
219     }
220     
221     private static java.nio.ByteBuffer allocate0( int capacity, boolean direct )
222     {
223         Stack[] bufferStacks = direct? directBufferStacks : heapBufferStacks;
224         int idx = getBufferStackIndex( bufferStacks, capacity );
225         Stack stack = bufferStacks[ idx ];
226 
227         java.nio.ByteBuffer buf;
228         synchronized( stack )
229         {
230             buf = ( java.nio.ByteBuffer ) stack.pop();
231         }
232 
233         if( buf == null )
234         {
235             buf = direct ? java.nio.ByteBuffer.allocateDirect( MINIMUM_CAPACITY << idx ) :
236                            java.nio.ByteBuffer.allocate( MINIMUM_CAPACITY << idx );
237         }
238         
239         buf.clear();
240         buf.order( ByteOrder.BIG_ENDIAN );
241         return buf;
242     }
243     
244     private static void release0( java.nio.ByteBuffer buf )
245     {
246         Stack[] bufferStacks = buf.isDirect()? directBufferStacks : heapBufferStacks;
247         Stack stack = bufferStacks[ getBufferStackIndex( bufferStacks, buf.capacity() ) ];
248         synchronized( stack )
249         {
250             // push back
251             stack.push( buf );
252         }
253     }
254     
255     /***
256      * Wraps the specified NIO {@link java.nio.ByteBuffer} into MINA buffer.
257      */
258     public static ByteBuffer wrap( java.nio.ByteBuffer nioBuffer )
259     {
260         DefaultByteBuffer buf = allocateContainer();
261         buf.init( nioBuffer );
262         return buf;
263     }
264     
265     /***
266      * Wraps the specified byte array into MINA heap buffer.
267      */
268     public static ByteBuffer wrap( byte[] byteArray )
269     {
270         return wrap( java.nio.ByteBuffer.wrap( byteArray ) );
271     }
272     
273     /***
274      * Wraps the specified byte array into MINA heap buffer.
275      * Please note that MINA buffers are going to be pooled, and
276      * therefore there can be waste of memory if you wrap
277      * your byte array specifying <tt>offset</tt> and <tt>length</tt>.
278      */
279     public static ByteBuffer wrap( byte[] byteArray, int offset, int length )
280     {
281         return wrap( java.nio.ByteBuffer.wrap( byteArray, offset, length ) );
282     }
283     
284     private static int getBufferStackIndex( Stack[] bufferStacks, int size )
285     {
286         int targetSize = MINIMUM_CAPACITY;
287         int stackIdx = 0;
288         while( size > targetSize )
289         {
290             targetSize <<= 1;
291             stackIdx ++ ;
292             if( stackIdx >= bufferStacks.length )
293             {
294                 throw new IllegalArgumentException(
295                         "Buffer size is too big: " + size );
296             }
297         }
298 
299         return stackIdx;
300     }
301 
302     protected ByteBuffer()
303     {
304     }
305 
306     /***
307      * Increases the internal reference count of this buffer to defer
308      * automatic release.  You have to invoke {@link #release()} as many
309      * as you invoked this method to release this buffer.
310      * 
311      * @throws IllegalStateException if you attempt to acquire already
312      *                               released buffer.
313      */
314     public abstract void acquire();
315 
316     /***
317      * Releases the specified buffer to buffer pool.
318      * 
319      * @throws IllegalStateException if you attempt to release already
320      *                               released buffer.
321      */
322     public abstract void release();
323 
324     /***
325      * Returns the underlying NIO buffer instance.
326      */
327     public abstract java.nio.ByteBuffer buf();
328     
329     public abstract boolean isDirect();
330     
331     public abstract int capacity();
332     
333     /***
334      * Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on.
335      */
336     public abstract boolean isAutoExpand();
337     
338     /***
339      * Turns on or off <tt>autoExpand</tt>.
340      */
341     public abstract ByteBuffer setAutoExpand( boolean autoExpand );
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 
561         protected DefaultByteBuffer()
562         {
563         }
564 
565         private synchronized void init( java.nio.ByteBuffer buf )
566         {
567             this.buf = buf;
568             autoExpand = false;
569             refCount = 1;
570         }
571         
572         public synchronized void acquire()
573         {
574             if( refCount <= 0 )
575             {
576                 throw new IllegalStateException( "Already released buffer." );
577             }
578 
579             refCount ++;
580         }
581 
582         public void release()
583         {
584             synchronized( this )
585             {
586                 if( refCount <= 0 )
587                 {
588                     refCount = 0;
589                     throw new IllegalStateException(
590                             "Already released buffer.  You released the buffer too many times." );
591                 }
592 
593                 refCount --;
594                 if( refCount > 0)
595                 {
596                     return;
597                 }
598             }
599 
600             release0( buf );
601             synchronized( containerStack )
602             {
603                 containerStack.push( this );
604             }
605         }
606 
607         public java.nio.ByteBuffer buf()
608         {
609             return buf;
610         }
611         
612         public boolean isDirect()
613         {
614             return buf.isDirect();
615         }
616         
617         public boolean isReadOnly()
618         {
619             return buf.isReadOnly();
620         }
621         
622         public boolean isAutoExpand()
623         {
624             return autoExpand;
625         }
626         
627         public ByteBuffer setAutoExpand( boolean autoExpand )
628         {
629             this.autoExpand = autoExpand;
630             return this;
631         }
632 
633         public int capacity()
634         {
635             return buf.capacity();
636         }
637         
638         public int position()
639         {
640             return buf.position();
641         }
642 
643         public ByteBuffer position( int newPosition )
644         {
645             autoExpand( newPosition, 0 );
646             buf.position( newPosition );
647             return this;
648         }
649 
650         public int limit()
651         {
652             return buf.limit();
653         }
654 
655         public ByteBuffer limit( int newLimit )
656         {
657             autoExpand( newLimit, 0 );
658             buf.limit( newLimit );
659             return this;
660         }
661 
662         public ByteBuffer mark()
663         {
664             buf.mark();
665             return this;
666         }
667 
668         public ByteBuffer reset()
669         {
670             buf.reset();
671             return this;
672         }
673 
674         public ByteBuffer clear()
675         {
676             buf.clear();
677             return this;
678         }
679 
680         public ByteBuffer flip()
681         {
682             buf.flip();
683             return this;
684         }
685 
686         public ByteBuffer rewind()
687         {
688             buf.rewind();
689             return this;
690         }
691 
692         public int remaining()
693         {
694             return buf.remaining();
695         }
696 
697         public boolean hasRemaining()
698         {
699             return buf.hasRemaining();
700         }
701 
702         public byte get()
703         {
704             return buf.get();
705         }
706 
707         public short getUnsigned()
708         {
709             return ( short ) ( get() & 0xff );
710         }
711 
712         public ByteBuffer put( byte b )
713         {
714             autoExpand( 1 );
715             buf.put( b );
716             return this;
717         }
718 
719         public byte get( int index )
720         {
721             return buf.get( index );
722         }
723 
724         public short getUnsigned( int index )
725         {
726             return ( short ) ( get( index ) & 0xff );
727         }
728 
729         public ByteBuffer put( int index, byte b )
730         {
731             autoExpand( index, 1 );
732             buf.put( index, b );
733             return this;
734         }
735 
736         public ByteBuffer get( byte[] dst, int offset, int length )
737         {
738             buf.get( dst, offset, length );
739             return this;
740         }
741 
742         public ByteBuffer get( byte[] dst )
743         {
744             buf.get( dst );
745             return this;
746         }
747 
748         public ByteBuffer put( java.nio.ByteBuffer src )
749         {
750             autoExpand( src.remaining() );
751             buf.put( src );
752             return this;
753         }
754 
755         public ByteBuffer put( ByteBuffer src )
756         {
757             autoExpand( src.remaining() );
758             buf.put( src.buf() );
759             return this;
760         }
761 
762         public ByteBuffer put( byte[] src, int offset, int length )
763         {
764             autoExpand( length );
765             buf.put( src, offset, length );
766             return this;
767         }
768 
769         public ByteBuffer put( byte[] src )
770         {
771             autoExpand( src.length );
772             buf.put( src );
773             return this;
774         }
775 
776         public ByteBuffer compact()
777         {
778             buf.compact();
779             return this;
780         }
781 
782         public String toString()
783         {
784             return buf.toString();
785         }
786 
787         public int hashCode()
788         {
789             return buf.hashCode();
790         }
791 
792         public boolean equals( Object ob )
793         {
794             if( !( ob instanceof ByteBuffer ) )
795                 return false;
796 
797             ByteBuffer that = ( ByteBuffer ) ob;
798             return this.buf.equals( that.buf() );
799         }
800 
801         public int compareTo( ByteBuffer that )
802         {
803             return this.buf.compareTo( that.buf() );
804         }
805 
806         public ByteOrder order()
807         {
808             return buf.order();
809         }
810 
811         public ByteBuffer order( ByteOrder bo )
812         {
813             buf.order( bo );
814             return this;
815         }
816 
817         public char getChar()
818         {
819             return buf.getChar();
820         }
821 
822         public ByteBuffer putChar( char value )
823         {
824             autoExpand( 2 );
825             buf.putChar( value );
826             return this;
827         }
828 
829         public char getChar( int index )
830         {
831             return buf.getChar( index );
832         }
833 
834         public ByteBuffer putChar( int index, char value )
835         {
836             autoExpand( index, 2 );
837             buf.putChar( index, value );
838             return this;
839         }
840 
841         public CharBuffer asCharBuffer()
842         {
843             return buf.asCharBuffer();
844         }
845 
846         public short getShort()
847         {
848             return buf.getShort();
849         }
850 
851         public int getUnsignedShort()
852         {
853             return getShort() & 0xffff;
854         }
855 
856         public ByteBuffer putShort( short value )
857         {
858             autoExpand( 2 );
859             buf.putShort( value );
860             return this;
861         }
862 
863         public short getShort( int index )
864         {
865             return buf.getShort( index );
866         }
867 
868         public int getUnsignedShort( int index )
869         {
870             return getShort( index ) & 0xffff;
871         }
872 
873         public ByteBuffer putShort( int index, short value )
874         {
875             autoExpand( index, 2 );
876             buf.putShort( index, value );
877             return this;
878         }
879 
880         public ShortBuffer asShortBuffer()
881         {
882             return buf.asShortBuffer();
883         }
884 
885         public int getInt()
886         {
887             return buf.getInt();
888         }
889 
890         public long getUnsignedInt()
891         {
892             return getInt() & 0xffffffffL;
893         }
894 
895         public ByteBuffer putInt( int value )
896         {
897             autoExpand( 4 );
898             buf.putInt( value );
899             return this;
900         }
901 
902         public int getInt( int index )
903         {
904             return buf.getInt( index );
905         }
906 
907         public long getUnsignedInt( int index )
908         {
909             return getInt( index ) & 0xffffffffL;
910         }
911 
912         public ByteBuffer putInt( int index, int value )
913         {
914             autoExpand( index, 4 );
915             buf.putInt( index, value );
916             return this;
917         }
918 
919         public IntBuffer asIntBuffer()
920         {
921             return buf.asIntBuffer();
922         }
923 
924         public long getLong()
925         {
926             return buf.getLong();
927         }
928 
929         public ByteBuffer putLong( long value )
930         {
931             autoExpand( 8 );
932             buf.putLong( value );
933             return this;
934         }
935 
936         public long getLong( int index )
937         {
938             return buf.getLong( index );
939         }
940 
941         public ByteBuffer putLong( int index, long value )
942         {
943             autoExpand( index, 8 );
944             buf.putLong( index, value );
945             return this;
946         }
947 
948         public LongBuffer asLongBuffer()
949         {
950             return buf.asLongBuffer();
951         }
952 
953         public float getFloat()
954         {
955             return buf.getFloat();
956         }
957 
958         public ByteBuffer putFloat( float value )
959         {
960             autoExpand( 4 );
961             buf.putFloat( value );
962             return this;
963         }
964 
965         public float getFloat( int index )
966         {
967             return buf.getFloat( index );
968         }
969 
970         public ByteBuffer putFloat( int index, float value )
971         {
972             autoExpand( index, 4 );
973             buf.putFloat( index, value );
974             return this;
975         }
976 
977         public FloatBuffer asFloatBuffer()
978         {
979             return buf.asFloatBuffer();
980         }
981 
982         public double getDouble()
983         {
984             return buf.getDouble();
985         }
986 
987         public ByteBuffer putDouble( double value )
988         {
989             autoExpand( 8 );
990             buf.putDouble( value );
991             return this;
992         }
993 
994         public double getDouble( int index )
995         {
996             return buf.getDouble( index );
997         }
998 
999         public ByteBuffer putDouble( int index, double value )
1000         {
1001             autoExpand( index, 8 );
1002             buf.putDouble( index, value );
1003             return this;
1004         }
1005 
1006         public DoubleBuffer asDoubleBuffer()
1007         {
1008             return buf.asDoubleBuffer();
1009         }
1010 
1011         public String getHexDump()
1012         {
1013             return ByteBufferHexDumper.getHexdump( this );
1014         }
1015 
1016         public String getString( CharsetDecoder decoder ) throws CharacterCodingException
1017         {
1018             if( !buf.hasRemaining() )
1019             {
1020                 return "";
1021             }
1022 
1023             boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
1024 
1025             int oldPos = buf.position();
1026             int oldLimit = buf.limit();
1027             int end;
1028 
1029             if( !utf16 )
1030             {
1031                 while( buf.hasRemaining() )
1032                 {
1033                     if( buf.get() == 0 )
1034                     {
1035                         break;
1036                     }
1037                 }
1038 
1039                 end = buf.position();
1040                 if( end == oldLimit )
1041                 {
1042                     buf.limit( end );
1043                 }
1044                 else
1045                 {
1046                     buf.limit( end - 1 );
1047                 }
1048             }
1049             else
1050             {
1051                 while( buf.remaining() >= 2 )
1052                 {
1053                     if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
1054                     {
1055                         break;
1056                     }
1057                 }
1058 
1059                 end = buf.position();
1060                 if( end == oldLimit || end == oldLimit - 1 )
1061                 {
1062                     buf.limit( end );
1063                 }
1064                 else
1065                 {
1066                     buf.limit( end - 2 );
1067                 }
1068             }
1069 
1070             buf.position( oldPos );
1071             decoder.reset();
1072 
1073             int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
1074             CharBuffer out = CharBuffer.allocate( expectedLength );
1075             for( ;; )
1076             {
1077                 CoderResult cr;
1078                 if ( buf.hasRemaining() )
1079                 {
1080                     cr = decoder.decode( buf, out, true );
1081                 }
1082                 else
1083                 {
1084                     cr = decoder.flush( out );
1085                 }
1086                 
1087                 if ( cr.isUnderflow() )
1088                 {
1089                     break;
1090                 }
1091                 
1092                 if ( cr.isOverflow() )
1093                 {
1094                     CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1095                     out.flip();
1096                     o.put(out);
1097                     out = o;
1098                     continue;
1099                 }
1100 
1101                 cr.throwException();
1102             }
1103             
1104             buf.limit( oldLimit );
1105             buf.position( end );
1106             return out.flip().toString();
1107         }
1108         
1109         public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException
1110         {
1111             checkFieldSize( fieldSize );
1112 
1113             if( fieldSize == 0 )
1114             {
1115                 return "";
1116             }
1117 
1118             if( !buf.hasRemaining() )
1119             {
1120                 return "";
1121             }
1122 
1123             boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
1124 
1125             if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1126             {
1127                 throw new IllegalArgumentException( "fieldSize is not even." );
1128             }
1129 
1130             int i;
1131             int oldPos = buf.position();
1132             int oldLimit = buf.limit();
1133             int end = buf.position() + fieldSize;
1134 
1135             if( oldLimit < end )
1136             {
1137                 throw new BufferUnderflowException();
1138             }
1139 
1140             if( !utf16 )
1141             {
1142                 for( i = 0; i < fieldSize; i ++ )
1143                 {
1144                     if( buf.get() == 0 )
1145                     {
1146                         break;
1147                     }
1148                 }
1149 
1150                 if( i == fieldSize )
1151                 {
1152                     buf.limit( end );
1153                 }
1154                 else
1155                 {
1156                     buf.limit( buf.position() - 1 );
1157                 }
1158             }
1159             else
1160             {
1161                 for( i = 0; i < fieldSize; i += 2 )
1162                 {
1163                     if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
1164                     {
1165                         break;
1166                     }
1167                 }
1168 
1169                 if( i == fieldSize )
1170                 {
1171                     buf.limit( end );
1172                 }
1173                 else
1174                 {
1175                     buf.limit( buf.position() - 2 );
1176                 }
1177             }
1178 
1179             buf.position( oldPos );
1180             decoder.reset();
1181 
1182             int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
1183             CharBuffer out = CharBuffer.allocate( expectedLength );
1184             for( ;; )
1185             {
1186                 CoderResult cr;
1187                 if ( buf.hasRemaining() )
1188                 {
1189                     cr = decoder.decode( buf, out, true );
1190                 }
1191                 else
1192                 {
1193                     cr = decoder.flush( out );
1194                 }
1195                 
1196                 if ( cr.isUnderflow() )
1197                 {
1198                     break;
1199                 }
1200                 
1201                 if ( cr.isOverflow() )
1202                 {
1203                     CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1204                     out.flip();
1205                     o.put(out);
1206                     out = o;
1207                     continue;
1208                 }
1209 
1210                 cr.throwException();
1211             }
1212             
1213             buf.limit( oldLimit );
1214             buf.position( end );
1215             return out.flip().toString();
1216         }
1217 
1218         public ByteBuffer putString(
1219                 CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException
1220         {
1221             checkFieldSize( fieldSize );
1222 
1223             if( fieldSize == 0 )
1224                 return this;
1225             
1226             autoExpand( fieldSize );
1227             
1228             boolean utf16 = encoder.charset().name().startsWith( "UTF-16" );
1229 
1230             if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1231             {
1232                 throw new IllegalArgumentException( "fieldSize is not even." );
1233             }
1234 
1235             int oldLimit = buf.limit();
1236             int end = buf.position() + fieldSize;
1237 
1238             if( oldLimit < end )
1239             {
1240                 throw new BufferOverflowException();
1241             }
1242 
1243             if( val.length() == 0 )
1244             {
1245                 if( !utf16 )
1246                 {
1247                     buf.put( ( byte ) 0x00 );
1248                 }
1249                 else
1250                 {
1251                     buf.put( ( byte ) 0x00 );
1252                     buf.put( ( byte ) 0x00 );
1253                 }
1254                 buf.position( end );
1255                 return this;
1256             }
1257             
1258             CharBuffer in = CharBuffer.wrap( val ); 
1259             buf.limit( end );
1260             encoder.reset();
1261 
1262             for (;;) {
1263                 CoderResult cr;
1264                 if( in.hasRemaining() )
1265                 {
1266                     cr = encoder.encode( in, buf(), true );
1267                 }
1268                 else
1269                 {
1270                     cr = encoder.flush( buf() );
1271                 }
1272                 
1273                 if( cr.isUnderflow() || cr.isOverflow() )
1274                 {
1275                     break;
1276                 }
1277                 cr.throwException();
1278             }
1279 
1280             buf.limit( oldLimit );
1281 
1282             if( buf.position() < end )
1283             {
1284                 if( !utf16 )
1285                 {
1286                     buf.put( ( byte ) 0x00 );
1287                 }
1288                 else
1289                 {
1290                     buf.put( ( byte ) 0x00 );
1291                     buf.put( ( byte ) 0x00 );
1292                 }
1293             }
1294 
1295             buf.position( end );
1296             return this;
1297         }
1298 
1299         public ByteBuffer putString(
1300                 CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException
1301         {
1302             if( val.length() == 0 )
1303             {
1304                 return this;
1305             }
1306             
1307             CharBuffer in = CharBuffer.wrap( val ); 
1308             int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar());
1309 
1310             encoder.reset();
1311 
1312             for (;;) {
1313                 CoderResult cr;
1314                 if( in.hasRemaining() )
1315                 {
1316                     cr = encoder.encode( in, buf(), true );
1317                 }
1318                 else
1319                 {
1320                     cr = encoder.flush( buf() );
1321                 }
1322                 
1323                 if( cr.isUnderflow() )
1324                 {
1325                     break;
1326                 }
1327                 if( cr.isOverflow() && autoExpand )
1328                 {
1329                     autoExpand( expectedLength );
1330                     continue;
1331                 }
1332                 cr.throwException();
1333             }
1334             return this;
1335         }
1336         
1337         public ByteBuffer skip( int size )
1338         {
1339             autoExpand( size );
1340             return position( position() + size );
1341         }
1342 
1343         public ByteBuffer fill( byte value, int size )
1344         {
1345             autoExpand( size );
1346             int q = size >>> 3;
1347             int r = size & 7;
1348 
1349             if( q > 0 )
1350             {
1351                 int intValue = value | ( value << 8 ) | ( value << 16 )
1352                                | ( value << 24 );
1353                 long longValue = intValue;
1354                 longValue <<= 32;
1355                 longValue |= intValue;
1356 
1357                 for( int i = q; i > 0; i -- )
1358                 {
1359                     buf.putLong( longValue );
1360                 }
1361             }
1362 
1363             q = r >>> 2;
1364             r = r & 3;
1365 
1366             if( q > 0 )
1367             {
1368                 int intValue = value | ( value << 8 ) | ( value << 16 )
1369                                | ( value << 24 );
1370                 buf.putInt( intValue );
1371             }
1372 
1373             q = r >> 1;
1374             r = r & 1;
1375 
1376             if( q > 0 )
1377             {
1378                 short shortValue = ( short ) ( value | ( value << 8 ) );
1379                 buf.putShort( shortValue );
1380             }
1381 
1382             if( r > 0 )
1383             {
1384                 buf.put( value );
1385             }
1386 
1387             return this;
1388         }
1389 
1390         public ByteBuffer fillAndReset( byte value, int size )
1391         {
1392             autoExpand( size );
1393             int pos = buf.position();
1394             try
1395             {
1396                 fill( value, size );
1397             }
1398             finally
1399             {
1400                 buf.position( pos );
1401             }
1402             return this;
1403         }
1404 
1405         public ByteBuffer fill( int size )
1406         {
1407             autoExpand( size );
1408             int q = size >>> 3;
1409             int r = size & 7;
1410 
1411             for( int i = q; i > 0; i -- )
1412             {
1413                 buf.putLong( 0L );
1414             }
1415 
1416             q = r >>> 2;
1417             r = r & 3;
1418 
1419             if( q > 0 )
1420             {
1421                 buf.putInt( 0 );
1422             }
1423 
1424             q = r >> 1;
1425             r = r & 1;
1426 
1427             if( q > 0 )
1428             {
1429                 buf.putShort( ( short ) 0 );
1430             }
1431 
1432             if( r > 0 )
1433             {
1434                 buf.put( ( byte ) 0 );
1435             }
1436 
1437             return this;
1438         }
1439 
1440         public ByteBuffer fillAndReset( int size )
1441         {
1442             autoExpand( size );
1443             int pos = buf.position();
1444             try
1445             {
1446                 fill( size );
1447             }
1448             finally
1449             {
1450                 buf.position( pos );
1451             }
1452 
1453             return this;
1454         }
1455 
1456         private void autoExpand( int delta )
1457         {
1458             if( autoExpand )
1459             {
1460                 int pos = buf.position();
1461                 int limit = buf.limit();
1462                 int end = pos + delta;
1463                 if( end > limit ) {
1464                     ensureCapacity( end );
1465                     buf.limit( end );
1466                 }
1467             }
1468         }
1469         
1470         private void autoExpand( int pos, int delta )
1471         {
1472             if( autoExpand )
1473             {
1474                 int limit = buf.limit();
1475                 int end = pos + delta;
1476                 if( end > limit ) {
1477                     ensureCapacity( end ); // expand by 50%
1478                     buf.limit( end );
1479                 }
1480             }
1481         }
1482         
1483         private void ensureCapacity( int requestedCapacity )
1484         {
1485             if( requestedCapacity <= buf.capacity() )
1486             {
1487                 return;
1488             }
1489             
1490             int newCapacity = MINIMUM_CAPACITY;
1491             while( newCapacity < requestedCapacity )
1492             {
1493                 newCapacity <<= 1;
1494             }
1495             
1496             java.nio.ByteBuffer oldBuf = this.buf;
1497             java.nio.ByteBuffer newBuf = allocate0( newCapacity, isDirect() );
1498             newBuf.clear();
1499             newBuf.order( oldBuf.order() );
1500 
1501             int pos = oldBuf.position();
1502             int limit = oldBuf.limit();
1503             oldBuf.clear();
1504             newBuf.put( oldBuf );
1505             newBuf.position( 0 );
1506             newBuf.limit( limit );
1507             newBuf.position( pos );
1508             this.buf = newBuf;
1509             release0( oldBuf );
1510         }
1511         
1512         private static void checkFieldSize( int fieldSize )
1513         {
1514             if( fieldSize < 0 )
1515             {
1516                 throw new IllegalArgumentException(
1517                         "fieldSize cannot be negative: " + fieldSize );
1518             }
1519         }
1520         
1521     }
1522 }