1 | /* |
2 | * @(#) $Id: ByteBuffer.java 327113 2005-10-21 06:59:15Z trustin $ |
3 | * |
4 | * Copyright 2004 The Apache Software Foundation |
5 | * |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | * you may not use this file except in compliance with the License. |
8 | * You may obtain a copy of the License at |
9 | * |
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * |
12 | * Unless required by applicable law or agreed to in writing, software |
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | * See the License for the specific language governing permissions and |
16 | * limitations under the License. |
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: 327113 $, $Date: 2005-10-21 15:59:15 +0900 $ |
120 | */ |
121 | public abstract class ByteBuffer |
122 | { |
123 | private static final int MINIMUM_CAPACITY = 1; |
124 | |
125 | private static final Stack containerStack = new Stack(); |
126 | |
127 | private static final Stack[] heapBufferStacks = new Stack[] { |
128 | new Stack(), new Stack(), new Stack(), new Stack(), |
129 | new Stack(), new Stack(), new Stack(), new Stack(), |
130 | new Stack(), new Stack(), new Stack(), new Stack(), |
131 | new Stack(), new Stack(), new Stack(), new Stack(), |
132 | new Stack(), new Stack(), new Stack(), new Stack(), |
133 | new Stack(), new Stack(), new Stack(), new Stack(), |
134 | new Stack(), new Stack(), new Stack(), new Stack(), |
135 | new Stack(), new Stack(), new Stack(), new Stack(), }; |
136 | |
137 | private static final Stack[] directBufferStacks = new Stack[] { |
138 | new Stack(), new Stack(), new Stack(), new Stack(), |
139 | new Stack(), new Stack(), new Stack(), new Stack(), |
140 | new Stack(), new Stack(), new Stack(), new Stack(), |
141 | new Stack(), new Stack(), new Stack(), new Stack(), |
142 | new Stack(), new Stack(), new Stack(), new Stack(), |
143 | new Stack(), new Stack(), new Stack(), new Stack(), |
144 | new Stack(), new Stack(), new Stack(), new Stack(), |
145 | new Stack(), new Stack(), new Stack(), new Stack(), }; |
146 | |
147 | /** |
148 | * Returns the direct or heap buffer which is capable of the specified |
149 | * size. This method tries to allocate direct buffer first, and then |
150 | * tries heap buffer if direct buffer memory is exhausted. Please use |
151 | * {@link #allocate(int, boolean)} to allocate buffers of specific type. |
152 | * |
153 | * @param capacity the capacity of the buffer |
154 | */ |
155 | public static ByteBuffer allocate( int capacity ) |
156 | { |
157 | try |
158 | { |
159 | // first try to allocate direct buffer |
160 | return allocate( capacity, true ); |
161 | } |
162 | catch( OutOfMemoryError e ) |
163 | { |
164 | // if failed, try heap |
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 | // push back |
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 | // String getters and putters // |
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 | // Skip or fill methods // |
523 | ////////////////////////// |
524 | |
525 | /** |
526 | * Forwards the position of this buffer as the specified <code>size</code> |
527 | * bytes. |
528 | */ |
529 | public abstract ByteBuffer skip( int size ); |
530 | |
531 | /** |
532 | * Fills this buffer with the specified value. |
533 | * This method moves buffer position forward. |
534 | */ |
535 | public abstract ByteBuffer fill( byte value, int size ); |
536 | |
537 | /** |
538 | * Fills this buffer with the specified value. |
539 | * This method does not change buffer position. |
540 | */ |
541 | public abstract ByteBuffer fillAndReset( byte value, int size ); |
542 | |
543 | /** |
544 | * Fills this buffer with <code>NUL (0x00)</code>. |
545 | * This method moves buffer position forward. |
546 | */ |
547 | public abstract ByteBuffer fill( int size ); |
548 | |
549 | /** |
550 | * Fills this buffer with <code>NUL (0x00)</code>. |
551 | * This method does not change buffer position. |
552 | */ |
553 | public abstract ByteBuffer fillAndReset( int size ); |
554 | |
555 | private static class DefaultByteBuffer extends ByteBuffer |
556 | { |
557 | private java.nio.ByteBuffer buf; |
558 | private int refCount = 1; |
559 | private boolean autoExpand; |
560 | private boolean pooled; |
561 | |
562 | protected DefaultByteBuffer() |
563 | { |
564 | } |
565 | |
566 | private synchronized void init( java.nio.ByteBuffer buf ) |
567 | { |
568 | this.buf = buf; |
569 | autoExpand = false; |
570 | pooled = true; |
571 | refCount = 1; |
572 | } |
573 | |
574 | public synchronized void acquire() |
575 | { |
576 | if( refCount <= 0 ) |
577 | { |
578 | throw new IllegalStateException( "Already released buffer." ); |
579 | } |
580 | |
581 | refCount ++; |
582 | } |
583 | |
584 | public void release() |
585 | { |
586 | synchronized( this ) |
587 | { |
588 | if( refCount <= 0 ) |
589 | { |
590 | refCount = 0; |
591 | throw new IllegalStateException( |
592 | "Already released buffer. You released the buffer too many times." ); |
593 | } |
594 | |
595 | refCount --; |
596 | if( refCount > 0) |
597 | { |
598 | return; |
599 | } |
600 | } |
601 | |
602 | if( pooled ) |
603 | { |
604 | release0( buf ); |
605 | } |
606 | |
607 | synchronized( containerStack ) |
608 | { |
609 | containerStack.push( this ); |
610 | } |
611 | } |
612 | |
613 | public java.nio.ByteBuffer buf() |
614 | { |
615 | return buf; |
616 | } |
617 | |
618 | public boolean isDirect() |
619 | { |
620 | return buf.isDirect(); |
621 | } |
622 | |
623 | public boolean isReadOnly() |
624 | { |
625 | return buf.isReadOnly(); |
626 | } |
627 | |
628 | public boolean isAutoExpand() |
629 | { |
630 | return autoExpand; |
631 | } |
632 | |
633 | public ByteBuffer setAutoExpand( boolean autoExpand ) |
634 | { |
635 | this.autoExpand = autoExpand; |
636 | return this; |
637 | } |
638 | |
639 | public boolean isPooled() |
640 | { |
641 | return pooled; |
642 | } |
643 | |
644 | public void setPooled( boolean pooled ) |
645 | { |
646 | this.pooled = pooled; |
647 | } |
648 | |
649 | public int capacity() |
650 | { |
651 | return buf.capacity(); |
652 | } |
653 | |
654 | public int position() |
655 | { |
656 | return buf.position(); |
657 | } |
658 | |
659 | public ByteBuffer position( int newPosition ) |
660 | { |
661 | autoExpand( newPosition, 0 ); |
662 | buf.position( newPosition ); |
663 | return this; |
664 | } |
665 | |
666 | public int limit() |
667 | { |
668 | return buf.limit(); |
669 | } |
670 | |
671 | public ByteBuffer limit( int newLimit ) |
672 | { |
673 | autoExpand( newLimit, 0 ); |
674 | buf.limit( newLimit ); |
675 | return this; |
676 | } |
677 | |
678 | public ByteBuffer mark() |
679 | { |
680 | buf.mark(); |
681 | return this; |
682 | } |
683 | |
684 | public ByteBuffer reset() |
685 | { |
686 | buf.reset(); |
687 | return this; |
688 | } |
689 | |
690 | public ByteBuffer clear() |
691 | { |
692 | buf.clear(); |
693 | return this; |
694 | } |
695 | |
696 | public ByteBuffer flip() |
697 | { |
698 | buf.flip(); |
699 | return this; |
700 | } |
701 | |
702 | public ByteBuffer rewind() |
703 | { |
704 | buf.rewind(); |
705 | return this; |
706 | } |
707 | |
708 | public int remaining() |
709 | { |
710 | return buf.remaining(); |
711 | } |
712 | |
713 | public boolean hasRemaining() |
714 | { |
715 | return buf.hasRemaining(); |
716 | } |
717 | |
718 | public byte get() |
719 | { |
720 | return buf.get(); |
721 | } |
722 | |
723 | public short getUnsigned() |
724 | { |
725 | return ( short ) ( get() & 0xff ); |
726 | } |
727 | |
728 | public ByteBuffer put( byte b ) |
729 | { |
730 | autoExpand( 1 ); |
731 | buf.put( b ); |
732 | return this; |
733 | } |
734 | |
735 | public byte get( int index ) |
736 | { |
737 | return buf.get( index ); |
738 | } |
739 | |
740 | public short getUnsigned( int index ) |
741 | { |
742 | return ( short ) ( get( index ) & 0xff ); |
743 | } |
744 | |
745 | public ByteBuffer put( int index, byte b ) |
746 | { |
747 | autoExpand( index, 1 ); |
748 | buf.put( index, b ); |
749 | return this; |
750 | } |
751 | |
752 | public ByteBuffer get( byte[] dst, int offset, int length ) |
753 | { |
754 | buf.get( dst, offset, length ); |
755 | return this; |
756 | } |
757 | |
758 | public ByteBuffer get( byte[] dst ) |
759 | { |
760 | buf.get( dst ); |
761 | return this; |
762 | } |
763 | |
764 | public ByteBuffer put( java.nio.ByteBuffer src ) |
765 | { |
766 | autoExpand( src.remaining() ); |
767 | buf.put( src ); |
768 | return this; |
769 | } |
770 | |
771 | public ByteBuffer put( ByteBuffer src ) |
772 | { |
773 | autoExpand( src.remaining() ); |
774 | buf.put( src.buf() ); |
775 | return this; |
776 | } |
777 | |
778 | public ByteBuffer put( byte[] src, int offset, int length ) |
779 | { |
780 | autoExpand( length ); |
781 | buf.put( src, offset, length ); |
782 | return this; |
783 | } |
784 | |
785 | public ByteBuffer put( byte[] src ) |
786 | { |
787 | autoExpand( src.length ); |
788 | buf.put( src ); |
789 | return this; |
790 | } |
791 | |
792 | public ByteBuffer compact() |
793 | { |
794 | buf.compact(); |
795 | return this; |
796 | } |
797 | |
798 | public String toString() |
799 | { |
800 | return buf.toString(); |
801 | } |
802 | |
803 | public int hashCode() |
804 | { |
805 | return buf.hashCode(); |
806 | } |
807 | |
808 | public boolean equals( Object ob ) |
809 | { |
810 | if( !( ob instanceof ByteBuffer ) ) |
811 | return false; |
812 | |
813 | ByteBuffer that = ( ByteBuffer ) ob; |
814 | return this.buf.equals( that.buf() ); |
815 | } |
816 | |
817 | public int compareTo( ByteBuffer that ) |
818 | { |
819 | return this.buf.compareTo( that.buf() ); |
820 | } |
821 | |
822 | public ByteOrder order() |
823 | { |
824 | return buf.order(); |
825 | } |
826 | |
827 | public ByteBuffer order( ByteOrder bo ) |
828 | { |
829 | buf.order( bo ); |
830 | return this; |
831 | } |
832 | |
833 | public char getChar() |
834 | { |
835 | return buf.getChar(); |
836 | } |
837 | |
838 | public ByteBuffer putChar( char value ) |
839 | { |
840 | autoExpand( 2 ); |
841 | buf.putChar( value ); |
842 | return this; |
843 | } |
844 | |
845 | public char getChar( int index ) |
846 | { |
847 | return buf.getChar( index ); |
848 | } |
849 | |
850 | public ByteBuffer putChar( int index, char value ) |
851 | { |
852 | autoExpand( index, 2 ); |
853 | buf.putChar( index, value ); |
854 | return this; |
855 | } |
856 | |
857 | public CharBuffer asCharBuffer() |
858 | { |
859 | return buf.asCharBuffer(); |
860 | } |
861 | |
862 | public short getShort() |
863 | { |
864 | return buf.getShort(); |
865 | } |
866 | |
867 | public int getUnsignedShort() |
868 | { |
869 | return getShort() & 0xffff; |
870 | } |
871 | |
872 | public ByteBuffer putShort( short value ) |
873 | { |
874 | autoExpand( 2 ); |
875 | buf.putShort( value ); |
876 | return this; |
877 | } |
878 | |
879 | public short getShort( int index ) |
880 | { |
881 | return buf.getShort( index ); |
882 | } |
883 | |
884 | public int getUnsignedShort( int index ) |
885 | { |
886 | return getShort( index ) & 0xffff; |
887 | } |
888 | |
889 | public ByteBuffer putShort( int index, short value ) |
890 | { |
891 | autoExpand( index, 2 ); |
892 | buf.putShort( index, value ); |
893 | return this; |
894 | } |
895 | |
896 | public ShortBuffer asShortBuffer() |
897 | { |
898 | return buf.asShortBuffer(); |
899 | } |
900 | |
901 | public int getInt() |
902 | { |
903 | return buf.getInt(); |
904 | } |
905 | |
906 | public long getUnsignedInt() |
907 | { |
908 | return getInt() & 0xffffffffL; |
909 | } |
910 | |
911 | public ByteBuffer putInt( int value ) |
912 | { |
913 | autoExpand( 4 ); |
914 | buf.putInt( value ); |
915 | return this; |
916 | } |
917 | |
918 | public int getInt( int index ) |
919 | { |
920 | return buf.getInt( index ); |
921 | } |
922 | |
923 | public long getUnsignedInt( int index ) |
924 | { |
925 | return getInt( index ) & 0xffffffffL; |
926 | } |
927 | |
928 | public ByteBuffer putInt( int index, int value ) |
929 | { |
930 | autoExpand( index, 4 ); |
931 | buf.putInt( index, value ); |
932 | return this; |
933 | } |
934 | |
935 | public IntBuffer asIntBuffer() |
936 | { |
937 | return buf.asIntBuffer(); |
938 | } |
939 | |
940 | public long getLong() |
941 | { |
942 | return buf.getLong(); |
943 | } |
944 | |
945 | public ByteBuffer putLong( long value ) |
946 | { |
947 | autoExpand( 8 ); |
948 | buf.putLong( value ); |
949 | return this; |
950 | } |
951 | |
952 | public long getLong( int index ) |
953 | { |
954 | return buf.getLong( index ); |
955 | } |
956 | |
957 | public ByteBuffer putLong( int index, long value ) |
958 | { |
959 | autoExpand( index, 8 ); |
960 | buf.putLong( index, value ); |
961 | return this; |
962 | } |
963 | |
964 | public LongBuffer asLongBuffer() |
965 | { |
966 | return buf.asLongBuffer(); |
967 | } |
968 | |
969 | public float getFloat() |
970 | { |
971 | return buf.getFloat(); |
972 | } |
973 | |
974 | public ByteBuffer putFloat( float value ) |
975 | { |
976 | autoExpand( 4 ); |
977 | buf.putFloat( value ); |
978 | return this; |
979 | } |
980 | |
981 | public float getFloat( int index ) |
982 | { |
983 | return buf.getFloat( index ); |
984 | } |
985 | |
986 | public ByteBuffer putFloat( int index, float value ) |
987 | { |
988 | autoExpand( index, 4 ); |
989 | buf.putFloat( index, value ); |
990 | return this; |
991 | } |
992 | |
993 | public FloatBuffer asFloatBuffer() |
994 | { |
995 | return buf.asFloatBuffer(); |
996 | } |
997 | |
998 | public double getDouble() |
999 | { |
1000 | return buf.getDouble(); |
1001 | } |
1002 | |
1003 | public ByteBuffer putDouble( double value ) |
1004 | { |
1005 | autoExpand( 8 ); |
1006 | buf.putDouble( value ); |
1007 | return this; |
1008 | } |
1009 | |
1010 | public double getDouble( int index ) |
1011 | { |
1012 | return buf.getDouble( index ); |
1013 | } |
1014 | |
1015 | public ByteBuffer putDouble( int index, double value ) |
1016 | { |
1017 | autoExpand( index, 8 ); |
1018 | buf.putDouble( index, value ); |
1019 | return this; |
1020 | } |
1021 | |
1022 | public DoubleBuffer asDoubleBuffer() |
1023 | { |
1024 | return buf.asDoubleBuffer(); |
1025 | } |
1026 | |
1027 | public String getHexDump() |
1028 | { |
1029 | return ByteBufferHexDumper.getHexdump( this ); |
1030 | } |
1031 | |
1032 | public String getString( CharsetDecoder decoder ) throws CharacterCodingException |
1033 | { |
1034 | if( !buf.hasRemaining() ) |
1035 | { |
1036 | return ""; |
1037 | } |
1038 | |
1039 | boolean utf16 = decoder.charset().name().startsWith( "UTF-16" ); |
1040 | |
1041 | int oldPos = buf.position(); |
1042 | int oldLimit = buf.limit(); |
1043 | int end; |
1044 | |
1045 | if( !utf16 ) |
1046 | { |
1047 | while( buf.hasRemaining() ) |
1048 | { |
1049 | if( buf.get() == 0 ) |
1050 | { |
1051 | break; |
1052 | } |
1053 | } |
1054 | |
1055 | end = buf.position(); |
1056 | if( end == oldLimit ) |
1057 | { |
1058 | buf.limit( end ); |
1059 | } |
1060 | else |
1061 | { |
1062 | buf.limit( end - 1 ); |
1063 | } |
1064 | } |
1065 | else |
1066 | { |
1067 | while( buf.remaining() >= 2 ) |
1068 | { |
1069 | if( ( buf.get() == 0 ) && ( buf.get() == 0 ) ) |
1070 | { |
1071 | break; |
1072 | } |
1073 | } |
1074 | |
1075 | end = buf.position(); |
1076 | if( end == oldLimit || end == oldLimit - 1 ) |
1077 | { |
1078 | buf.limit( end ); |
1079 | } |
1080 | else |
1081 | { |
1082 | buf.limit( end - 2 ); |
1083 | } |
1084 | } |
1085 | |
1086 | buf.position( oldPos ); |
1087 | decoder.reset(); |
1088 | |
1089 | int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ); |
1090 | CharBuffer out = CharBuffer.allocate( expectedLength ); |
1091 | for( ;; ) |
1092 | { |
1093 | CoderResult cr; |
1094 | if ( buf.hasRemaining() ) |
1095 | { |
1096 | cr = decoder.decode( buf, out, true ); |
1097 | } |
1098 | else |
1099 | { |
1100 | cr = decoder.flush( out ); |
1101 | } |
1102 | |
1103 | if ( cr.isUnderflow() ) |
1104 | { |
1105 | break; |
1106 | } |
1107 | |
1108 | if ( cr.isOverflow() ) |
1109 | { |
1110 | CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); |
1111 | out.flip(); |
1112 | o.put(out); |
1113 | out = o; |
1114 | continue; |
1115 | } |
1116 | |
1117 | cr.throwException(); |
1118 | } |
1119 | |
1120 | buf.limit( oldLimit ); |
1121 | buf.position( end ); |
1122 | return out.flip().toString(); |
1123 | } |
1124 | |
1125 | public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException |
1126 | { |
1127 | checkFieldSize( fieldSize ); |
1128 | |
1129 | if( fieldSize == 0 ) |
1130 | { |
1131 | return ""; |
1132 | } |
1133 | |
1134 | if( !buf.hasRemaining() ) |
1135 | { |
1136 | return ""; |
1137 | } |
1138 | |
1139 | boolean utf16 = decoder.charset().name().startsWith( "UTF-16" ); |
1140 | |
1141 | if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) |
1142 | { |
1143 | throw new IllegalArgumentException( "fieldSize is not even." ); |
1144 | } |
1145 | |
1146 | int i; |
1147 | int oldPos = buf.position(); |
1148 | int oldLimit = buf.limit(); |
1149 | int end = buf.position() + fieldSize; |
1150 | |
1151 | if( oldLimit < end ) |
1152 | { |
1153 | throw new BufferUnderflowException(); |
1154 | } |
1155 | |
1156 | if( !utf16 ) |
1157 | { |
1158 | for( i = 0; i < fieldSize; i ++ ) |
1159 | { |
1160 | if( buf.get() == 0 ) |
1161 | { |
1162 | break; |
1163 | } |
1164 | } |
1165 | |
1166 | if( i == fieldSize ) |
1167 | { |
1168 | buf.limit( end ); |
1169 | } |
1170 | else |
1171 | { |
1172 | buf.limit( buf.position() - 1 ); |
1173 | } |
1174 | } |
1175 | else |
1176 | { |
1177 | for( i = 0; i < fieldSize; i += 2 ) |
1178 | { |
1179 | if( ( buf.get() == 0 ) && ( buf.get() == 0 ) ) |
1180 | { |
1181 | break; |
1182 | } |
1183 | } |
1184 | |
1185 | if( i == fieldSize ) |
1186 | { |
1187 | buf.limit( end ); |
1188 | } |
1189 | else |
1190 | { |
1191 | buf.limit( buf.position() - 2 ); |
1192 | } |
1193 | } |
1194 | |
1195 | buf.position( oldPos ); |
1196 | decoder.reset(); |
1197 | |
1198 | int expectedLength = (int) ( buf.remaining() * decoder.averageCharsPerByte() ); |
1199 | CharBuffer out = CharBuffer.allocate( expectedLength ); |
1200 | for( ;; ) |
1201 | { |
1202 | CoderResult cr; |
1203 | if ( buf.hasRemaining() ) |
1204 | { |
1205 | cr = decoder.decode( buf, out, true ); |
1206 | } |
1207 | else |
1208 | { |
1209 | cr = decoder.flush( out ); |
1210 | } |
1211 | |
1212 | if ( cr.isUnderflow() ) |
1213 | { |
1214 | break; |
1215 | } |
1216 | |
1217 | if ( cr.isOverflow() ) |
1218 | { |
1219 | CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); |
1220 | out.flip(); |
1221 | o.put(out); |
1222 | out = o; |
1223 | continue; |
1224 | } |
1225 | |
1226 | cr.throwException(); |
1227 | } |
1228 | |
1229 | buf.limit( oldLimit ); |
1230 | buf.position( end ); |
1231 | return out.flip().toString(); |
1232 | } |
1233 | |
1234 | public ByteBuffer putString( |
1235 | CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException |
1236 | { |
1237 | checkFieldSize( fieldSize ); |
1238 | |
1239 | if( fieldSize == 0 ) |
1240 | return this; |
1241 | |
1242 | autoExpand( fieldSize ); |
1243 | |
1244 | boolean utf16 = encoder.charset().name().startsWith( "UTF-16" ); |
1245 | |
1246 | if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) |
1247 | { |
1248 | throw new IllegalArgumentException( "fieldSize is not even." ); |
1249 | } |
1250 | |
1251 | int oldLimit = buf.limit(); |
1252 | int end = buf.position() + fieldSize; |
1253 | |
1254 | if( oldLimit < end ) |
1255 | { |
1256 | throw new BufferOverflowException(); |
1257 | } |
1258 | |
1259 | if( val.length() == 0 ) |
1260 | { |
1261 | if( !utf16 ) |
1262 | { |
1263 | buf.put( ( byte ) 0x00 ); |
1264 | } |
1265 | else |
1266 | { |
1267 | buf.put( ( byte ) 0x00 ); |
1268 | buf.put( ( byte ) 0x00 ); |
1269 | } |
1270 | buf.position( end ); |
1271 | return this; |
1272 | } |
1273 | |
1274 | CharBuffer in = CharBuffer.wrap( val ); |
1275 | buf.limit( end ); |
1276 | encoder.reset(); |
1277 | |
1278 | for (;;) { |
1279 | CoderResult cr; |
1280 | if( in.hasRemaining() ) |
1281 | { |
1282 | cr = encoder.encode( in, buf(), true ); |
1283 | } |
1284 | else |
1285 | { |
1286 | cr = encoder.flush( buf() ); |
1287 | } |
1288 | |
1289 | if( cr.isUnderflow() || cr.isOverflow() ) |
1290 | { |
1291 | break; |
1292 | } |
1293 | cr.throwException(); |
1294 | } |
1295 | |
1296 | buf.limit( oldLimit ); |
1297 | |
1298 | if( buf.position() < end ) |
1299 | { |
1300 | if( !utf16 ) |
1301 | { |
1302 | buf.put( ( byte ) 0x00 ); |
1303 | } |
1304 | else |
1305 | { |
1306 | buf.put( ( byte ) 0x00 ); |
1307 | buf.put( ( byte ) 0x00 ); |
1308 | } |
1309 | } |
1310 | |
1311 | buf.position( end ); |
1312 | return this; |
1313 | } |
1314 | |
1315 | public ByteBuffer putString( |
1316 | CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException |
1317 | { |
1318 | if( val.length() == 0 ) |
1319 | { |
1320 | return this; |
1321 | } |
1322 | |
1323 | CharBuffer in = CharBuffer.wrap( val ); |
1324 | int expectedLength = (int) (in.remaining() * encoder.averageBytesPerChar()); |
1325 | |
1326 | encoder.reset(); |
1327 | |
1328 | for (;;) { |
1329 | CoderResult cr; |
1330 | if( in.hasRemaining() ) |
1331 | { |
1332 | cr = encoder.encode( in, buf(), true ); |
1333 | } |
1334 | else |
1335 | { |
1336 | cr = encoder.flush( buf() ); |
1337 | } |
1338 | |
1339 | if( cr.isUnderflow() ) |
1340 | { |
1341 | break; |
1342 | } |
1343 | if( cr.isOverflow() && autoExpand ) |
1344 | { |
1345 | autoExpand( expectedLength ); |
1346 | continue; |
1347 | } |
1348 | cr.throwException(); |
1349 | } |
1350 | return this; |
1351 | } |
1352 | |
1353 | public ByteBuffer skip( int size ) |
1354 | { |
1355 | autoExpand( size ); |
1356 | return position( position() + size ); |
1357 | } |
1358 | |
1359 | public ByteBuffer fill( byte value, int size ) |
1360 | { |
1361 | autoExpand( size ); |
1362 | int q = size >>> 3; |
1363 | int r = size & 7; |
1364 | |
1365 | if( q > 0 ) |
1366 | { |
1367 | int intValue = value | ( value << 8 ) | ( value << 16 ) |
1368 | | ( value << 24 ); |
1369 | long longValue = intValue; |
1370 | longValue <<= 32; |
1371 | longValue |= intValue; |
1372 | |
1373 | for( int i = q; i > 0; i -- ) |
1374 | { |
1375 | buf.putLong( longValue ); |
1376 | } |
1377 | } |
1378 | |
1379 | q = r >>> 2; |
1380 | r = r & 3; |
1381 | |
1382 | if( q > 0 ) |
1383 | { |
1384 | int intValue = value | ( value << 8 ) | ( value << 16 ) |
1385 | | ( value << 24 ); |
1386 | buf.putInt( intValue ); |
1387 | } |
1388 | |
1389 | q = r >> 1; |
1390 | r = r & 1; |
1391 | |
1392 | if( q > 0 ) |
1393 | { |
1394 | short shortValue = ( short ) ( value | ( value << 8 ) ); |
1395 | buf.putShort( shortValue ); |
1396 | } |
1397 | |
1398 | if( r > 0 ) |
1399 | { |
1400 | buf.put( value ); |
1401 | } |
1402 | |
1403 | return this; |
1404 | } |
1405 | |
1406 | public ByteBuffer fillAndReset( byte value, int size ) |
1407 | { |
1408 | autoExpand( size ); |
1409 | int pos = buf.position(); |
1410 | try |
1411 | { |
1412 | fill( value, size ); |
1413 | } |
1414 | finally |
1415 | { |
1416 | buf.position( pos ); |
1417 | } |
1418 | return this; |
1419 | } |
1420 | |
1421 | public ByteBuffer fill( int size ) |
1422 | { |
1423 | autoExpand( size ); |
1424 | int q = size >>> 3; |
1425 | int r = size & 7; |
1426 | |
1427 | for( int i = q; i > 0; i -- ) |
1428 | { |
1429 | buf.putLong( 0L ); |
1430 | } |
1431 | |
1432 | q = r >>> 2; |
1433 | r = r & 3; |
1434 | |
1435 | if( q > 0 ) |
1436 | { |
1437 | buf.putInt( 0 ); |
1438 | } |
1439 | |
1440 | q = r >> 1; |
1441 | r = r & 1; |
1442 | |
1443 | if( q > 0 ) |
1444 | { |
1445 | buf.putShort( ( short ) 0 ); |
1446 | } |
1447 | |
1448 | if( r > 0 ) |
1449 | { |
1450 | buf.put( ( byte ) 0 ); |
1451 | } |
1452 | |
1453 | return this; |
1454 | } |
1455 | |
1456 | public ByteBuffer fillAndReset( int size ) |
1457 | { |
1458 | autoExpand( size ); |
1459 | int pos = buf.position(); |
1460 | try |
1461 | { |
1462 | fill( size ); |
1463 | } |
1464 | finally |
1465 | { |
1466 | buf.position( pos ); |
1467 | } |
1468 | |
1469 | return this; |
1470 | } |
1471 | |
1472 | private void autoExpand( int delta ) |
1473 | { |
1474 | if( autoExpand ) |
1475 | { |
1476 | int pos = buf.position(); |
1477 | int limit = buf.limit(); |
1478 | int end = pos + delta; |
1479 | if( end > limit ) { |
1480 | ensureCapacity( end ); |
1481 | buf.limit( end ); |
1482 | } |
1483 | } |
1484 | } |
1485 | |
1486 | private void autoExpand( int pos, int delta ) |
1487 | { |
1488 | if( autoExpand ) |
1489 | { |
1490 | int limit = buf.limit(); |
1491 | int end = pos + delta; |
1492 | if( end > limit ) { |
1493 | ensureCapacity( end ); // expand by 50% |
1494 | buf.limit( end ); |
1495 | } |
1496 | } |
1497 | } |
1498 | |
1499 | private void ensureCapacity( int requestedCapacity ) |
1500 | { |
1501 | if( requestedCapacity <= buf.capacity() ) |
1502 | { |
1503 | return; |
1504 | } |
1505 | |
1506 | int newCapacity = MINIMUM_CAPACITY; |
1507 | while( newCapacity < requestedCapacity ) |
1508 | { |
1509 | newCapacity <<= 1; |
1510 | } |
1511 | |
1512 | java.nio.ByteBuffer oldBuf = this.buf; |
1513 | java.nio.ByteBuffer newBuf = allocate0( newCapacity, isDirect() ); |
1514 | newBuf.clear(); |
1515 | newBuf.order( oldBuf.order() ); |
1516 | |
1517 | int pos = oldBuf.position(); |
1518 | int limit = oldBuf.limit(); |
1519 | oldBuf.clear(); |
1520 | newBuf.put( oldBuf ); |
1521 | newBuf.position( 0 ); |
1522 | newBuf.limit( limit ); |
1523 | newBuf.position( pos ); |
1524 | this.buf = newBuf; |
1525 | release0( oldBuf ); |
1526 | } |
1527 | |
1528 | private static void checkFieldSize( int fieldSize ) |
1529 | { |
1530 | if( fieldSize < 0 ) |
1531 | { |
1532 | throw new IllegalArgumentException( |
1533 | "fieldSize cannot be negative: " + fieldSize ); |
1534 | } |
1535 | } |
1536 | |
1537 | } |
1538 | } |