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: 210062 $, $Date: 2005-07-11 12:52:38 +0900 $
142 */
143 public abstract class ByteBuffer
144 {
145 private static final int MINIMUM_CAPACITY = 1;
146
147 private static final Stack containerStack = new Stack();
148
149 private static final Stack[] heapBufferStacks = new Stack[] {
150 new Stack(), new Stack(), new Stack(), new Stack(),
151 new Stack(), new Stack(), new Stack(), new Stack(),
152 new Stack(), new Stack(), new Stack(), new Stack(),
153 new Stack(), new Stack(), new Stack(), new Stack(),
154 new Stack(), new Stack(), new Stack(), new Stack(),
155 new Stack(), new Stack(), new Stack(), new Stack(),
156 new Stack(), new Stack(), new Stack(), new Stack(),
157 new Stack(), new Stack(), new Stack(), new Stack(), };
158
159 private static final Stack[] directBufferStacks = new Stack[] {
160 new Stack(), new Stack(), new Stack(), new Stack(),
161 new Stack(), new Stack(), new Stack(), new Stack(),
162 new Stack(), new Stack(), new Stack(), new Stack(),
163 new Stack(), new Stack(), new Stack(), new Stack(),
164 new Stack(), new Stack(), new Stack(), new Stack(),
165 new Stack(), new Stack(), new Stack(), new Stack(),
166 new Stack(), new Stack(), new Stack(), new Stack(),
167 new Stack(), new Stack(), new Stack(), new Stack(), };
168
169 /***
170 * Returns the direct or heap buffer which is capable of the specified
171 * size. This method tries to allocate direct buffer first, and then
172 * tries heap buffer if direct buffer memory is exhausted. Please use
173 * {@link #allocate(int, boolean)} to allocate buffers of specific type.
174 *
175 * @param capacity the capacity of the buffer
176 */
177 public static ByteBuffer allocate( int capacity )
178 {
179 try
180 {
181
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 if( !buf.hasRemaining() )
1019 {
1020 return "";
1021 }
1022
1023 boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
1024
1025 int oldPos = buf.position();
1026 int oldLimit = buf.limit();
1027 int end;
1028
1029 if( !utf16 )
1030 {
1031 while( buf.hasRemaining() )
1032 {
1033 if( buf.get() == 0 )
1034 {
1035 break;
1036 }
1037 }
1038
1039 end = buf.position();
1040 if( end == oldLimit )
1041 {
1042 buf.limit( end );
1043 }
1044 else
1045 {
1046 buf.limit( end - 1 );
1047 }
1048 }
1049 else
1050 {
1051 while( buf.remaining() >= 2 )
1052 {
1053 if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
1054 {
1055 break;
1056 }
1057 }
1058
1059 end = buf.position();
1060 if( end == oldLimit || end == oldLimit - 1 )
1061 {
1062 buf.limit( end );
1063 }
1064 else
1065 {
1066 buf.limit( end - 2 );
1067 }
1068 }
1069
1070 buf.position( oldPos );
1071 decoder.reset();
1072
1073 int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
1074 CharBuffer out = CharBuffer.allocate( expectedLength );
1075 for( ;; )
1076 {
1077 CoderResult cr;
1078 if ( buf.hasRemaining() )
1079 {
1080 cr = decoder.decode( buf, out, true );
1081 }
1082 else
1083 {
1084 cr = decoder.flush( out );
1085 }
1086
1087 if ( cr.isUnderflow() )
1088 {
1089 break;
1090 }
1091
1092 if ( cr.isOverflow() )
1093 {
1094 CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1095 out.flip();
1096 o.put(out);
1097 out = o;
1098 continue;
1099 }
1100
1101 cr.throwException();
1102 }
1103
1104 buf.limit( oldLimit );
1105 buf.position( end );
1106 return out.flip().toString();
1107 }
1108
1109 public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException
1110 {
1111 checkFieldSize( fieldSize );
1112
1113 if( fieldSize == 0 )
1114 {
1115 return "";
1116 }
1117
1118 if( !buf.hasRemaining() )
1119 {
1120 return "";
1121 }
1122
1123 boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
1124
1125 if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1126 {
1127 throw new IllegalArgumentException( "fieldSize is not even." );
1128 }
1129
1130 int i;
1131 int oldPos = buf.position();
1132 int oldLimit = buf.limit();
1133 int end = buf.position() + fieldSize;
1134
1135 if( oldLimit < end )
1136 {
1137 throw new BufferUnderflowException();
1138 }
1139
1140 if( !utf16 )
1141 {
1142 for( i = 0; i < fieldSize; i ++ )
1143 {
1144 if( buf.get() == 0 )
1145 {
1146 break;
1147 }
1148 }
1149
1150 if( i == fieldSize )
1151 {
1152 buf.limit( end );
1153 }
1154 else
1155 {
1156 buf.limit( buf.position() - 1 );
1157 }
1158 }
1159 else
1160 {
1161 for( i = 0; i < fieldSize; i += 2 )
1162 {
1163 if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
1164 {
1165 break;
1166 }
1167 }
1168
1169 if( i == fieldSize )
1170 {
1171 buf.limit( end );
1172 }
1173 else
1174 {
1175 buf.limit( buf.position() - 2 );
1176 }
1177 }
1178
1179 buf.position( oldPos );
1180 decoder.reset();
1181
1182 int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() );
1183 CharBuffer out = CharBuffer.allocate( expectedLength );
1184 for( ;; )
1185 {
1186 CoderResult cr;
1187 if ( buf.hasRemaining() )
1188 {
1189 cr = decoder.decode( buf, out, true );
1190 }
1191 else
1192 {
1193 cr = decoder.flush( out );
1194 }
1195
1196 if ( cr.isUnderflow() )
1197 {
1198 break;
1199 }
1200
1201 if ( cr.isOverflow() )
1202 {
1203 CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1204 out.flip();
1205 o.put(out);
1206 out = o;
1207 continue;
1208 }
1209
1210 cr.throwException();
1211 }
1212
1213 buf.limit( oldLimit );
1214 buf.position( end );
1215 return out.flip().toString();
1216 }
1217
1218 public ByteBuffer putString(
1219 CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException
1220 {
1221 checkFieldSize( fieldSize );
1222
1223 if( fieldSize == 0 )
1224 return this;
1225
1226 autoExpand( fieldSize );
1227
1228 boolean utf16 = encoder.charset().name().startsWith( "UTF-16" );
1229
1230 if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1231 {
1232 throw new IllegalArgumentException( "fieldSize is not even." );
1233 }
1234
1235 int oldLimit = buf.limit();
1236 int end = buf.position() + fieldSize;
1237
1238 if( oldLimit < end )
1239 {
1240 throw new BufferOverflowException();
1241 }
1242
1243 if( val.length() == 0 )
1244 {
1245 if( !utf16 )
1246 {
1247 buf.put( ( byte ) 0x00 );
1248 }
1249 else
1250 {
1251 buf.put( ( byte ) 0x00 );
1252 buf.put( ( byte ) 0x00 );
1253 }
1254 buf.position( end );
1255 return this;
1256 }
1257
1258 CharBuffer in = CharBuffer.wrap( val );
1259 buf.limit( end );
1260 encoder.reset();
1261
1262 for (;;) {
1263 CoderResult cr;
1264 if( in.hasRemaining() )
1265 {
1266 cr = encoder.encode( in, buf(), true );
1267 }
1268 else
1269 {
1270 cr = encoder.flush( buf() );
1271 }
1272
1273 if( cr.isUnderflow() || cr.isOverflow() )
1274 {
1275 break;
1276 }
1277 cr.throwException();
1278 }
1279
1280 buf.limit( oldLimit );
1281
1282 if( buf.position() < end )
1283 {
1284 if( !utf16 )
1285 {
1286 buf.put( ( byte ) 0x00 );
1287 }
1288 else
1289 {
1290 buf.put( ( byte ) 0x00 );
1291 buf.put( ( byte ) 0x00 );
1292 }
1293 }
1294
1295 buf.position( end );
1296 return this;
1297 }
1298
1299 public ByteBuffer putString(
1300 CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException
1301 {
1302 if( val.length() == 0 )
1303 {
1304 return this;
1305 }
1306
1307 CharBuffer in = CharBuffer.wrap( val );
1308 int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar());
1309
1310 encoder.reset();
1311
1312 for (;;) {
1313 CoderResult cr;
1314 if( in.hasRemaining() )
1315 {
1316 cr = encoder.encode( in, buf(), true );
1317 }
1318 else
1319 {
1320 cr = encoder.flush( buf() );
1321 }
1322
1323 if( cr.isUnderflow() )
1324 {
1325 break;
1326 }
1327 if( cr.isOverflow() && autoExpand )
1328 {
1329 autoExpand( expectedLength );
1330 continue;
1331 }
1332 cr.throwException();
1333 }
1334 return this;
1335 }
1336
1337 public ByteBuffer skip( int size )
1338 {
1339 autoExpand( size );
1340 return position( position() + size );
1341 }
1342
1343 public ByteBuffer fill( byte value, int size )
1344 {
1345 autoExpand( size );
1346 int q = size >>> 3;
1347 int r = size & 7;
1348
1349 if( q > 0 )
1350 {
1351 int intValue = value | ( value << 8 ) | ( value << 16 )
1352 | ( value << 24 );
1353 long longValue = intValue;
1354 longValue <<= 32;
1355 longValue |= intValue;
1356
1357 for( int i = q; i > 0; i -- )
1358 {
1359 buf.putLong( longValue );
1360 }
1361 }
1362
1363 q = r >>> 2;
1364 r = r & 3;
1365
1366 if( q > 0 )
1367 {
1368 int intValue = value | ( value << 8 ) | ( value << 16 )
1369 | ( value << 24 );
1370 buf.putInt( intValue );
1371 }
1372
1373 q = r >> 1;
1374 r = r & 1;
1375
1376 if( q > 0 )
1377 {
1378 short shortValue = ( short ) ( value | ( value << 8 ) );
1379 buf.putShort( shortValue );
1380 }
1381
1382 if( r > 0 )
1383 {
1384 buf.put( value );
1385 }
1386
1387 return this;
1388 }
1389
1390 public ByteBuffer fillAndReset( byte value, int size )
1391 {
1392 autoExpand( size );
1393 int pos = buf.position();
1394 try
1395 {
1396 fill( value, size );
1397 }
1398 finally
1399 {
1400 buf.position( pos );
1401 }
1402 return this;
1403 }
1404
1405 public ByteBuffer fill( int size )
1406 {
1407 autoExpand( size );
1408 int q = size >>> 3;
1409 int r = size & 7;
1410
1411 for( int i = q; i > 0; i -- )
1412 {
1413 buf.putLong( 0L );
1414 }
1415
1416 q = r >>> 2;
1417 r = r & 3;
1418
1419 if( q > 0 )
1420 {
1421 buf.putInt( 0 );
1422 }
1423
1424 q = r >> 1;
1425 r = r & 1;
1426
1427 if( q > 0 )
1428 {
1429 buf.putShort( ( short ) 0 );
1430 }
1431
1432 if( r > 0 )
1433 {
1434 buf.put( ( byte ) 0 );
1435 }
1436
1437 return this;
1438 }
1439
1440 public ByteBuffer fillAndReset( int size )
1441 {
1442 autoExpand( size );
1443 int pos = buf.position();
1444 try
1445 {
1446 fill( size );
1447 }
1448 finally
1449 {
1450 buf.position( pos );
1451 }
1452
1453 return this;
1454 }
1455
1456 private void autoExpand( int delta )
1457 {
1458 if( autoExpand )
1459 {
1460 int pos = buf.position();
1461 int limit = buf.limit();
1462 int end = pos + delta;
1463 if( end > limit ) {
1464 ensureCapacity( end );
1465 buf.limit( end );
1466 }
1467 }
1468 }
1469
1470 private void autoExpand( int pos, int delta )
1471 {
1472 if( autoExpand )
1473 {
1474 int limit = buf.limit();
1475 int end = pos + delta;
1476 if( end > limit ) {
1477 ensureCapacity( end );
1478 buf.limit( end );
1479 }
1480 }
1481 }
1482
1483 private void ensureCapacity( int requestedCapacity )
1484 {
1485 if( requestedCapacity <= buf.capacity() )
1486 {
1487 return;
1488 }
1489
1490 int newCapacity = MINIMUM_CAPACITY;
1491 while( newCapacity < requestedCapacity )
1492 {
1493 newCapacity <<= 1;
1494 }
1495
1496 java.nio.ByteBuffer oldBuf = this.buf;
1497 java.nio.ByteBuffer newBuf = allocate0( newCapacity, isDirect() );
1498 newBuf.clear();
1499 newBuf.order( oldBuf.order() );
1500
1501 int pos = oldBuf.position();
1502 int limit = oldBuf.limit();
1503 oldBuf.clear();
1504 newBuf.put( oldBuf );
1505 newBuf.position( 0 );
1506 newBuf.limit( limit );
1507 newBuf.position( pos );
1508 this.buf = newBuf;
1509 release0( oldBuf );
1510 }
1511
1512 private static void checkFieldSize( int fieldSize )
1513 {
1514 if( fieldSize < 0 )
1515 {
1516 throw new IllegalArgumentException(
1517 "fieldSize cannot be negative: " + fieldSize );
1518 }
1519 }
1520
1521 }
1522 }