1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
152 return allocate( capacity, true );
153 }
154 catch( OutOfMemoryError e )
155 {
156
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
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
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
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 );
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 }