1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. 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,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 */
20 package org.apache.mina.common;
21
22 import java.io.EOFException;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.io.ObjectStreamClass;
28 import java.io.OutputStream;
29 import java.io.StreamCorruptedException;
30 import java.nio.BufferOverflowException;
31 import java.nio.BufferUnderflowException;
32 import java.nio.ByteOrder;
33 import java.nio.CharBuffer;
34 import java.nio.DoubleBuffer;
35 import java.nio.FloatBuffer;
36 import java.nio.IntBuffer;
37 import java.nio.LongBuffer;
38 import java.nio.ShortBuffer;
39 import java.nio.charset.CharacterCodingException;
40 import java.nio.charset.CharsetDecoder;
41 import java.nio.charset.CharsetEncoder;
42 import java.nio.charset.CoderResult;
43 import java.util.HashSet;
44 import java.util.Set;
45
46 import org.apache.mina.common.support.ByteBufferHexDumper;
47 import org.apache.mina.filter.codec.ProtocolEncoderOutput;
48
49 /**
50 * A byte buffer used by MINA applications.
51 * <p>
52 * This is a replacement for {@link java.nio.ByteBuffer}. Please refer to
53 * {@link java.nio.ByteBuffer} and {@link java.nio.Buffer} documentation for
54 * usage. MINA does not use NIO {@link java.nio.ByteBuffer} directly for two
55 * reasons:
56 * <ul>
57 * <li>It doesn't provide useful getters and putters such as
58 * <code>fill</code>, <code>get/putString</code>, and
59 * <code>get/putAsciiInt()</code> enough.</li>
60 * <li>It is hard to distinguish if the buffer is created from MINA buffer
61 * pool or not. MINA have to return used buffers back to pool.</li>
62 * <li>It is difficult to write variable-length data due to its fixed
63 * capacity</li>
64 * </ul>
65 * </p>
66 *
67 * <h2>Allocation</h2>
68 * <p>
69 * You can get a heap buffer from buffer pool:
70 * <pre>
71 * ByteBuffer buf = ByteBuffer.allocate(1024, false);
72 * </pre>
73 * you can also get a direct buffer from buffer pool:
74 * <pre>
75 * ByteBuffer buf = ByteBuffer.allocate(1024, true);
76 * </pre>
77 * or you can let MINA choose:
78 * <pre>
79 * ByteBuffer buf = ByteBuffer.allocate(1024);
80 * </pre>
81 * </p>
82 *
83 * <h2>Acquire/Release</h2>
84 * <p>
85 * <b>Please note that you never need to release the allocated buffer</b>
86 * because MINA will release it automatically when:
87 * <ul>
88 * <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li>
89 * <li>You pass the buffer by calling {@link IoFilter.NextFilter#filterWrite(IoSession,IoFilter.WriteRequest)}.</li>
90 * <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li>
91 * </ul>
92 * And, you don't need to release any {@link ByteBuffer} which is passed as a parameter
93 * of {@link IoHandler#messageReceived(IoSession, Object)} method. They are released
94 * automatically when the method returns.
95 * <p>
96 * You have to release buffers manually by calling {@link #release()} when:
97 * <ul>
98 * <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li>
99 * <li>You called {@link #acquire()} to prevent the buffer from being released.</li>
100 * </ul>
101 * </p>
102 *
103 * <h2>Wrapping existing NIO buffers and arrays</h2>
104 * <p>
105 * This class provides a few <tt>wrap(...)</tt> methods that wraps
106 * any NIO buffers and byte arrays. Wrapped MINA buffers are not returned
107 * to the buffer pool by default to prevent unexpected memory leakage by default.
108 * In case you want to make it pooled, you can call {@link #setPooled(boolean)}
109 * with <tt>true</tt> flag to enable pooling.
110 *
111 * <h2>AutoExpand</h2>
112 * <p>
113 * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really
114 * easy, and it is because its size is fixed. MINA <tt>ByteBuffer</tt>
115 * introduces <tt>autoExpand</tt> property. If <tt>autoExpand</tt> property
116 * is true, you never get {@link BufferOverflowException} or
117 * {@link IndexOutOfBoundsException} (except when index is negative).
118 * It automatically expands its capacity and limit value. For example:
119 * <pre>
120 * String greeting = messageBundle.getMessage( "hello" );
121 * ByteBuffer buf = ByteBuffer.allocate( 16 );
122 * // Turn on autoExpand (it is off by default)
123 * buf.setAutoExpand( true );
124 * buf.putString( greeting, utf8encoder );
125 * </pre>
126 * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind
127 * the scene if the encoded data is larger than 16 bytes. Its capacity and
128 * its limit will increase to the last position the string is written.
129 * </p>
130 *
131 * <h2>Derived Buffers</h2>
132 * <p>
133 * Derived buffers are the buffers which were created by
134 * {@link #duplicate()}, {@link #slice()}, or {@link #asReadOnlyBuffer()}.
135 * They are useful especially when you broadcast the same messages to
136 * multiple {@link IoSession}s. Please note that the derived buffers are
137 * neither pooled nor auto-expandable. Trying to expand a derived buffer will
138 * raise {@link IllegalStateException}.
139 * </p>
140 *
141 * <h2>Changing Buffer Allocation and Management Policy</h2>
142 * <p>
143 * MINA provides a {@link ByteBufferAllocator} interface to let you override
144 * the default buffer management behavior. There are two allocators provided
145 * out-of-the-box:
146 * <ul>
147 * <li>{@link PooledByteBufferAllocator} (Default)</li>
148 * <li>{@link SimpleByteBufferAllocator}</li>
149 * </ul>
150 * You can change the allocator by calling {@link #setAllocator(ByteBufferAllocator)}.
151 * </p>
152 *
153 * @author The Apache Directory Project (mina-dev@directory.apache.org)
154 * @version $Rev: 637706 $, $Date: 2008-03-17 12:18:43 +0900 (Mon, 17 Mar 2008) $
155 * @noinspection StaticNonFinalField
156 * @see ByteBufferAllocator
157 */
158 public abstract class ByteBuffer implements Comparable<ByteBuffer> {
159 private static ByteBufferAllocator allocator = new PooledByteBufferAllocator();
160
161 private static boolean useDirectBuffers = true;
162
163 /**
164 * Returns the current allocator which manages the allocated buffers.
165 */
166 public static ByteBufferAllocator getAllocator() {
167 return allocator;
168 }
169
170 /**
171 * Changes the current allocator with the specified one to manage
172 * the allocated buffers from now.
173 */
174 public static void setAllocator(ByteBufferAllocator newAllocator) {
175 if (newAllocator == null) {
176 throw new NullPointerException("allocator");
177 }
178
179 ByteBufferAllocator oldAllocator = allocator;
180
181 allocator = newAllocator;
182
183 if (null != oldAllocator) {
184 oldAllocator.dispose();
185 }
186 }
187
188 public static boolean isUseDirectBuffers() {
189 return useDirectBuffers;
190 }
191
192 public static void setUseDirectBuffers(boolean useDirectBuffers) {
193 ByteBuffer.useDirectBuffers = useDirectBuffers;
194 }
195
196 /**
197 * Returns the direct or heap buffer which is capable of the specified
198 * size. This method tries to allocate direct buffer first, and then
199 * tries heap buffer if direct buffer memory is exhausted. Please use
200 * {@link #allocate(int, boolean)} to allocate buffers of specific type.
201 *
202 * @param capacity the capacity of the buffer
203 */
204 public static ByteBuffer allocate(int capacity) {
205 if (useDirectBuffers) {
206 try {
207 // first try to allocate direct buffer
208 return allocate(capacity, true);
209 } catch (OutOfMemoryError e) {
210 // fall through to heap buffer
211 }
212 }
213
214 return allocate(capacity, false);
215 }
216
217 /**
218 * Returns the buffer which is capable of the specified size.
219 *
220 * @param capacity the capacity of the buffer
221 * @param direct <tt>true</tt> to get a direct buffer,
222 * <tt>false</tt> to get a heap buffer.
223 */
224 public static ByteBuffer allocate(int capacity, boolean direct) {
225 return allocator.allocate(capacity, direct);
226 }
227
228 /**
229 * Wraps the specified NIO {@link java.nio.ByteBuffer} into MINA buffer.
230 */
231 public static ByteBuffer wrap(java.nio.ByteBuffer nioBuffer) {
232 return allocator.wrap(nioBuffer);
233 }
234
235 /**
236 * Wraps the specified byte array into MINA heap buffer.
237 */
238 public static ByteBuffer wrap(byte[] byteArray) {
239 return wrap(java.nio.ByteBuffer.wrap(byteArray));
240 }
241
242 /**
243 * Wraps the specified byte array into MINA heap buffer.
244 * Please note that MINA buffers are going to be pooled, and
245 * therefore there can be waste of memory if you wrap
246 * your byte array specifying <tt>offset</tt> and <tt>length</tt>.
247 */
248 public static ByteBuffer wrap(byte[] byteArray, int offset, int length) {
249 return wrap(java.nio.ByteBuffer.wrap(byteArray, offset, length));
250 }
251
252 private static final Set<String> primitiveTypeNames = new HashSet<String>();
253
254 static {
255 primitiveTypeNames.add("void");
256 primitiveTypeNames.add("boolean");
257 primitiveTypeNames.add("byte");
258 primitiveTypeNames.add("char");
259 primitiveTypeNames.add("short");
260 primitiveTypeNames.add("int");
261 primitiveTypeNames.add("long");
262 primitiveTypeNames.add("float");
263 primitiveTypeNames.add("double");
264 }
265
266 protected ByteBuffer() {
267 }
268
269 /**
270 * Increases the internal reference count of this buffer to defer
271 * automatic release. You have to invoke {@link #release()} as many
272 * as you invoked this method to release this buffer.
273 *
274 * @throws IllegalStateException if you attempt to acquire already
275 * released buffer.
276 */
277 public abstract void acquire();
278
279 /**
280 * Releases the specified buffer to buffer pool.
281 *
282 * @throws IllegalStateException if you attempt to release already
283 * released buffer.
284 */
285 public abstract void release();
286
287 /**
288 * Returns the underlying NIO buffer instance.
289 */
290 public abstract java.nio.ByteBuffer buf();
291
292 /**
293 * @see java.nio.ByteBuffer#isDirect()
294 */
295 public abstract boolean isDirect();
296
297 /**
298 * @see java.nio.ByteBuffer#isReadOnly()
299 */
300 public abstract boolean isReadOnly();
301
302 /**
303 * @see java.nio.ByteBuffer#capacity()
304 */
305 public abstract int capacity();
306
307 /**
308 * Changes the capacity of this buffer.
309 */
310 public abstract ByteBuffer capacity(int newCapacity);
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 * Changes the capacity and limit of this buffer so this buffer get
324 * the specified <tt>expectedRemaining</tt> room from the current position.
325 * This method works even if you didn't set <tt>autoExpand</tt> to
326 * <tt>true</tt>.
327 */
328 public ByteBuffer expand(int expectedRemaining) {
329 return expand(position(), expectedRemaining);
330 }
331
332 /**
333 * Changes the capacity and limit of this buffer so this buffer get
334 * the specified <tt>expectedRemaining</tt> room from the specified
335 * <tt>pos</tt>.
336 * This method works even if you didn't set <tt>autoExpand</tt> to
337 * <tt>true</tt>.
338 */
339 public abstract ByteBuffer expand(int pos, int expectedRemaining);
340
341 /**
342 * Returns <tt>true</tt> if and only if this buffer is returned back
343 * to the buffer pool when released.
344 * <p>
345 * The default value of this property is <tt>true</tt> if and only if you
346 * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
347 * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
348 * and {@link #wrap(java.nio.ByteBuffer)})
349 */
350 public abstract boolean isPooled();
351
352 /**
353 * Sets whether this buffer is returned back to the buffer pool when released.
354 * <p>
355 * The default value of this property is <tt>true</tt> if and only if you
356 * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, boolean)},
357 * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
358 * and {@link #wrap(java.nio.ByteBuffer)})
359 */
360 public abstract void setPooled(boolean pooled);
361
362 /**
363 * @see java.nio.Buffer#position()
364 */
365 public abstract int position();
366
367 /**
368 * @see java.nio.Buffer#position(int)
369 */
370 public abstract ByteBuffer position(int newPosition);
371
372 /**
373 * @see java.nio.Buffer#limit()
374 */
375 public abstract int limit();
376
377 /**
378 * @see java.nio.Buffer#limit(int)
379 */
380 public abstract ByteBuffer limit(int newLimit);
381
382 /**
383 * @see java.nio.Buffer#mark()
384 */
385 public abstract ByteBuffer mark();
386
387 /**
388 * Returns the position of the current mark. This method returns <tt>-1</tt> if no
389 * mark is set.
390 */
391 public abstract int markValue();
392
393 /**
394 * @see java.nio.Buffer#reset()
395 */
396 public abstract ByteBuffer reset();
397
398 /**
399 * @see java.nio.Buffer#clear()
400 */
401 public abstract ByteBuffer clear();
402
403 /**
404 * Clears this buffer and fills its content with <tt>NUL</tt>.
405 * The position is set to zero, the limit is set to the capacity,
406 * and the mark is discarded.
407 */
408 public ByteBuffer sweep() {
409 clear();
410 return fillAndReset(remaining());
411 }
412
413 /**
414 * Clears this buffer and fills its content with <tt>value</tt>.
415 * The position is set to zero, the limit is set to the capacity,
416 * and the mark is discarded.
417 */
418 public ByteBuffer sweep(byte value) {
419 clear();
420 return fillAndReset(value, remaining());
421 }
422
423 /**
424 * @see java.nio.Buffer#flip()
425 */
426 public abstract ByteBuffer flip();
427
428 /**
429 * @see java.nio.Buffer#rewind()
430 */
431 public abstract ByteBuffer rewind();
432
433 /**
434 * @see java.nio.Buffer#remaining()
435 */
436 public int remaining() {
437 return limit() - position();
438 }
439
440 /**
441 * @see java.nio.Buffer#hasRemaining()
442 */
443 public boolean hasRemaining() {
444 return remaining() > 0;
445 }
446
447 /**
448 * @see java.nio.ByteBuffer#duplicate()
449 */
450 public abstract ByteBuffer duplicate();
451
452 /**
453 * @see java.nio.ByteBuffer#slice()
454 */
455 public abstract ByteBuffer slice();
456
457 /**
458 * @see java.nio.ByteBuffer#asReadOnlyBuffer()
459 */
460 public abstract ByteBuffer asReadOnlyBuffer();
461
462 /**
463 * @see java.nio.ByteBuffer#array()
464 */
465 public abstract byte[] array();
466
467 /**
468 * @see java.nio.ByteBuffer#arrayOffset()
469 */
470 public abstract int arrayOffset();
471
472 /**
473 * @see java.nio.ByteBuffer#get()
474 */
475 public abstract byte get();
476
477 /**
478 * Reads one unsigned byte as a short integer.
479 */
480 public short getUnsigned() {
481 return (short) (get() & 0xff);
482 }
483
484 /**
485 * @see java.nio.ByteBuffer#put(byte)
486 */
487 public abstract ByteBuffer put(byte b);
488
489 /**
490 * @see java.nio.ByteBuffer#get(int)
491 */
492 public abstract byte get(int index);
493
494 /**
495 * Reads one byte as an unsigned short integer.
496 */
497 public short getUnsigned(int index) {
498 return (short) (get(index) & 0xff);
499 }
500
501 /**
502 * @see java.nio.ByteBuffer#put(int, byte)
503 */
504 public abstract ByteBuffer put(int index, byte b);
505
506 /**
507 * @see java.nio.ByteBuffer#get(byte[], int, int)
508 */
509 public abstract ByteBuffer get(byte[] dst, int offset, int length);
510
511 /**
512 * @see java.nio.ByteBuffer#get(byte[])
513 */
514 public ByteBuffer get(byte[] dst) {
515 return get(dst, 0, dst.length);
516 }
517
518 /**
519 * Writes the content of the specified <tt>src</tt> into this buffer.
520 */
521 public abstract ByteBuffer put(java.nio.ByteBuffer src);
522
523 /**
524 * Writes the content of the specified <tt>src</tt> into this buffer.
525 */
526 public ByteBuffer put(ByteBuffer src) {
527 return put(src.buf());
528 }
529
530 /**
531 * @see java.nio.ByteBuffer#put(byte[], int, int)
532 */
533 public abstract ByteBuffer put(byte[] src, int offset, int length);
534
535 /**
536 * @see java.nio.ByteBuffer#put(byte[])
537 */
538 public ByteBuffer put(byte[] src) {
539 return put(src, 0, src.length);
540 }
541
542 /**
543 * @see java.nio.ByteBuffer#compact()
544 */
545 public abstract ByteBuffer compact();
546
547 @Override
548 public String toString() {
549 StringBuffer buf = new StringBuffer();
550 if (isDirect()) {
551 buf.append("DirectBuffer");
552 } else {
553 buf.append("HeapBuffer");
554 }
555 buf.append("[pos=");
556 buf.append(position());
557 buf.append(" lim=");
558 buf.append(limit());
559 buf.append(" cap=");
560 buf.append(capacity());
561 buf.append(": ");
562 buf.append(getHexDump());
563 buf.append(']');
564 return buf.toString();
565 }
566
567 @Override
568 public int hashCode() {
569 int h = 1;
570 int p = position();
571 for (int i = limit() - 1; i >= p; i--) {
572 h = 31 * h + get(i);
573 }
574 return h;
575 }
576
577 @Override
578 public boolean equals(Object o) {
579 if (!(o instanceof ByteBuffer)) {
580 return false;
581 }
582
583 ByteBuffer that = (ByteBuffer) o;
584 if (this.remaining() != that.remaining()) {
585 return false;
586 }
587
588 int p = this.position();
589 for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
590 byte v1 = this.get(i);
591 byte v2 = that.get(j);
592 if (v1 != v2) {
593 return false;
594 }
595 }
596 return true;
597 }
598
599 public int compareTo(ByteBuffer that) {
600 int n = this.position() + Math.min(this.remaining(), that.remaining());
601 for (int i = this.position(), j = that.position(); i < n; i++, j++) {
602 byte v1 = this.get(i);
603 byte v2 = that.get(j);
604 if (v1 == v2) {
605 continue;
606 }
607 if (v1 < v2) {
608 return -1;
609 }
610
611 return +1;
612 }
613 return this.remaining() - that.remaining();
614 }
615
616 /**
617 * @see java.nio.ByteBuffer#order()
618 */
619 public abstract ByteOrder order();
620
621 /**
622 * @see java.nio.ByteBuffer#order(ByteOrder)
623 */
624 public abstract ByteBuffer order(ByteOrder bo);
625
626 /**
627 * @see java.nio.ByteBuffer#getChar()
628 */
629 public abstract char getChar();
630
631 /**
632 * @see java.nio.ByteBuffer#putChar(char)
633 */
634 public abstract ByteBuffer putChar(char value);
635
636 /**
637 * @see java.nio.ByteBuffer#getChar(int)
638 */
639 public abstract char getChar(int index);
640
641 /**
642 * @see java.nio.ByteBuffer#putChar(int, char)
643 */
644 public abstract ByteBuffer putChar(int index, char value);
645
646 /**
647 * @see java.nio.ByteBuffer#asCharBuffer()
648 */
649 public abstract CharBuffer asCharBuffer();
650
651 /**
652 * @see java.nio.ByteBuffer#getShort()
653 */
654 public abstract short getShort();
655
656 /**
657 * Reads two bytes unsigned integer.
658 */
659 public int getUnsignedShort() {
660 return getShort() & 0xffff;
661 }
662
663 /**
664 * @see java.nio.ByteBuffer#putShort(short)
665 */
666 public abstract ByteBuffer putShort(short value);
667
668 /**
669 * @see java.nio.ByteBuffer#getShort()
670 */
671 public abstract short getShort(int index);
672
673 /**
674 * Reads two bytes unsigned integer.
675 */
676 public int getUnsignedShort(int index) {
677 return getShort(index) & 0xffff;
678 }
679
680 /**
681 * @see java.nio.ByteBuffer#putShort(int, short)
682 */
683 public abstract ByteBuffer putShort(int index, short value);
684
685 /**
686 * @see java.nio.ByteBuffer#asShortBuffer()
687 */
688 public abstract ShortBuffer asShortBuffer();
689
690 /**
691 * @see java.nio.ByteBuffer#getInt()
692 */
693 public abstract int getInt();
694
695 /**
696 * Reads four bytes unsigned integer.
697 */
698 public long getUnsignedInt() {
699 return getInt() & 0xffffffffL;
700 }
701
702 /**
703 * @see java.nio.ByteBuffer#putInt(int)
704 */
705 public abstract ByteBuffer putInt(int value);
706
707 /**
708 * @see java.nio.ByteBuffer#getInt(int)
709 */
710 public abstract int getInt(int index);
711
712 /**
713 * Reads four bytes unsigned integer.
714 */
715 public long getUnsignedInt(int index) {
716 return getInt(index) & 0xffffffffL;
717 }
718
719 /**
720 * @see java.nio.ByteBuffer#putInt(int, int)
721 */
722 public abstract ByteBuffer putInt(int index, int value);
723
724 /**
725 * @see java.nio.ByteBuffer#asIntBuffer()
726 */
727 public abstract IntBuffer asIntBuffer();
728
729 /**
730 * @see java.nio.ByteBuffer#getLong()
731 */
732 public abstract long getLong();
733
734 /**
735 * @see java.nio.ByteBuffer#putLong(int, long)
736 */
737 public abstract ByteBuffer putLong(long value);
738
739 /**
740 * @see java.nio.ByteBuffer#getLong(int)
741 */
742 public abstract long getLong(int index);
743
744 /**
745 * @see java.nio.ByteBuffer#putLong(int, long)
746 */
747 public abstract ByteBuffer putLong(int index, long value);
748
749 /**
750 * @see java.nio.ByteBuffer#asLongBuffer()
751 */
752 public abstract LongBuffer asLongBuffer();
753
754 /**
755 * @see java.nio.ByteBuffer#getFloat()
756 */
757 public abstract float getFloat();
758
759 /**
760 * @see java.nio.ByteBuffer#putFloat(float)
761 */
762 public abstract ByteBuffer putFloat(float value);
763
764 /**
765 * @see java.nio.ByteBuffer#getFloat(int)
766 */
767 public abstract float getFloat(int index);
768
769 /**
770 * @see java.nio.ByteBuffer#putFloat(int, float)
771 */
772 public abstract ByteBuffer putFloat(int index, float value);
773
774 /**
775 * @see java.nio.ByteBuffer#asFloatBuffer()
776 */
777 public abstract FloatBuffer asFloatBuffer();
778
779 /**
780 * @see java.nio.ByteBuffer#getDouble()
781 */
782 public abstract double getDouble();
783
784 /**
785 * @see java.nio.ByteBuffer#putDouble(double)
786 */
787 public abstract ByteBuffer putDouble(double value);
788
789 /**
790 * @see java.nio.ByteBuffer#getDouble(int)
791 */
792 public abstract double getDouble(int index);
793
794 /**
795 * @see java.nio.ByteBuffer#putDouble(int, double)
796 */
797 public abstract ByteBuffer putDouble(int index, double value);
798
799 /**
800 * @see java.nio.ByteBuffer#asDoubleBuffer()
801 */
802 public abstract DoubleBuffer asDoubleBuffer();
803
804 /**
805 * Returns an {@link InputStream} that reads the data from this buffer.
806 * {@link InputStream#read()} returns <tt>-1</tt> if the buffer position
807 * reaches to the limit.
808 */
809 public InputStream asInputStream() {
810 return new InputStream() {
811 @Override
812 public int available() {
813 return ByteBuffer.this.remaining();
814 }
815
816 @Override
817 public synchronized void mark(int readlimit) {
818 ByteBuffer.this.mark();
819 }
820
821 @Override
822 public boolean markSupported() {
823 return true;
824 }
825
826 @Override
827 public int read() {
828 if (ByteBuffer.this.hasRemaining()) {
829 return ByteBuffer.this.get() & 0xff;
830 } else {
831 return -1;
832 }
833 }
834
835 @Override
836 public int read(byte[] b, int off, int len) {
837 int remaining = ByteBuffer.this.remaining();
838 if (remaining > 0) {
839 int readBytes = Math.min(remaining, len);
840 ByteBuffer.this.get(b, off, readBytes);
841 return readBytes;
842 } else {
843 return -1;
844 }
845 }
846
847 @Override
848 public synchronized void reset() {
849 ByteBuffer.this.reset();
850 }
851
852 @Override
853 public long skip(long n) {
854 int bytes;
855 if (n > Integer.MAX_VALUE) {
856 bytes = ByteBuffer.this.remaining();
857 } else {
858 bytes = Math.min(ByteBuffer.this.remaining(), (int) n);
859 }
860 ByteBuffer.this.skip(bytes);
861 return bytes;
862 }
863 };
864 }
865
866 /**
867 * Returns an {@link OutputStream} that appends the data into this buffer.
868 * Please note that the {@link OutputStream#write(int)} will throw a
869 * {@link BufferOverflowException} instead of an {@link IOException}
870 * in case of buffer overflow. Please set <tt>autoExpand</tt> property by
871 * calling {@link #setAutoExpand(boolean)} to prevent the unexpected runtime
872 * exception.
873 */
874 public OutputStream asOutputStream() {
875 return new OutputStream() {
876 @Override
877 public void write(byte[] b, int off, int len) {
878 ByteBuffer.this.put(b, off, len);
879 }
880
881 @Override
882 public void write(int b) {
883 ByteBuffer.this.put((byte) b);
884 }
885 };
886 }
887
888 /**
889 * Returns hexdump of this buffer.
890 */
891 public String getHexDump() {
892 return ByteBufferHexDumper.getHexdump(this);
893 }
894
895 ////////////////////////////////
896 // String getters and putters //
897 ////////////////////////////////
898
899 /**
900 * Reads a <code>NUL</code>-terminated string from this buffer using the
901 * specified <code>decoder</code> and returns it. This method reads
902 * until the limit of this buffer if no <tt>NUL</tt> is found.
903 */
904 public String getString(CharsetDecoder decoder)
905 throws CharacterCodingException {
906 if (!hasRemaining()) {
907 return "";
908 }
909
910 boolean utf16 = decoder.charset().name().startsWith("UTF-16");
911
912 int oldPos = position();
913 int oldLimit = limit();
914 int end;
915
916 if (!utf16) {
917 while (hasRemaining()) {
918 if (get() == 0) {
919 break;
920 }
921 }
922
923 end = position();
924 if (end == oldLimit && get(end - 1) != 0) {
925 limit(end);
926 } else {
927 limit(end - 1);
928 }
929 } else {
930 while (remaining() >= 2) {
931 boolean highZero = (get() == 0);
932 boolean lowZero = (get() == 0);
933 if (highZero && lowZero) {
934 break;
935 }
936 }
937
938 end = position();
939 if (end == oldLimit || end == oldLimit - 1) {
940 limit(end);
941 } else {
942 limit(end - 2);
943 }
944 }
945
946 position(oldPos);
947 if (!hasRemaining()) {
948 limit(oldLimit);
949 position(end);
950 return "";
951 }
952 decoder.reset();
953
954 int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
955 CharBuffer out = CharBuffer.allocate(expectedLength);
956 for (;;) {
957 CoderResult cr;
958 if (hasRemaining()) {
959 cr = decoder.decode(buf(), out, true);
960 } else {
961 cr = decoder.flush(out);
962 }
963
964 if (cr.isUnderflow()) {
965 break;
966 }
967
968 if (cr.isOverflow()) {
969 CharBuffer o = CharBuffer.allocate(out.capacity()
970 + expectedLength);
971 out.flip();
972 o.put(out);
973 out = o;
974 continue;
975 }
976
977 if (cr.isError()) {
978 // Revert the buffer back to the previous state.
979 limit(oldLimit);
980 position(oldPos);
981 cr.throwException();
982 }
983 }
984
985 limit(oldLimit);
986 position(end);
987 return out.flip().toString();
988 }
989
990 /**
991 * Reads a <code>NUL</code>-terminated string from this buffer using the
992 * specified <code>decoder</code> and returns it.
993 *
994 * @param fieldSize the maximum number of bytes to read
995 */
996 public String getString(int fieldSize, CharsetDecoder decoder)
997 throws CharacterCodingException {
998 checkFieldSize(fieldSize);
999
1000 if (fieldSize == 0) {
1001 return "";
1002 }
1003
1004 if (!hasRemaining()) {
1005 return "";
1006 }
1007
1008 boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1009
1010 if (utf16 && ((fieldSize & 1) != 0)) {
1011 throw new IllegalArgumentException("fieldSize is not even.");
1012 }
1013
1014 int oldPos = position();
1015 int oldLimit = limit();
1016 int end = position() + fieldSize;
1017
1018 if (oldLimit < end) {
1019 throw new BufferUnderflowException();
1020 }
1021
1022 int i;
1023
1024 if (!utf16) {
1025 for (i = 0; i < fieldSize; i++) {
1026 if (get() == 0) {
1027 break;
1028 }
1029 }
1030
1031 if (i == fieldSize) {
1032 limit(end);
1033 } else {
1034 limit(position() - 1);
1035 }
1036 } else {
1037 for (i = 0; i < fieldSize; i += 2) {
1038 boolean highZero = (get() == 0);
1039 boolean lowZero = (get() == 0);
1040 if (highZero && lowZero) {
1041 break;
1042 }
1043 }
1044
1045 if (i == fieldSize) {
1046 limit(end);
1047 } else {
1048 limit(position() - 2);
1049 }
1050 }
1051
1052 position(oldPos);
1053 if (!hasRemaining()) {
1054 limit(oldLimit);
1055 position(end);
1056 return "";
1057 }
1058 decoder.reset();
1059
1060 int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1061 CharBuffer out = CharBuffer.allocate(expectedLength);
1062 for (;;) {
1063 CoderResult cr;
1064 if (hasRemaining()) {
1065 cr = decoder.decode(buf(), out, true);
1066 } else {
1067 cr = decoder.flush(out);
1068 }
1069
1070 if (cr.isUnderflow()) {
1071 break;
1072 }
1073
1074 if (cr.isOverflow()) {
1075 CharBuffer o = CharBuffer.allocate(out.capacity()
1076 + expectedLength);
1077 out.flip();
1078 o.put(out);
1079 out = o;
1080 continue;
1081 }
1082
1083 if (cr.isError()) {
1084 // Revert the buffer back to the previous state.
1085 limit(oldLimit);
1086 position(oldPos);
1087 cr.throwException();
1088 }
1089 }
1090
1091 limit(oldLimit);
1092 position(end);
1093 return out.flip().toString();
1094 }
1095
1096 /**
1097 * Writes the content of <code>in</code> into this buffer using the
1098 * specified <code>encoder</code>. This method doesn't terminate
1099 * string with <tt>NUL</tt>. You have to do it by yourself.
1100 *
1101 * @throws BufferOverflowException if the specified string doesn't fit
1102 */
1103 public ByteBuffer putString(CharSequence val, CharsetEncoder encoder)
1104 throws CharacterCodingException {
1105 if (val.length() == 0) {
1106 return this;
1107 }
1108
1109 CharBuffer in = CharBuffer.wrap(val);
1110 encoder.reset();
1111
1112 int expandedState = 0;
1113
1114 for (;;) {
1115 CoderResult cr;
1116 if (in.hasRemaining()) {
1117 cr = encoder.encode(in, buf(), true);
1118 } else {
1119 cr = encoder.flush(buf());
1120 }
1121
1122 if (cr.isUnderflow()) {
1123 break;
1124 }
1125 if (cr.isOverflow()) {
1126 if (isAutoExpand()) {
1127 switch (expandedState) {
1128 case 0:
1129 autoExpand((int) Math.ceil(in.remaining()
1130 * encoder.averageBytesPerChar()));
1131 expandedState++;
1132 break;
1133 case 1:
1134 autoExpand((int) Math.ceil(in.remaining()
1135 * encoder.maxBytesPerChar()));
1136 expandedState++;
1137 break;
1138 default:
1139 throw new RuntimeException("Expanded by "
1140 + (int) Math.ceil(in.remaining()
1141 * encoder.maxBytesPerChar())
1142 + " but that wasn't enough for '" + val + "'");
1143 }
1144 continue;
1145 }
1146 } else {
1147 expandedState = 0;
1148 }
1149 cr.throwException();
1150 }
1151 return this;
1152 }
1153
1154 /**
1155 * Writes the content of <code>in</code> into this buffer as a
1156 * <code>NUL</code>-terminated string using the specified
1157 * <code>encoder</code>.
1158 * <p>
1159 * If the charset name of the encoder is UTF-16, you cannot specify
1160 * odd <code>fieldSize</code>, and this method will append two
1161 * <code>NUL</code>s as a terminator.
1162 * <p>
1163 * Please note that this method doesn't terminate with <code>NUL</code>
1164 * if the input string is longer than <tt>fieldSize</tt>.
1165 *
1166 * @param fieldSize the maximum number of bytes to write
1167 */
1168 public ByteBuffer putString(CharSequence val, int fieldSize,
1169 CharsetEncoder encoder) throws CharacterCodingException {
1170 checkFieldSize(fieldSize);
1171
1172 if (fieldSize == 0)
1173 return this;
1174
1175 autoExpand(fieldSize);
1176
1177 boolean utf16 = encoder.charset().name().startsWith("UTF-16");
1178
1179 if (utf16 && ((fieldSize & 1) != 0)) {
1180 throw new IllegalArgumentException("fieldSize is not even.");
1181 }
1182
1183 int oldLimit = limit();
1184 int end = position() + fieldSize;
1185
1186 if (oldLimit < end) {
1187 throw new BufferOverflowException();
1188 }
1189
1190 if (val.length() == 0) {
1191 if (!utf16) {
1192 put((byte) 0x00);
1193 } else {
1194 put((byte) 0x00);
1195 put((byte) 0x00);
1196 }
1197 position(end);
1198 return this;
1199 }
1200
1201 CharBuffer in = CharBuffer.wrap(val);
1202 limit(end);
1203 encoder.reset();
1204
1205 for (;;) {
1206 CoderResult cr;
1207 if (in.hasRemaining()) {
1208 cr = encoder.encode(in, buf(), true);
1209 } else {
1210 cr = encoder.flush(buf());
1211 }
1212
1213 if (cr.isUnderflow() || cr.isOverflow()) {
1214 break;
1215 }
1216 cr.throwException();
1217 }
1218
1219 limit(oldLimit);
1220
1221 if (position() < end) {
1222 if (!utf16) {
1223 put((byte) 0x00);
1224 } else {
1225 put((byte) 0x00);
1226 put((byte) 0x00);
1227 }
1228 }
1229
1230 position(end);
1231 return this;
1232 }
1233
1234 /**
1235 * Reads a string which has a 16-bit length field before the actual
1236 * encoded string, using the specified <code>decoder</code> and returns it.
1237 * This method is a shortcut for <tt>getPrefixedString(2, decoder)</tt>.
1238 */
1239 public String getPrefixedString(CharsetDecoder decoder)
1240 throws CharacterCodingException {
1241 return getPrefixedString(2, decoder);
1242 }
1243
1244 /**
1245 * Reads a string which has a length field before the actual
1246 * encoded string, using the specified <code>decoder</code> and returns it.
1247 *
1248 * @param prefixLength the length of the length field (1, 2, or 4)
1249 */
1250 public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
1251 throws CharacterCodingException {
1252 if (!prefixedDataAvailable(prefixLength)) {
1253 throw new BufferUnderflowException();
1254 }
1255
1256 int fieldSize = 0;
1257
1258 switch (prefixLength) {
1259 case 1:
1260 fieldSize = getUnsigned();
1261 break;
1262 case 2:
1263 fieldSize = getUnsignedShort();
1264 break;
1265 case 4:
1266 fieldSize = getInt();
1267 break;
1268 }
1269
1270 if (fieldSize == 0) {
1271 return "";
1272 }
1273
1274 boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1275
1276 if (utf16 && ((fieldSize & 1) != 0)) {
1277 throw new BufferDataException(
1278 "fieldSize is not even for a UTF-16 string.");
1279 }
1280
1281 int oldLimit = limit();
1282 int end = position() + fieldSize;
1283
1284 if (oldLimit < end) {
1285 throw new BufferUnderflowException();
1286 }
1287
1288 limit(end);
1289 decoder.reset();
1290
1291 int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1292 CharBuffer out = CharBuffer.allocate(expectedLength);
1293 for (;;) {
1294 CoderResult cr;
1295 if (hasRemaining()) {
1296 cr = decoder.decode(buf(), out, true);
1297 } else {
1298 cr = decoder.flush(out);
1299 }
1300
1301 if (cr.isUnderflow()) {
1302 break;
1303 }
1304
1305 if (cr.isOverflow()) {
1306 CharBuffer o = CharBuffer.allocate(out.capacity()
1307 + expectedLength);
1308 out.flip();
1309 o.put(out);
1310 out = o;
1311 continue;
1312 }
1313
1314 cr.throwException();
1315 }
1316
1317 limit(oldLimit);
1318 position(end);
1319 return out.flip().toString();
1320 }
1321
1322 /**
1323 * Writes the content of <code>in</code> into this buffer as a
1324 * string which has a 16-bit length field before the actual
1325 * encoded string, using the specified <code>encoder</code>.
1326 * This method is a shortcut for <tt>putPrefixedString(in, 2, 0, encoder)</tt>.
1327 *
1328 * @throws BufferOverflowException if the specified string doesn't fit
1329 */
1330 public ByteBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
1331 throws CharacterCodingException {
1332 return putPrefixedString(in, 2, 0, encoder);
1333 }
1334
1335 /**
1336 * Writes the content of <code>in</code> into this buffer as a
1337 * string which has a 16-bit length field before the actual
1338 * encoded string, using the specified <code>encoder</code>.
1339 * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>.
1340 *
1341 * @param prefixLength the length of the length field (1, 2, or 4)
1342 *
1343 * @throws BufferOverflowException if the specified string doesn't fit
1344 */
1345 public ByteBuffer putPrefixedString(CharSequence in, int prefixLength,
1346 CharsetEncoder encoder) throws CharacterCodingException {
1347 return putPrefixedString(in, prefixLength, 0, encoder);
1348 }
1349
1350 /**
1351 * Writes the content of <code>in</code> into this buffer as a
1352 * string which has a 16-bit length field before the actual
1353 * encoded string, using the specified <code>encoder</code>.
1354 * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>.
1355 *
1356 * @param prefixLength the length of the length field (1, 2, or 4)
1357 * @param padding the number of padded <tt>NUL</tt>s (1 (or 0), 2, or 4)
1358 *
1359 * @throws BufferOverflowException if the specified string doesn't fit
1360 */
1361 public ByteBuffer putPrefixedString(CharSequence in, int prefixLength,
1362 int padding, CharsetEncoder encoder)
1363 throws CharacterCodingException {
1364 return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
1365 }
1366
1367 /**
1368 * Writes the content of <code>in</code> into this buffer as a
1369 * string which has a 16-bit length field before the actual
1370 * encoded string, using the specified <code>encoder</code>.
1371 *
1372 * @param prefixLength the length of the length field (1, 2, or 4)
1373 * @param padding the number of padded bytes (1 (or 0), 2, or 4)
1374 * @param padValue the value of padded bytes
1375 *
1376 * @throws BufferOverflowException if the specified string doesn't fit
1377 */
1378 public ByteBuffer putPrefixedString(CharSequence val, int prefixLength,
1379 int padding, byte padValue, CharsetEncoder encoder)
1380 throws CharacterCodingException {
1381 int maxLength;
1382 switch (prefixLength) {
1383 case 1:
1384 maxLength = 255;
1385 break;
1386 case 2:
1387 maxLength = 65535;
1388 break;
1389 case 4:
1390 maxLength = Integer.MAX_VALUE;
1391 break;
1392 default:
1393 throw new IllegalArgumentException("prefixLength: " + prefixLength);
1394 }
1395
1396 if (val.length() > maxLength) {
1397 throw new IllegalArgumentException(
1398 "The specified string is too long.");
1399 }
1400 if (val.length() == 0) {
1401 switch (prefixLength) {
1402 case 1:
1403 put((byte) 0);
1404 break;
1405 case 2:
1406 putShort((short) 0);
1407 break;
1408 case 4:
1409 putInt(0);
1410 break;
1411 }
1412 return this;
1413 }
1414
1415 int padMask;
1416 switch (padding) {
1417 case 0:
1418 case 1:
1419 padMask = 0;
1420 break;
1421 case 2:
1422 padMask = 1;
1423 break;
1424 case 4:
1425 padMask = 3;
1426 break;
1427 default:
1428 throw new IllegalArgumentException("padding: " + padding);
1429 }
1430
1431 CharBuffer in = CharBuffer.wrap(val);
1432 int expectedLength = (int) (in.remaining() * encoder
1433 .averageBytesPerChar()) + 1;
1434
1435 skip(prefixLength); // make a room for the length field
1436 int oldPos = position();
1437 encoder.reset();
1438
1439 for (;;) {
1440 CoderResult cr;
1441 if (in.hasRemaining()) {
1442 cr = encoder.encode(in, buf(), true);
1443 } else {
1444 cr = encoder.flush(buf());
1445 }
1446
1447 if (position() - oldPos > maxLength) {
1448 throw new IllegalArgumentException(
1449 "The specified string is too long.");
1450 }
1451
1452 if (cr.isUnderflow()) {
1453 break;
1454 }
1455 if (cr.isOverflow() && isAutoExpand()) {
1456 autoExpand(expectedLength);
1457 continue;
1458 }
1459 cr.throwException();
1460 }
1461
1462 // Write the length field
1463 fill(padValue, padding - ((position() - oldPos) & padMask));
1464 int length = position() - oldPos;
1465 switch (prefixLength) {
1466 case 1:
1467 put(oldPos - 1, (byte) length);
1468 break;
1469 case 2:
1470 putShort(oldPos - 2, (short) length);
1471 break;
1472 case 4:
1473 putInt(oldPos - 4, length);
1474 break;
1475 }
1476 return this;
1477 }
1478
1479 /**
1480 * Reads a Java object from the buffer using the context {@link ClassLoader}
1481 * of the current thread.
1482 */
1483 public Object getObject() throws ClassNotFoundException {
1484 return getObject(Thread.currentThread().getContextClassLoader());
1485 }
1486
1487 /**
1488 * Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
1489 */
1490 public Object getObject(final ClassLoader classLoader)
1491 throws ClassNotFoundException {
1492 if (!prefixedDataAvailable(4)) {
1493 throw new BufferUnderflowException();
1494 }
1495
1496 int length = getInt();
1497 if (length <= 4) {
1498 throw new BufferDataException(
1499 "Object length should be greater than 4: " + length);
1500 }
1501
1502 int oldLimit = limit();
1503 limit(position() + length);
1504 try {
1505 ObjectInputStream in = new ObjectInputStream(asInputStream()) {
1506 @Override
1507 protected ObjectStreamClass readClassDescriptor()
1508 throws IOException, ClassNotFoundException {
1509 int type = read();
1510 if (type < 0) {
1511 throw new EOFException();
1512 }
1513 switch (type) {
1514 case 0: // Primitive types
1515 return super.readClassDescriptor();
1516 case 1: // Non-primitive types
1517 String className = readUTF();
1518 Class<?> clazz =
1519 Class.forName(className, true, classLoader);
1520 return ObjectStreamClass.lookup(clazz);
1521 default:
1522 throw new StreamCorruptedException(
1523 "Unexpected class descriptor type: " + type);
1524 }
1525 }
1526
1527 @Override
1528 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
1529 String name = desc.getName();
1530 try {
1531 return Class.forName(name, false, classLoader);
1532 } catch (ClassNotFoundException ex) {
1533 return super.resolveClass(desc);
1534 }
1535 }
1536 };
1537 return in.readObject();
1538 } catch (IOException e) {
1539 throw new BufferDataException(e);
1540 } finally {
1541 limit(oldLimit);
1542 }
1543 }
1544
1545 /**
1546 * Writes the specified Java object to the buffer.
1547 */
1548 public ByteBuffer putObject(Object o) {
1549 int oldPos = position();
1550 skip(4); // Make a room for the length field.
1551 try {
1552 ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
1553 @Override
1554 protected void writeClassDescriptor(ObjectStreamClass desc)
1555 throws IOException {
1556 String className = desc.getName();
1557 if (primitiveTypeNames.contains(className)) {
1558 write(0);
1559 super.writeClassDescriptor(desc);
1560 } else {
1561 write(1);
1562 writeUTF(desc.getName());
1563 }
1564 }
1565 };
1566 out.writeObject(o);
1567 out.flush();
1568 } catch (IOException e) {
1569 throw new BufferDataException(e);
1570 }
1571
1572 // Fill the length field
1573 int newPos = position();
1574 position(oldPos);
1575 putInt(newPos - oldPos - 4);
1576 position(newPos);
1577 return this;
1578 }
1579
1580 /**
1581 * Returns <tt>true</tt> if this buffer contains a data which has a data
1582 * length as a prefix and the buffer has remaining data as enough as
1583 * specified in the data length field. This method is identical with
1584 * <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>.
1585 * Please not that using this method can allow DoS (Denial of Service)
1586 * attack in case the remote peer sends too big data length value.
1587 * It is recommended to use {@link #prefixedDataAvailable(int, int)}
1588 * instead.
1589 *
1590 * @param prefixLength the length of the prefix field (1, 2, or 4)
1591 *
1592 * @throws IllegalArgumentException if prefixLength is wrong
1593 * @throws BufferDataException if data length is negative
1594 */
1595 public boolean prefixedDataAvailable(int prefixLength) {
1596 return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
1597 }
1598
1599 /**
1600 * Returns <tt>true</tt> if this buffer contains a data which has a data
1601 * length as a prefix and the buffer has remaining data as enough as
1602 * specified in the data length field.
1603 *
1604 * @param prefixLength the length of the prefix field (1, 2, or 4)
1605 * @param maxDataLength the allowed maximum of the read data length
1606 *
1607 * @throws IllegalArgumentException if prefixLength is wrong
1608 * @throws BufferDataException if data length is negative or greater then <tt>maxDataLength</tt>
1609 */
1610 public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
1611 if (remaining() < prefixLength) {
1612 return false;
1613 }
1614
1615 int dataLength;
1616 switch (prefixLength) {
1617 case 1:
1618 dataLength = getUnsigned(position());
1619 break;
1620 case 2:
1621 dataLength = getUnsignedShort(position());
1622 break;
1623 case 4:
1624 dataLength = getInt(position());
1625 break;
1626 default:
1627 throw new IllegalArgumentException("prefixLength: " + prefixLength);
1628 }
1629
1630 if (dataLength < 0 || dataLength > maxDataLength) {
1631 throw new BufferDataException("dataLength: " + dataLength);
1632 }
1633
1634 return remaining() - prefixLength >= dataLength;
1635 }
1636
1637 //////////////////////////
1638 // Skip or fill methods //
1639 //////////////////////////
1640
1641 /**
1642 * Forwards the position of this buffer as the specified <code>size</code>
1643 * bytes.
1644 */
1645 public ByteBuffer skip(int size) {
1646 autoExpand(size);
1647 return position(position() + size);
1648 }
1649
1650 /**
1651 * Fills this buffer with the specified value.
1652 * This method moves buffer position forward.
1653 */
1654 public ByteBuffer fill(byte value, int size) {
1655 autoExpand(size);
1656 int q = size >>> 3;
1657 int r = size & 7;
1658
1659 if (q > 0) {
1660 int intValue = value | (value << 8) | (value << 16) | (value << 24);
1661 long longValue = intValue;
1662 longValue <<= 32;
1663 longValue |= intValue;
1664
1665 for (int i = q; i > 0; i--) {
1666 putLong(longValue);
1667 }
1668 }
1669
1670 q = r >>> 2;
1671 r = r & 3;
1672
1673 if (q > 0) {
1674 int intValue = value | (value << 8) | (value << 16) | (value << 24);
1675 putInt(intValue);
1676 }
1677
1678 q = r >> 1;
1679 r = r & 1;
1680
1681 if (q > 0) {
1682 short shortValue = (short) (value | (value << 8));
1683 putShort(shortValue);
1684 }
1685
1686 if (r > 0) {
1687 put(value);
1688 }
1689
1690 return this;
1691 }
1692
1693 /**
1694 * Fills this buffer with the specified value.
1695 * This method does not change buffer position.
1696 */
1697 public ByteBuffer fillAndReset(byte value, int size) {
1698 autoExpand(size);
1699 int pos = position();
1700 try {
1701 fill(value, size);
1702 } finally {
1703 position(pos);
1704 }
1705 return this;
1706 }
1707
1708 /**
1709 * Fills this buffer with <code>NUL (0x00)</code>.
1710 * This method moves buffer position forward.
1711 */
1712 public ByteBuffer fill(int size) {
1713 autoExpand(size);
1714 int q = size >>> 3;
1715 int r = size & 7;
1716
1717 for (int i = q; i > 0; i--) {
1718 putLong(0L);
1719 }
1720
1721 q = r >>> 2;
1722 r = r & 3;
1723
1724 if (q > 0) {
1725 putInt(0);
1726 }
1727
1728 q = r >> 1;
1729 r = r & 1;
1730
1731 if (q > 0) {
1732 putShort((short) 0);
1733 }
1734
1735 if (r > 0) {
1736 put((byte) 0);
1737 }
1738
1739 return this;
1740 }
1741
1742 /**
1743 * Fills this buffer with <code>NUL (0x00)</code>.
1744 * This method does not change buffer position.
1745 */
1746 public ByteBuffer fillAndReset(int size) {
1747 autoExpand(size);
1748 int pos = position();
1749 try {
1750 fill(size);
1751 } finally {
1752 position(pos);
1753 }
1754
1755 return this;
1756 }
1757
1758 /**
1759 * This method forwards the call to {@link #expand(int)} only when
1760 * <tt>autoExpand</tt> property is <tt>true</tt>.
1761 */
1762 protected ByteBuffer autoExpand(int expectedRemaining) {
1763 if (isAutoExpand()) {
1764 expand(expectedRemaining);
1765 }
1766 return this;
1767 }
1768
1769 /**
1770 * This method forwards the call to {@link #expand(int)} only when
1771 * <tt>autoExpand</tt> property is <tt>true</tt>.
1772 */
1773 protected ByteBuffer autoExpand(int pos, int expectedRemaining) {
1774 if (isAutoExpand()) {
1775 expand(pos, expectedRemaining);
1776 }
1777 return this;
1778 }
1779
1780 private static void checkFieldSize(int fieldSize) {
1781 if (fieldSize < 0) {
1782 throw new IllegalArgumentException("fieldSize cannot be negative: "
1783 + fieldSize);
1784 }
1785 }
1786 }