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: 357871 $, $Date: 2005-12-20 10:56:40 +0900 (Tue, 20 Dec 2005) $
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 if( !buf.hasRemaining() )
1088 {
1089 buf.limit( oldLimit );
1090 buf.position( end );
1091 return "";
1092 }
1093 decoder.reset();
1094
1095 int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ) + 1;
1096 CharBuffer out = CharBuffer.allocate( expectedLength );
1097 for( ;; )
1098 {
1099 CoderResult cr;
1100 if ( buf.hasRemaining() )
1101 {
1102 cr = decoder.decode( buf, out, true );
1103 }
1104 else
1105 {
1106 cr = decoder.flush( out );
1107 }
1108
1109 if ( cr.isUnderflow() )
1110 {
1111 break;
1112 }
1113
1114 if ( cr.isOverflow() )
1115 {
1116 CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1117 out.flip();
1118 o.put(out);
1119 out = o;
1120 continue;
1121 }
1122
1123 cr.throwException();
1124 }
1125
1126 buf.limit( oldLimit );
1127 buf.position( end );
1128 return out.flip().toString();
1129 }
1130
1131 public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException
1132 {
1133 checkFieldSize( fieldSize );
1134
1135 if( fieldSize == 0 )
1136 {
1137 return "";
1138 }
1139
1140 if( !buf.hasRemaining() )
1141 {
1142 return "";
1143 }
1144
1145 boolean utf16 = decoder.charset().name().startsWith( "UTF-16" );
1146
1147 if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1148 {
1149 throw new IllegalArgumentException( "fieldSize is not even." );
1150 }
1151
1152 int i;
1153 int oldPos = buf.position();
1154 int oldLimit = buf.limit();
1155 int end = buf.position() + fieldSize;
1156
1157 if( oldLimit < end )
1158 {
1159 throw new BufferUnderflowException();
1160 }
1161
1162 if( !utf16 )
1163 {
1164 for( i = 0; i < fieldSize; i ++ )
1165 {
1166 if( buf.get() == 0 )
1167 {
1168 break;
1169 }
1170 }
1171
1172 if( i == fieldSize )
1173 {
1174 buf.limit( end );
1175 }
1176 else
1177 {
1178 buf.limit( buf.position() - 1 );
1179 }
1180 }
1181 else
1182 {
1183 for( i = 0; i < fieldSize; i += 2 )
1184 {
1185 if( ( buf.get() == 0 ) && ( buf.get() == 0 ) )
1186 {
1187 break;
1188 }
1189 }
1190
1191 if( i == fieldSize )
1192 {
1193 buf.limit( end );
1194 }
1195 else
1196 {
1197 buf.limit( buf.position() - 2 );
1198 }
1199 }
1200
1201 buf.position( oldPos );
1202 if( !buf.hasRemaining() )
1203 {
1204 buf.limit( oldLimit );
1205 buf.position( end );
1206 return "";
1207 }
1208 decoder.reset();
1209
1210 int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ) + 1;
1211 CharBuffer out = CharBuffer.allocate( expectedLength );
1212 for( ;; )
1213 {
1214 CoderResult cr;
1215 if ( buf.hasRemaining() )
1216 {
1217 cr = decoder.decode( buf, out, true );
1218 }
1219 else
1220 {
1221 cr = decoder.flush( out );
1222 }
1223
1224 if ( cr.isUnderflow() )
1225 {
1226 break;
1227 }
1228
1229 if ( cr.isOverflow() )
1230 {
1231 CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength );
1232 out.flip();
1233 o.put(out);
1234 out = o;
1235 continue;
1236 }
1237
1238 cr.throwException();
1239 }
1240
1241 buf.limit( oldLimit );
1242 buf.position( end );
1243 return out.flip().toString();
1244 }
1245
1246 public ByteBuffer putString(
1247 CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException
1248 {
1249 checkFieldSize( fieldSize );
1250
1251 if( fieldSize == 0 )
1252 return this;
1253
1254 autoExpand( fieldSize );
1255
1256 boolean utf16 = encoder.charset().name().startsWith( "UTF-16" );
1257
1258 if( utf16 && ( ( fieldSize & 1 ) != 0 ) )
1259 {
1260 throw new IllegalArgumentException( "fieldSize is not even." );
1261 }
1262
1263 int oldLimit = buf.limit();
1264 int end = buf.position() + fieldSize;
1265
1266 if( oldLimit < end )
1267 {
1268 throw new BufferOverflowException();
1269 }
1270
1271 if( val.length() == 0 )
1272 {
1273 if( !utf16 )
1274 {
1275 buf.put( ( byte ) 0x00 );
1276 }
1277 else
1278 {
1279 buf.put( ( byte ) 0x00 );
1280 buf.put( ( byte ) 0x00 );
1281 }
1282 buf.position( end );
1283 return this;
1284 }
1285
1286 CharBuffer in = CharBuffer.wrap( val );
1287 buf.limit( end );
1288 encoder.reset();
1289
1290 for (;;) {
1291 CoderResult cr;
1292 if( in.hasRemaining() )
1293 {
1294 cr = encoder.encode( in, buf(), true );
1295 }
1296 else
1297 {
1298 cr = encoder.flush( buf() );
1299 }
1300
1301 if( cr.isUnderflow() || cr.isOverflow() )
1302 {
1303 break;
1304 }
1305 cr.throwException();
1306 }
1307
1308 buf.limit( oldLimit );
1309
1310 if( buf.position() < end )
1311 {
1312 if( !utf16 )
1313 {
1314 buf.put( ( byte ) 0x00 );
1315 }
1316 else
1317 {
1318 buf.put( ( byte ) 0x00 );
1319 buf.put( ( byte ) 0x00 );
1320 }
1321 }
1322
1323 buf.position( end );
1324 return this;
1325 }
1326
1327 public ByteBuffer putString(
1328 CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException
1329 {
1330 if( val.length() == 0 )
1331 {
1332 return this;
1333 }
1334
1335 CharBuffer in = CharBuffer.wrap( val );
1336 int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()) + 1;
1337
1338 encoder.reset();
1339
1340 for (;;) {
1341 CoderResult cr;
1342 if( in.hasRemaining() )
1343 {
1344 cr = encoder.encode( in, buf(), true );
1345 }
1346 else
1347 {
1348 cr = encoder.flush( buf() );
1349 }
1350
1351 if( cr.isUnderflow() )
1352 {
1353 break;
1354 }
1355 if( cr.isOverflow() && autoExpand )
1356 {
1357 autoExpand( expectedLength );
1358 continue;
1359 }
1360 cr.throwException();
1361 }
1362 return this;
1363 }
1364
1365 public ByteBuffer skip( int size )
1366 {
1367 autoExpand( size );
1368 return position( position() + size );
1369 }
1370
1371 public ByteBuffer fill( byte value, int size )
1372 {
1373 autoExpand( size );
1374 int q = size >>> 3;
1375 int r = size & 7;
1376
1377 if( q > 0 )
1378 {
1379 int intValue = value | ( value << 8 ) | ( value << 16 )
1380 | ( value << 24 );
1381 long longValue = intValue;
1382 longValue <<= 32;
1383 longValue |= intValue;
1384
1385 for( int i = q; i > 0; i -- )
1386 {
1387 buf.putLong( longValue );
1388 }
1389 }
1390
1391 q = r >>> 2;
1392 r = r & 3;
1393
1394 if( q > 0 )
1395 {
1396 int intValue = value | ( value << 8 ) | ( value << 16 )
1397 | ( value << 24 );
1398 buf.putInt( intValue );
1399 }
1400
1401 q = r >> 1;
1402 r = r & 1;
1403
1404 if( q > 0 )
1405 {
1406 short shortValue = ( short ) ( value | ( value << 8 ) );
1407 buf.putShort( shortValue );
1408 }
1409
1410 if( r > 0 )
1411 {
1412 buf.put( value );
1413 }
1414
1415 return this;
1416 }
1417
1418 public ByteBuffer fillAndReset( byte value, int size )
1419 {
1420 autoExpand( size );
1421 int pos = buf.position();
1422 try
1423 {
1424 fill( value, size );
1425 }
1426 finally
1427 {
1428 buf.position( pos );
1429 }
1430 return this;
1431 }
1432
1433 public ByteBuffer fill( int size )
1434 {
1435 autoExpand( size );
1436 int q = size >>> 3;
1437 int r = size & 7;
1438
1439 for( int i = q; i > 0; i -- )
1440 {
1441 buf.putLong( 0L );
1442 }
1443
1444 q = r >>> 2;
1445 r = r & 3;
1446
1447 if( q > 0 )
1448 {
1449 buf.putInt( 0 );
1450 }
1451
1452 q = r >> 1;
1453 r = r & 1;
1454
1455 if( q > 0 )
1456 {
1457 buf.putShort( ( short ) 0 );
1458 }
1459
1460 if( r > 0 )
1461 {
1462 buf.put( ( byte ) 0 );
1463 }
1464
1465 return this;
1466 }
1467
1468 public ByteBuffer fillAndReset( int size )
1469 {
1470 autoExpand( size );
1471 int pos = buf.position();
1472 try
1473 {
1474 fill( size );
1475 }
1476 finally
1477 {
1478 buf.position( pos );
1479 }
1480
1481 return this;
1482 }
1483
1484 private void autoExpand( int delta )
1485 {
1486 if( autoExpand )
1487 {
1488 int pos = buf.position();
1489 int limit = buf.limit();
1490 int end = pos + delta;
1491 if( end > limit ) {
1492 ensureCapacity( end );
1493 buf.limit( end );
1494 }
1495 }
1496 }
1497
1498 private void autoExpand( int pos, int delta )
1499 {
1500 if( autoExpand )
1501 {
1502 int limit = buf.limit();
1503 int end = pos + delta;
1504 if( end > limit ) {
1505 ensureCapacity( end );
1506 buf.limit( end );
1507 }
1508 }
1509 }
1510
1511 private void ensureCapacity( int requestedCapacity )
1512 {
1513 if( requestedCapacity <= buf.capacity() )
1514 {
1515 return;
1516 }
1517
1518 int newCapacity = MINIMUM_CAPACITY;
1519 while( newCapacity < requestedCapacity )
1520 {
1521 newCapacity <<= 1;
1522 }
1523
1524 java.nio.ByteBuffer oldBuf = this.buf;
1525 java.nio.ByteBuffer newBuf = allocate0( newCapacity, isDirect() );
1526 newBuf.clear();
1527 newBuf.order( oldBuf.order() );
1528
1529 int pos = oldBuf.position();
1530 int limit = oldBuf.limit();
1531 oldBuf.clear();
1532 newBuf.put( oldBuf );
1533 newBuf.position( 0 );
1534 newBuf.limit( limit );
1535 newBuf.position( pos );
1536 this.buf = newBuf;
1537 release0( oldBuf );
1538 }
1539
1540 private static void checkFieldSize( int fieldSize )
1541 {
1542 if( fieldSize < 0 )
1543 {
1544 throw new IllegalArgumentException(
1545 "fieldSize cannot be negative: " + fieldSize );
1546 }
1547 }
1548
1549 }
1550 }