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