View Javadoc

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