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