View Javadoc
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.core.buffer;
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.Serializable;
30  import java.io.StreamCorruptedException;
31  import java.nio.BufferOverflowException;
32  import java.nio.BufferUnderflowException;
33  import java.nio.ByteBuffer;
34  import java.nio.ByteOrder;
35  import java.nio.CharBuffer;
36  import java.nio.DoubleBuffer;
37  import java.nio.FloatBuffer;
38  import java.nio.IntBuffer;
39  import java.nio.LongBuffer;
40  import java.nio.ShortBuffer;
41  import java.nio.charset.CharacterCodingException;
42  import java.nio.charset.CharsetDecoder;
43  import java.nio.charset.CharsetEncoder;
44  import java.nio.charset.CoderResult;
45  import java.util.EnumSet;
46  import java.util.Set;
47  
48  /**
49   * A base implementation of {@link IoBuffer}.  This implementation
50   * assumes that {@link IoBuffer#buf()} always returns a correct NIO
51   * {@link ByteBuffer} instance.  Most implementations could
52   * extend this class and implement their own buffer management mechanism.
53   *
54   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
55   * @see IoBufferAllocator
56   */
57  public abstract class AbstractIoBuffer extends IoBuffer {
58      /** Tells if a buffer has been created from an existing buffer */
59      private final boolean derived;
60  
61      /** A flag set to true if the buffer can extend automatically */
62      private boolean autoExpand;
63  
64      /** A flag set to true if the buffer can shrink automatically */
65      private boolean autoShrink;
66  
67      /** Tells if a buffer can be expanded */
68      private boolean recapacityAllowed = true;
69  
70      /** The minimum number of bytes the IoBuffer can hold */
71      private int minimumCapacity;
72  
73      /** A mask for a byte */
74      private static final long BYTE_MASK = 0xFFL;
75  
76      /** A mask for a short */
77      private static final long SHORT_MASK = 0xFFFFL;
78  
79      /** A mask for an int */
80      private static final long INT_MASK = 0xFFFFFFFFL;
81  
82      /**
83       * We don't have any access to Buffer.markValue(), so we need to track it down,
84       * which will cause small extra overhead.
85       */
86      private int mark = -1;
87  
88      /**
89       * Creates a new parent buffer.
90       * 
91       * @param allocator The allocator to use to create new buffers
92       * @param initialCapacity The initial buffer capacity when created
93       */
94      protected AbstractIoBuffer(IoBufferAllocator allocator, int initialCapacity) {
95          setAllocator(allocator);
96          this.recapacityAllowed = true;
97          this.derived = false;
98          this.minimumCapacity = initialCapacity;
99      }
100 
101     /**
102      * Creates a new derived buffer. A derived buffer uses an existing
103      * buffer properties - the allocator and capacity -.
104      * 
105      * @param parent The buffer we get the properties from
106      */
107     protected AbstractIoBuffer(AbstractIoBuffer parent) {
108         setAllocator(IoBuffer.getAllocator());
109         this.recapacityAllowed = false;
110         this.derived = true;
111         this.minimumCapacity = parent.minimumCapacity;
112     }
113 
114     /**
115      * {@inheritDoc}
116      */
117     @Override
118     public final boolean isDirect() {
119         return buf().isDirect();
120     }
121 
122     /**
123      * {@inheritDoc}
124      */
125     @Override
126     public final boolean isReadOnly() {
127         return buf().isReadOnly();
128     }
129 
130     /**
131      * Sets the underlying NIO buffer instance.
132      * 
133      * @param newBuf The buffer to store within this IoBuffer
134      */
135     protected abstract void buf(ByteBuffer newBuf);
136 
137     /**
138      * {@inheritDoc}
139      */
140     @Override
141     public final int minimumCapacity() {
142         return minimumCapacity;
143     }
144 
145     /**
146      * {@inheritDoc}
147      */
148     @Override
149     public final IoBuffer minimumCapacity(int minimumCapacity) {
150         if (minimumCapacity < 0) {
151             throw new IllegalArgumentException("minimumCapacity: " + minimumCapacity);
152         }
153         this.minimumCapacity = minimumCapacity;
154         return this;
155     }
156 
157     /**
158      * {@inheritDoc}
159      */
160     @Override
161     public final int capacity() {
162         return buf().capacity();
163     }
164 
165     /**
166      * {@inheritDoc}
167      */
168     @Override
169     public final IoBuffer capacity(int newCapacity) {
170         if (!recapacityAllowed) {
171             throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
172         }
173 
174         // Allocate a new buffer and transfer all settings to it.
175         if (newCapacity > capacity()) {
176             // Expand:
177             //// Save the state.
178             int pos = position();
179             int limit = limit();
180             ByteOrder bo = order();
181 
182             //// Reallocate.
183             ByteBuffer oldBuf = buf();
184             ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
185             oldBuf.clear();
186             newBuf.put(oldBuf);
187             buf(newBuf);
188 
189             //// Restore the state.
190             buf().limit(limit);
191             if (mark >= 0) {
192                 buf().position(mark);
193                 buf().mark();
194             }
195             buf().position(pos);
196             buf().order(bo);
197         }
198 
199         return this;
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
205     @Override
206     public final boolean isAutoExpand() {
207         return autoExpand && recapacityAllowed;
208     }
209 
210     /**
211      * {@inheritDoc}
212      */
213     @Override
214     public final boolean isAutoShrink() {
215         return autoShrink && recapacityAllowed;
216     }
217 
218     /**
219      * {@inheritDoc}
220      */
221     @Override
222     public final boolean isDerived() {
223         return derived;
224     }
225 
226     /**
227      * {@inheritDoc}
228      */
229     @Override
230     public final IoBuffer setAutoExpand(boolean autoExpand) {
231         if (!recapacityAllowed) {
232             throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
233         }
234         this.autoExpand = autoExpand;
235         return this;
236     }
237 
238     /**
239      * {@inheritDoc}
240      */
241     @Override
242     public final IoBuffer setAutoShrink(boolean autoShrink) {
243         if (!recapacityAllowed) {
244             throw new IllegalStateException("Derived buffers and their parent can't be shrinked.");
245         }
246         this.autoShrink = autoShrink;
247         return this;
248     }
249 
250     /**
251      * {@inheritDoc}
252      */
253     @Override
254     public final IoBuffer expand(int expectedRemaining) {
255         return expand(position(), expectedRemaining, false);
256     }
257 
258     private IoBuffer expand(int expectedRemaining, boolean autoExpand) {
259         return expand(position(), expectedRemaining, autoExpand);
260     }
261 
262     /**
263      * {@inheritDoc}
264      */
265     @Override
266     public final IoBuffer expand(int pos, int expectedRemaining) {
267         return expand(pos, expectedRemaining, false);
268     }
269 
270     private IoBuffer expand(int pos, int expectedRemaining, boolean autoExpand) {
271         if (!recapacityAllowed) {
272             throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
273         }
274 
275         int end = pos + expectedRemaining;
276         int newCapacity;
277         
278         if (autoExpand) {
279             newCapacity = IoBuffer.normalizeCapacity(end);
280         } else {
281             newCapacity = end;
282         }
283         if (newCapacity > capacity()) {
284             // The buffer needs expansion.
285             capacity(newCapacity);
286         }
287 
288         if (end > limit()) {
289             // We call limit() directly to prevent StackOverflowError
290             buf().limit(end);
291         }
292         return this;
293     }
294 
295     /**
296      * {@inheritDoc}
297      */
298     @Override
299     public final IoBuffer shrink() {
300 
301         if (!recapacityAllowed) {
302             throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
303         }
304 
305         int position = position();
306         int capacity = capacity();
307         int limit = limit();
308 
309         if (capacity == limit) {
310             return this;
311         }
312 
313         int newCapacity = capacity;
314         int minCapacity = Math.max(minimumCapacity, limit);
315 
316         for (;;) {
317             if (newCapacity >>> 1 < minCapacity) {
318                 break;
319             }
320 
321             newCapacity >>>= 1;
322 
323             if (minCapacity == 0) {
324                 break;
325             }
326         }
327 
328         newCapacity = Math.max(minCapacity, newCapacity);
329 
330         if (newCapacity == capacity) {
331             return this;
332         }
333 
334         // Shrink and compact:
335         //// Save the state.
336         ByteOrder bo = order();
337 
338         //// Reallocate.
339         ByteBuffer oldBuf = buf();
340         ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
341         oldBuf.position(0);
342         oldBuf.limit(limit);
343         newBuf.put(oldBuf);
344         buf(newBuf);
345 
346         //// Restore the state.
347         buf().position(position);
348         buf().limit(limit);
349         buf().order(bo);
350         mark = -1;
351 
352         return this;
353     }
354 
355     /**
356      * {@inheritDoc}
357      */
358     @Override
359     public final int position() {
360         return buf().position();
361     }
362 
363     /**
364      * {@inheritDoc}
365      */
366     @Override
367     public final IoBuffer position(int newPosition) {
368         autoExpand(newPosition, 0);
369         buf().position(newPosition);
370         
371         if (mark > newPosition) {
372             mark = -1;
373         }
374         
375         return this;
376     }
377 
378     /**
379      * {@inheritDoc}
380      */
381     @Override
382     public final int limit() {
383         return buf().limit();
384     }
385 
386     /**
387      * {@inheritDoc}
388      */
389     @Override
390     public final IoBuffer limit(int newLimit) {
391         autoExpand(newLimit, 0);
392         buf().limit(newLimit);
393         if (mark > newLimit) {
394             mark = -1;
395         }
396         return this;
397     }
398 
399     /**
400      * {@inheritDoc}
401      */
402     @Override
403     public final IoBuffer mark() {
404         ByteBuffer byteBuffer = buf();
405         byteBuffer.mark();
406         mark = byteBuffer.position();
407 
408         return this;
409     }
410 
411     /**
412      * {@inheritDoc}
413      */
414     @Override
415     public final int markValue() {
416         return mark;
417     }
418 
419     /**
420      * {@inheritDoc}
421      */
422     @Override
423     public final IoBuffer reset() {
424         buf().reset();
425         return this;
426     }
427 
428     /**
429      * {@inheritDoc}
430      */
431     @Override
432     public final IoBuffer clear() {
433         buf().clear();
434         mark = -1;
435         return this;
436     }
437 
438     /**
439      * {@inheritDoc}
440      */
441     @Override
442     public final IoBuffer sweep() {
443         clear();
444         return fillAndReset(remaining());
445     }
446 
447     /**
448      * {@inheritDoc}
449      */
450     @Override
451     public final IoBuffer sweep(byte value) {
452         clear();
453         return fillAndReset(value, remaining());
454     }
455 
456     /**
457      * {@inheritDoc}
458      */
459     @Override
460     public final IoBuffer flip() {
461         buf().flip();
462         mark = -1;
463         return this;
464     }
465 
466     /**
467      * {@inheritDoc}
468      */
469     @Override
470     public final IoBuffer rewind() {
471         buf().rewind();
472         mark = -1;
473         return this;
474     }
475 
476     /**
477      * {@inheritDoc}
478      */
479     @Override
480     public final int remaining() {
481         ByteBuffer byteBuffer = buf();
482 
483         return byteBuffer.limit() - byteBuffer.position();
484     }
485 
486     /**
487      * {@inheritDoc}
488      */
489     @Override
490     public final boolean hasRemaining() {
491         ByteBuffer byteBuffer = buf();
492 
493         return byteBuffer.limit() > byteBuffer.position();
494     }
495 
496     /**
497      * {@inheritDoc}
498      */
499     @Override
500     public final byte get() {
501         return buf().get();
502     }
503 
504     /**
505      * {@inheritDoc}
506      */
507     @Override
508     public final short getUnsigned() {
509         return (short) (get() & 0xff);
510     }
511 
512     /**
513      * {@inheritDoc}
514      */
515     @Override
516     public final IoBuffer put(byte b) {
517         autoExpand(1);
518         buf().put(b);
519         return this;
520     }
521 
522     /**
523      * {@inheritDoc}
524      */
525     public IoBuffer putUnsigned(byte value) {
526         autoExpand(1);
527         buf().put((byte) (value & 0xff));
528         return this;
529     }
530 
531     /**
532      * {@inheritDoc}
533      */
534     public IoBuffer putUnsigned(int index, byte value) {
535         autoExpand(index, 1);
536         buf().put(index, (byte) (value & 0xff));
537         return this;
538     }
539 
540     /**
541      * {@inheritDoc}
542      */
543     public IoBuffer putUnsigned(short value) {
544         autoExpand(1);
545         buf().put((byte) (value & 0x00ff));
546         return this;
547     }
548 
549     /**
550      * {@inheritDoc}
551      */
552     public IoBuffer putUnsigned(int index, short value) {
553         autoExpand(index, 1);
554         buf().put(index, (byte) (value & 0x00ff));
555         return this;
556     }
557 
558     /**
559      * {@inheritDoc}
560      */
561     public IoBuffer putUnsigned(int value) {
562         autoExpand(1);
563         buf().put((byte) (value & 0x000000ff));
564         return this;
565     }
566 
567     /**
568      * {@inheritDoc}
569      */
570     public IoBuffer putUnsigned(int index, int value) {
571         autoExpand(index, 1);
572         buf().put(index, (byte) (value & 0x000000ff));
573         return this;
574     }
575 
576     /**
577      * {@inheritDoc}
578      */
579     public IoBuffer putUnsigned(long value) {
580         autoExpand(1);
581         buf().put((byte) (value & 0x00000000000000ffL));
582         return this;
583     }
584 
585     /**
586      * {@inheritDoc}
587      */
588     public IoBuffer putUnsigned(int index, long value) {
589         autoExpand(index, 1);
590         buf().put(index, (byte) (value & 0x00000000000000ffL));
591         return this;
592     }
593 
594     /**
595      * {@inheritDoc}
596      */
597     @Override
598     public final byte get(int index) {
599         return buf().get(index);
600     }
601 
602     /**
603      * {@inheritDoc}
604      */
605     @Override
606     public final short getUnsigned(int index) {
607         return (short) (get(index) & 0xff);
608     }
609 
610     /**
611      * {@inheritDoc}
612      */
613     @Override
614     public final IoBuffer put(int index, byte b) {
615         autoExpand(index, 1);
616         buf().put(index, b);
617         return this;
618     }
619 
620     /**
621      * {@inheritDoc}
622      */
623     @Override
624     public final IoBuffer get(byte[] dst, int offset, int length) {
625         buf().get(dst, offset, length);
626         return this;
627     }
628 
629     /**
630      * {@inheritDoc}
631      */
632     @Override
633     public final IoBuffer put(ByteBuffer src) {
634         autoExpand(src.remaining());
635         buf().put(src);
636         return this;
637     }
638 
639     /**
640      * {@inheritDoc}
641      */
642     @Override
643     public final IoBuffer put(byte[] src, int offset, int length) {
644         autoExpand(length);
645         buf().put(src, offset, length);
646         return this;
647     }
648 
649     /**
650      * {@inheritDoc}
651      */
652     @Override
653     public final IoBuffer compact() {
654         int remaining = remaining();
655         int capacity = capacity();
656 
657         if (capacity == 0) {
658             return this;
659         }
660 
661         if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > minimumCapacity) {
662             int newCapacity = capacity;
663             int minCapacity = Math.max(minimumCapacity, remaining << 1);
664             for (;;) {
665                 if (newCapacity >>> 1 < minCapacity) {
666                     break;
667                 }
668                 newCapacity >>>= 1;
669             }
670 
671             newCapacity = Math.max(minCapacity, newCapacity);
672 
673             if (newCapacity == capacity) {
674                 return this;
675             }
676 
677             // Shrink and compact:
678             //// Save the state.
679             ByteOrder bo = order();
680 
681             //// Sanity check.
682             if (remaining > newCapacity) {
683                 throw new IllegalStateException("The amount of the remaining bytes is greater than "
684                         + "the new capacity.");
685             }
686 
687             //// Reallocate.
688             ByteBuffer oldBuf = buf();
689             ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
690             newBuf.put(oldBuf);
691             buf(newBuf);
692 
693             //// Restore the state.
694             buf().order(bo);
695         } else {
696             buf().compact();
697         }
698         mark = -1;
699         return this;
700     }
701 
702     /**
703      * {@inheritDoc}
704      */
705     @Override
706     public final ByteOrder order() {
707         return buf().order();
708     }
709 
710     /**
711      * {@inheritDoc}
712      */
713     @Override
714     public final IoBuffer order(ByteOrder bo) {
715         buf().order(bo);
716         return this;
717     }
718 
719     /**
720      * {@inheritDoc}
721      */
722     @Override
723     public final char getChar() {
724         return buf().getChar();
725     }
726 
727     /**
728      * {@inheritDoc}
729      */
730     @Override
731     public final IoBuffer putChar(char value) {
732         autoExpand(2);
733         buf().putChar(value);
734         return this;
735     }
736 
737     /**
738      * {@inheritDoc}
739      */
740     @Override
741     public final char getChar(int index) {
742         return buf().getChar(index);
743     }
744 
745     /**
746      * {@inheritDoc}
747      */
748     @Override
749     public final IoBuffer putChar(int index, char value) {
750         autoExpand(index, 2);
751         buf().putChar(index, value);
752         return this;
753     }
754 
755     /**
756      * {@inheritDoc}
757      */
758     @Override
759     public final CharBuffer asCharBuffer() {
760         return buf().asCharBuffer();
761     }
762 
763     /**
764      * {@inheritDoc}
765      */
766     @Override
767     public final short getShort() {
768         return buf().getShort();
769     }
770 
771     /**
772      * {@inheritDoc}
773      */
774     @Override
775     public final IoBuffer putShort(short value) {
776         autoExpand(2);
777         buf().putShort(value);
778         return this;
779     }
780 
781     /**
782      * {@inheritDoc}
783      */
784     @Override
785     public final short getShort(int index) {
786         return buf().getShort(index);
787     }
788 
789     /**
790      * {@inheritDoc}
791      */
792     @Override
793     public final IoBuffer putShort(int index, short value) {
794         autoExpand(index, 2);
795         buf().putShort(index, value);
796         return this;
797     }
798 
799     /**
800      * {@inheritDoc}
801      */
802     @Override
803     public final ShortBuffer asShortBuffer() {
804         return buf().asShortBuffer();
805     }
806 
807     /**
808      * {@inheritDoc}
809      */
810     @Override
811     public final int getInt() {
812         return buf().getInt();
813     }
814 
815     /**
816      * {@inheritDoc}
817      */
818     @Override
819     public final IoBuffer putInt(int value) {
820         autoExpand(4);
821         buf().putInt(value);
822         return this;
823     }
824 
825     /**
826      * {@inheritDoc}
827      */
828     @Override
829     public final IoBuffer putUnsignedInt(byte value) {
830         autoExpand(4);
831         buf().putInt((value & 0x00ff));
832         return this;
833     }
834 
835     /**
836      * {@inheritDoc}
837      */
838     @Override
839     public final IoBuffer putUnsignedInt(int index, byte value) {
840         autoExpand(index, 4);
841         buf().putInt(index, (value & 0x00ff));
842         return this;
843     }
844 
845     /**
846      * {@inheritDoc}
847      */
848     @Override
849     public final IoBuffer putUnsignedInt(short value) {
850         autoExpand(4);
851         buf().putInt((value & 0x0000ffff));
852         return this;
853     }
854 
855     /**
856      * {@inheritDoc}
857      */
858     @Override
859     public final IoBuffer putUnsignedInt(int index, short value) {
860         autoExpand(index, 4);
861         buf().putInt(index, (value & 0x0000ffff));
862         return this;
863     }
864 
865     /**
866      * {@inheritDoc}
867      */
868     @Override
869     public final IoBuffer putUnsignedInt(int value) {
870         autoExpand(4);
871         buf().putInt(value);
872         return this;
873     }
874 
875     /**
876      * {@inheritDoc}
877      */
878     @Override
879     public final IoBuffer putUnsignedInt(int index, int value) {
880         autoExpand(index, 4);
881         buf().putInt(index, value);
882         return this;
883     }
884 
885     /**
886      * {@inheritDoc}
887      */
888     @Override
889     public final IoBuffer putUnsignedInt(long value) {
890         autoExpand(4);
891         buf().putInt((int) (value & 0x00000000ffffffff));
892         return this;
893     }
894 
895     /**
896      * {@inheritDoc}
897      */
898     @Override
899     public final IoBuffer putUnsignedInt(int index, long value) {
900         autoExpand(index, 4);
901         buf().putInt(index, (int) (value & 0x00000000ffffffffL));
902         return this;
903     }
904 
905     /**
906      * {@inheritDoc}
907      */
908     @Override
909     public final IoBuffer putUnsignedShort(byte value) {
910         autoExpand(2);
911         buf().putShort((short) (value & 0x00ff));
912         return this;
913     }
914 
915     /**
916      * {@inheritDoc}
917      */
918     @Override
919     public final IoBuffer putUnsignedShort(int index, byte value) {
920         autoExpand(index, 2);
921         buf().putShort(index, (short) (value & 0x00ff));
922         return this;
923     }
924 
925     /**
926      * {@inheritDoc}
927      */
928     @Override
929     public final IoBuffer putUnsignedShort(short value) {
930         autoExpand(2);
931         buf().putShort(value);
932         return this;
933     }
934 
935     /**
936      * {@inheritDoc}
937      */
938     @Override
939     public final IoBuffer putUnsignedShort(int index, short value) {
940         autoExpand(index, 2);
941         buf().putShort(index, value);
942         return this;
943     }
944 
945     /**
946      * {@inheritDoc}
947      */
948     @Override
949     public final IoBuffer putUnsignedShort(int value) {
950         autoExpand(2);
951         buf().putShort((short) value);
952         return this;
953     }
954 
955     /**
956      * {@inheritDoc}
957      */
958     @Override
959     public final IoBuffer putUnsignedShort(int index, int value) {
960         autoExpand(index, 2);
961         buf().putShort(index, (short) value);
962         return this;
963     }
964 
965     /**
966      * {@inheritDoc}
967      */
968     @Override
969     public final IoBuffer putUnsignedShort(long value) {
970         autoExpand(2);
971         buf().putShort((short) (value));
972         return this;
973     }
974 
975     /**
976      * {@inheritDoc}
977      */
978     @Override
979     public final IoBuffer putUnsignedShort(int index, long value) {
980         autoExpand(index, 2);
981         buf().putShort(index, (short) (value));
982         return this;
983     }
984 
985     /**
986      * {@inheritDoc}
987      */
988     @Override
989     public final int getInt(int index) {
990         return buf().getInt(index);
991     }
992 
993     /**
994      * {@inheritDoc}
995      */
996     @Override
997     public final IoBuffer putInt(int index, int value) {
998         autoExpand(index, 4);
999         buf().putInt(index, value);
1000         return this;
1001     }
1002 
1003     /**
1004      * {@inheritDoc}
1005      */
1006     @Override
1007     public final IntBuffer asIntBuffer() {
1008         return buf().asIntBuffer();
1009     }
1010 
1011     /**
1012      * {@inheritDoc}
1013      */
1014     @Override
1015     public final long getLong() {
1016         return buf().getLong();
1017     }
1018 
1019     /**
1020      * {@inheritDoc}
1021      */
1022     @Override
1023     public final IoBuffer putLong(long value) {
1024         autoExpand(8);
1025         buf().putLong(value);
1026         return this;
1027     }
1028 
1029     /**
1030      * {@inheritDoc}
1031      */
1032     @Override
1033     public final long getLong(int index) {
1034         return buf().getLong(index);
1035     }
1036 
1037     /**
1038      * {@inheritDoc}
1039      */
1040     @Override
1041     public final IoBuffer putLong(int index, long value) {
1042         autoExpand(index, 8);
1043         buf().putLong(index, value);
1044         return this;
1045     }
1046 
1047     /**
1048      * {@inheritDoc}
1049      */
1050     @Override
1051     public final LongBuffer asLongBuffer() {
1052         return buf().asLongBuffer();
1053     }
1054 
1055     /**
1056      * {@inheritDoc}
1057      */
1058     @Override
1059     public final float getFloat() {
1060         return buf().getFloat();
1061     }
1062 
1063     /**
1064      * {@inheritDoc}
1065      */
1066     @Override
1067     public final IoBuffer putFloat(float value) {
1068         autoExpand(4);
1069         buf().putFloat(value);
1070         return this;
1071     }
1072 
1073     /**
1074      * {@inheritDoc}
1075      */
1076     @Override
1077     public final float getFloat(int index) {
1078         return buf().getFloat(index);
1079     }
1080 
1081     /**
1082      * {@inheritDoc}
1083      */
1084     @Override
1085     public final IoBuffer putFloat(int index, float value) {
1086         autoExpand(index, 4);
1087         buf().putFloat(index, value);
1088         return this;
1089     }
1090 
1091     /**
1092      * {@inheritDoc}
1093      */
1094     @Override
1095     public final FloatBuffer asFloatBuffer() {
1096         return buf().asFloatBuffer();
1097     }
1098 
1099     /**
1100      * {@inheritDoc}
1101      */
1102     @Override
1103     public final double getDouble() {
1104         return buf().getDouble();
1105     }
1106 
1107     /**
1108      * {@inheritDoc}
1109      */
1110     @Override
1111     public final IoBuffer putDouble(double value) {
1112         autoExpand(8);
1113         buf().putDouble(value);
1114         return this;
1115     }
1116 
1117     /**
1118      * {@inheritDoc}
1119      */
1120     @Override
1121     public final double getDouble(int index) {
1122         return buf().getDouble(index);
1123     }
1124 
1125     /**
1126      * {@inheritDoc}
1127      */
1128     @Override
1129     public final IoBuffer putDouble(int index, double value) {
1130         autoExpand(index, 8);
1131         buf().putDouble(index, value);
1132         return this;
1133     }
1134 
1135     /**
1136      * {@inheritDoc}
1137      */
1138     @Override
1139     public final DoubleBuffer asDoubleBuffer() {
1140         return buf().asDoubleBuffer();
1141     }
1142 
1143     /**
1144      * {@inheritDoc}
1145      */
1146     @Override
1147     public final IoBuffer asReadOnlyBuffer() {
1148         recapacityAllowed = false;
1149         return asReadOnlyBuffer0();
1150     }
1151 
1152     /**
1153      * Implement this method to return the unexpandable read only version of
1154      * this buffer.
1155      * 
1156      * @return the IoBoffer instance
1157      */
1158     protected abstract IoBuffer asReadOnlyBuffer0();
1159 
1160     /**
1161      * {@inheritDoc}
1162      */
1163     @Override
1164     public final IoBuffer duplicate() {
1165         recapacityAllowed = false;
1166         return duplicate0();
1167     }
1168 
1169     /**
1170      * Implement this method to return the unexpandable duplicate of this
1171      * buffer.
1172      * 
1173      * @return the IoBoffer instance
1174      */
1175     protected abstract IoBuffer duplicate0();
1176 
1177     /**
1178      * {@inheritDoc}
1179      */
1180     @Override
1181     public final IoBuffer slice() {
1182         recapacityAllowed = false;
1183         return slice0();
1184     }
1185 
1186     /**
1187      * {@inheritDoc}
1188      */
1189     @Override
1190     public final IoBuffer getSlice(int index, int length) {
1191         if (length < 0) {
1192             throw new IllegalArgumentException("length: " + length);
1193         }
1194 
1195         int pos = position();
1196         int limit = limit();
1197 
1198         if (index > limit) {
1199             throw new IllegalArgumentException("index: " + index);
1200         }
1201 
1202         int endIndex = index + length;
1203 
1204         if (endIndex > limit) {
1205             throw new IndexOutOfBoundsException("index + length (" + endIndex + ") is greater " + "than limit ("
1206                     + limit + ").");
1207         }
1208 
1209         clear();
1210         limit(endIndex);
1211         position(index);
1212 
1213         IoBuffer slice = slice();
1214         limit(limit);
1215         position(pos);
1216 
1217         return slice;
1218     }
1219 
1220     /**
1221      * {@inheritDoc}
1222      */
1223     @Override
1224     public final IoBuffer getSlice(int length) {
1225         if (length < 0) {
1226             throw new IllegalArgumentException("length: " + length);
1227         }
1228         int pos = position();
1229         int limit = limit();
1230         int nextPos = pos + length;
1231         if (limit < nextPos) {
1232             throw new IndexOutOfBoundsException("position + length (" + nextPos + ") is greater " + "than limit ("
1233                     + limit + ").");
1234         }
1235 
1236         limit(pos + length);
1237         IoBuffer slice = slice();
1238         position(nextPos);
1239         limit(limit);
1240         return slice;
1241     }
1242 
1243     /**
1244      * Implement this method to return the unexpandable slice of this
1245      * buffer.
1246      * 
1247      * @return the IoBoffer instance
1248      */
1249     protected abstract IoBuffer slice0();
1250 
1251     /**
1252      * {@inheritDoc}
1253      */
1254     @Override
1255     public int hashCode() {
1256         int h = 1;
1257         int p = position();
1258         for (int i = limit() - 1; i >= p; i--) {
1259             h = 31 * h + get(i);
1260         }
1261         return h;
1262     }
1263 
1264     /**
1265      * {@inheritDoc}
1266      */
1267     @Override
1268     public boolean equals(Object o) {
1269         if (!(o instanceof IoBuffer)) {
1270             return false;
1271         }
1272 
1273         IoBuffer that = (IoBuffer) o;
1274         if (this.remaining() != that.remaining()) {
1275             return false;
1276         }
1277 
1278         int p = this.position();
1279         for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
1280             byte v1 = this.get(i);
1281             byte v2 = that.get(j);
1282             if (v1 != v2) {
1283                 return false;
1284             }
1285         }
1286         return true;
1287     }
1288 
1289     /**
1290      * {@inheritDoc}
1291      */
1292     public int compareTo(IoBuffer that) {
1293         int n = this.position() + Math.min(this.remaining(), that.remaining());
1294         for (int i = this.position(), j = that.position(); i < n; i++, j++) {
1295             byte v1 = this.get(i);
1296             byte v2 = that.get(j);
1297             if (v1 == v2) {
1298                 continue;
1299             }
1300             if (v1 < v2) {
1301                 return -1;
1302             }
1303 
1304             return +1;
1305         }
1306         return this.remaining() - that.remaining();
1307     }
1308 
1309     /**
1310      * {@inheritDoc}
1311      */
1312     @Override
1313     public String toString() {
1314         StringBuilder buf = new StringBuilder();
1315         if (isDirect()) {
1316             buf.append("DirectBuffer");
1317         } else {
1318             buf.append("HeapBuffer");
1319         }
1320         buf.append("[pos=");
1321         buf.append(position());
1322         buf.append(" lim=");
1323         buf.append(limit());
1324         buf.append(" cap=");
1325         buf.append(capacity());
1326         buf.append(": ");
1327         buf.append(getHexDump(16));
1328         buf.append(']');
1329         return buf.toString();
1330     }
1331 
1332     /**
1333      * {@inheritDoc}
1334      */
1335     @Override
1336     public IoBuffer get(byte[] dst) {
1337         return get(dst, 0, dst.length);
1338     }
1339 
1340     /**
1341      * {@inheritDoc}
1342      */
1343     @Override
1344     public IoBuffer put(IoBuffer src) {
1345         return put(src.buf());
1346     }
1347 
1348     /**
1349      * {@inheritDoc}
1350      */
1351     @Override
1352     public IoBuffer put(byte[] src) {
1353         return put(src, 0, src.length);
1354     }
1355 
1356     /**
1357      * {@inheritDoc}
1358      */
1359     @Override
1360     public int getUnsignedShort() {
1361         return getShort() & 0xffff;
1362     }
1363 
1364     /**
1365      * {@inheritDoc}
1366      */
1367     @Override
1368     public int getUnsignedShort(int index) {
1369         return getShort(index) & 0xffff;
1370     }
1371 
1372     /**
1373      * {@inheritDoc}
1374      */
1375     @Override
1376     public long getUnsignedInt() {
1377         return getInt() & 0xffffffffL;
1378     }
1379 
1380     /**
1381      * {@inheritDoc}
1382      */
1383     @Override
1384     public int getMediumInt() {
1385         byte b1 = get();
1386         byte b2 = get();
1387         byte b3 = get();
1388         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1389             return getMediumInt(b1, b2, b3);
1390         }
1391 
1392         return getMediumInt(b3, b2, b1);
1393     }
1394 
1395     /**
1396      * {@inheritDoc}
1397      */
1398     @Override
1399     public int getUnsignedMediumInt() {
1400         int b1 = getUnsigned();
1401         int b2 = getUnsigned();
1402         int b3 = getUnsigned();
1403         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1404             return b1 << 16 | b2 << 8 | b3;
1405         }
1406 
1407         return b3 << 16 | b2 << 8 | b1;
1408     }
1409 
1410     /**
1411      * {@inheritDoc}
1412      */
1413     @Override
1414     public int getMediumInt(int index) {
1415         byte b1 = get(index);
1416         byte b2 = get(index + 1);
1417         byte b3 = get(index + 2);
1418         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1419             return getMediumInt(b1, b2, b3);
1420         }
1421 
1422         return getMediumInt(b3, b2, b1);
1423     }
1424 
1425     /**
1426      * {@inheritDoc}
1427      */
1428     @Override
1429     public int getUnsignedMediumInt(int index) {
1430         int b1 = getUnsigned(index);
1431         int b2 = getUnsigned(index + 1);
1432         int b3 = getUnsigned(index + 2);
1433         
1434         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1435             return b1 << 16 | b2 << 8 | b3;
1436         }
1437 
1438         return b3 << 16 | b2 << 8 | b1;
1439     }
1440 
1441     /**
1442      * {@inheritDoc}
1443      */
1444     private int getMediumInt(byte b1, byte b2, byte b3) {
1445         int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff;
1446         // Check to see if the medium int is negative (high bit in b1 set)
1447         if ((b1 & 0x80) == 0x80) {
1448             // Make the the whole int negative
1449             ret |= 0xff000000;
1450         }
1451         return ret;
1452     }
1453 
1454     /**
1455      * {@inheritDoc}
1456      */
1457     @Override
1458     public IoBuffer putMediumInt(int value) {
1459         byte b1 = (byte) (value >> 16);
1460         byte b2 = (byte) (value >> 8);
1461         byte b3 = (byte) value;
1462 
1463         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1464             put(b1).put(b2).put(b3);
1465         } else {
1466             put(b3).put(b2).put(b1);
1467         }
1468 
1469         return this;
1470     }
1471 
1472     /**
1473      * {@inheritDoc}
1474      */
1475     @Override
1476     public IoBuffer putMediumInt(int index, int value) {
1477         byte b1 = (byte) (value >> 16);
1478         byte b2 = (byte) (value >> 8);
1479         byte b3 = (byte) value;
1480 
1481         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1482             put(index, b1).put(index + 1, b2).put(index + 2, b3);
1483         } else {
1484             put(index, b3).put(index + 1, b2).put(index + 2, b1);
1485         }
1486 
1487         return this;
1488     }
1489 
1490     /**
1491      * {@inheritDoc}
1492      */
1493     @Override
1494     public long getUnsignedInt(int index) {
1495         return getInt(index) & 0xffffffffL;
1496     }
1497 
1498     /**
1499      * {@inheritDoc}
1500      */
1501     @Override
1502     public InputStream asInputStream() {
1503         return new InputStream() {
1504             @Override
1505             public int available() {
1506                 return AbstractIoBuffer.this.remaining();
1507             }
1508 
1509             @Override
1510             public synchronized void mark(int readlimit) {
1511                 AbstractIoBuffer.this.mark();
1512             }
1513 
1514             @Override
1515             public boolean markSupported() {
1516                 return true;
1517             }
1518 
1519             @Override
1520             public int read() {
1521                 if (AbstractIoBuffer.this.hasRemaining()) {
1522                     return AbstractIoBuffer.this.get() & 0xff;
1523                 }
1524 
1525                 return -1;
1526             }
1527 
1528             @Override
1529             public int read(byte[] b, int off, int len) {
1530                 int remaining = AbstractIoBuffer.this.remaining();
1531                 if (remaining > 0) {
1532                     int readBytes = Math.min(remaining, len);
1533                     AbstractIoBuffer.this.get(b, off, readBytes);
1534                     return readBytes;
1535                 }
1536 
1537                 return -1;
1538             }
1539 
1540             @Override
1541             public synchronized void reset() {
1542                 AbstractIoBuffer.this.reset();
1543             }
1544 
1545             @Override
1546             public long skip(long n) {
1547                 int bytes;
1548                 if (n > Integer.MAX_VALUE) {
1549                     bytes = AbstractIoBuffer.this.remaining();
1550                 } else {
1551                     bytes = Math.min(AbstractIoBuffer.this.remaining(), (int) n);
1552                 }
1553                 AbstractIoBuffer.this.skip(bytes);
1554                 return bytes;
1555             }
1556         };
1557     }
1558 
1559     /**
1560      * {@inheritDoc}
1561      */
1562     @Override
1563     public OutputStream asOutputStream() {
1564         return new OutputStream() {
1565             @Override
1566             public void write(byte[] b, int off, int len) {
1567                 AbstractIoBuffer.this.put(b, off, len);
1568             }
1569 
1570             @Override
1571             public void write(int b) {
1572                 AbstractIoBuffer.this.put((byte) b);
1573             }
1574         };
1575     }
1576 
1577     /**
1578      * {@inheritDoc}
1579      */
1580     @Override
1581     public String getHexDump() {
1582         return this.getHexDump(Integer.MAX_VALUE);
1583     }
1584 
1585     /**
1586      * {@inheritDoc}
1587      */
1588     @Override
1589     public String getHexDump(int lengthLimit) {
1590         return IoBufferHexDumper.getHexdump(this, lengthLimit);
1591     }
1592 
1593     /**
1594      * {@inheritDoc}
1595      */
1596     @Override
1597     public String getString(CharsetDecoder decoder) throws CharacterCodingException {
1598         if (!hasRemaining()) {
1599             return "";
1600         }
1601 
1602         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1603 
1604         int oldPos = position();
1605         int oldLimit = limit();
1606         int end = -1;
1607         int newPos;
1608 
1609         if (!utf16) {
1610             end = indexOf((byte) 0x00);
1611             if (end < 0) {
1612                 newPos = end = oldLimit;
1613             } else {
1614                 newPos = end + 1;
1615             }
1616         } else {
1617             int i = oldPos;
1618             for (;;) {
1619                 boolean wasZero = get(i) == 0;
1620                 i++;
1621 
1622                 if (i >= oldLimit) {
1623                     break;
1624                 }
1625 
1626                 if (get(i) != 0) {
1627                     i++;
1628                     if (i >= oldLimit) {
1629                         break;
1630                     }
1631 
1632                     continue;
1633                 }
1634 
1635                 if (wasZero) {
1636                     end = i - 1;
1637                     break;
1638                 }
1639             }
1640 
1641             if (end < 0) {
1642                 newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE);
1643             } else {
1644                 if (end + 2 <= oldLimit) {
1645                     newPos = end + 2;
1646                 } else {
1647                     newPos = end;
1648                 }
1649             }
1650         }
1651 
1652         if (oldPos == end) {
1653             position(newPos);
1654             return "";
1655         }
1656 
1657         limit(end);
1658         decoder.reset();
1659 
1660         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1661         CharBuffer out = CharBuffer.allocate(expectedLength);
1662         for (;;) {
1663             CoderResult cr;
1664             if (hasRemaining()) {
1665                 cr = decoder.decode(buf(), out, true);
1666             } else {
1667                 cr = decoder.flush(out);
1668             }
1669 
1670             if (cr.isUnderflow()) {
1671                 break;
1672             }
1673 
1674             if (cr.isOverflow()) {
1675                 CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
1676                 out.flip();
1677                 o.put(out);
1678                 out = o;
1679                 continue;
1680             }
1681 
1682             if (cr.isError()) {
1683                 // Revert the buffer back to the previous state.
1684                 limit(oldLimit);
1685                 position(oldPos);
1686                 cr.throwException();
1687             }
1688         }
1689 
1690         limit(oldLimit);
1691         position(newPos);
1692         return out.flip().toString();
1693     }
1694 
1695     /**
1696      * {@inheritDoc}
1697      */
1698     @Override
1699     public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException {
1700         checkFieldSize(fieldSize);
1701 
1702         if (fieldSize == 0) {
1703             return "";
1704         }
1705 
1706         if (!hasRemaining()) {
1707             return "";
1708         }
1709 
1710         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1711 
1712         if (utf16 && (fieldSize & 1) != 0) {
1713             throw new IllegalArgumentException("fieldSize is not even.");
1714         }
1715 
1716         int oldPos = position();
1717         int oldLimit = limit();
1718         int end = oldPos + fieldSize;
1719 
1720         if (oldLimit < end) {
1721             throw new BufferUnderflowException();
1722         }
1723 
1724         int i;
1725 
1726         if (!utf16) {
1727             for (i = oldPos; i < end; i++) {
1728                 if (get(i) == 0) {
1729                     break;
1730                 }
1731             }
1732 
1733             if (i == end) {
1734                 limit(end);
1735             } else {
1736                 limit(i);
1737             }
1738         } else {
1739             for (i = oldPos; i < end; i += 2) {
1740                 if (get(i) == 0 && get(i + 1) == 0) {
1741                     break;
1742                 }
1743             }
1744 
1745             if (i == end) {
1746                 limit(end);
1747             } else {
1748                 limit(i);
1749             }
1750         }
1751 
1752         if (!hasRemaining()) {
1753             limit(oldLimit);
1754             position(end);
1755             return "";
1756         }
1757         decoder.reset();
1758 
1759         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1760         CharBuffer out = CharBuffer.allocate(expectedLength);
1761         for (;;) {
1762             CoderResult cr;
1763             if (hasRemaining()) {
1764                 cr = decoder.decode(buf(), out, true);
1765             } else {
1766                 cr = decoder.flush(out);
1767             }
1768 
1769             if (cr.isUnderflow()) {
1770                 break;
1771             }
1772 
1773             if (cr.isOverflow()) {
1774                 CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
1775                 out.flip();
1776                 o.put(out);
1777                 out = o;
1778                 continue;
1779             }
1780 
1781             if (cr.isError()) {
1782                 // Revert the buffer back to the previous state.
1783                 limit(oldLimit);
1784                 position(oldPos);
1785                 cr.throwException();
1786             }
1787         }
1788 
1789         limit(oldLimit);
1790         position(end);
1791         return out.flip().toString();
1792     }
1793 
1794     /**
1795      * {@inheritDoc}
1796      */
1797     @Override
1798     public IoBuffer putString(CharSequence val, CharsetEncoder encoder) throws CharacterCodingException {
1799         if (val.length() == 0) {
1800             return this;
1801         }
1802 
1803         CharBuffer in = CharBuffer.wrap(val);
1804         encoder.reset();
1805 
1806         int expandedState = 0;
1807 
1808         for (;;) {
1809             CoderResult cr;
1810             if (in.hasRemaining()) {
1811                 cr = encoder.encode(in, buf(), true);
1812             } else {
1813                 cr = encoder.flush(buf());
1814             }
1815 
1816             if (cr.isUnderflow()) {
1817                 break;
1818             }
1819             if (cr.isOverflow()) {
1820                 if (isAutoExpand()) {
1821                     switch (expandedState) {
1822                     case 0:
1823                         autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
1824                         expandedState++;
1825                         break;
1826                     case 1:
1827                         autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
1828                         expandedState++;
1829                         break;
1830                     default:
1831                         throw new RuntimeException("Expanded by "
1832                                 + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
1833                                 + " but that wasn't enough for '" + val + "'");
1834                     }
1835                     continue;
1836                 }
1837             } else {
1838                 expandedState = 0;
1839             }
1840             cr.throwException();
1841         }
1842         return this;
1843     }
1844 
1845     /**
1846      * {@inheritDoc}
1847      */
1848     @Override
1849     public IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder) throws CharacterCodingException {
1850         checkFieldSize(fieldSize);
1851 
1852         if (fieldSize == 0) {
1853             return this;
1854         }
1855 
1856         autoExpand(fieldSize);
1857 
1858         boolean utf16 = encoder.charset().name().startsWith("UTF-16");
1859 
1860         if (utf16 && (fieldSize & 1) != 0) {
1861             throw new IllegalArgumentException("fieldSize is not even.");
1862         }
1863 
1864         int oldLimit = limit();
1865         int end = position() + fieldSize;
1866 
1867         if (oldLimit < end) {
1868             throw new BufferOverflowException();
1869         }
1870 
1871         if (val.length() == 0) {
1872             if (!utf16) {
1873                 put((byte) 0x00);
1874             } else {
1875                 put((byte) 0x00);
1876                 put((byte) 0x00);
1877             }
1878             position(end);
1879             return this;
1880         }
1881 
1882         CharBuffer in = CharBuffer.wrap(val);
1883         limit(end);
1884         encoder.reset();
1885 
1886         for (;;) {
1887             CoderResult cr;
1888             if (in.hasRemaining()) {
1889                 cr = encoder.encode(in, buf(), true);
1890             } else {
1891                 cr = encoder.flush(buf());
1892             }
1893 
1894             if (cr.isUnderflow() || cr.isOverflow()) {
1895                 break;
1896             }
1897             cr.throwException();
1898         }
1899 
1900         limit(oldLimit);
1901 
1902         if (position() < end) {
1903             if (!utf16) {
1904                 put((byte) 0x00);
1905             } else {
1906                 put((byte) 0x00);
1907                 put((byte) 0x00);
1908             }
1909         }
1910 
1911         position(end);
1912         return this;
1913     }
1914 
1915     /**
1916      * {@inheritDoc}
1917      */
1918     @Override
1919     public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException {
1920         return getPrefixedString(2, decoder);
1921     }
1922 
1923     /**
1924      * Reads a string which has a length field before the actual
1925      * encoded string, using the specified <code>decoder</code> and returns it.
1926      *
1927      * @param prefixLength the length of the length field (1, 2, or 4)
1928      * @param decoder the decoder to use for decoding the string
1929      * @return the prefixed string
1930      * @throws CharacterCodingException when decoding fails
1931      * @throws BufferUnderflowException when there is not enough data available
1932      */
1933     @Override
1934     public String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException {
1935         if (!prefixedDataAvailable(prefixLength)) {
1936             throw new BufferUnderflowException();
1937         }
1938 
1939         int fieldSize = 0;
1940 
1941         switch (prefixLength) {
1942         case 1:
1943             fieldSize = getUnsigned();
1944             break;
1945         case 2:
1946             fieldSize = getUnsignedShort();
1947             break;
1948         case 4:
1949             fieldSize = getInt();
1950             break;
1951         }
1952 
1953         if (fieldSize == 0) {
1954             return "";
1955         }
1956 
1957         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1958 
1959         if (utf16 && (fieldSize & 1) != 0) {
1960             throw new BufferDataException("fieldSize is not even for a UTF-16 string.");
1961         }
1962 
1963         int oldLimit = limit();
1964         int end = position() + fieldSize;
1965 
1966         if (oldLimit < end) {
1967             throw new BufferUnderflowException();
1968         }
1969 
1970         limit(end);
1971         decoder.reset();
1972 
1973         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1974         CharBuffer out = CharBuffer.allocate(expectedLength);
1975         for (;;) {
1976             CoderResult cr;
1977             if (hasRemaining()) {
1978                 cr = decoder.decode(buf(), out, true);
1979             } else {
1980                 cr = decoder.flush(out);
1981             }
1982 
1983             if (cr.isUnderflow()) {
1984                 break;
1985             }
1986 
1987             if (cr.isOverflow()) {
1988                 CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
1989                 out.flip();
1990                 o.put(out);
1991                 out = o;
1992                 continue;
1993             }
1994 
1995             cr.throwException();
1996         }
1997 
1998         limit(oldLimit);
1999         position(end);
2000         return out.flip().toString();
2001     }
2002 
2003     /**
2004      * {@inheritDoc}
2005      */
2006     @Override
2007     public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder) throws CharacterCodingException {
2008         return putPrefixedString(in, 2, 0, encoder);
2009     }
2010 
2011     /**
2012      * {@inheritDoc}
2013      */
2014     @Override
2015     public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
2016             throws CharacterCodingException {
2017         return putPrefixedString(in, prefixLength, 0, encoder);
2018     }
2019 
2020     /**
2021      * {@inheritDoc}
2022      */
2023     @Override
2024     public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding, CharsetEncoder encoder)
2025             throws CharacterCodingException {
2026         return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
2027     }
2028 
2029     /**
2030      * {@inheritDoc}
2031      */
2032     @Override
2033     public IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue,
2034             CharsetEncoder encoder) throws CharacterCodingException {
2035         int maxLength;
2036         switch (prefixLength) {
2037         case 1:
2038             maxLength = 255;
2039             break;
2040         case 2:
2041             maxLength = 65535;
2042             break;
2043         case 4:
2044             maxLength = Integer.MAX_VALUE;
2045             break;
2046         default:
2047             throw new IllegalArgumentException("prefixLength: " + prefixLength);
2048         }
2049 
2050         if (val.length() > maxLength) {
2051             throw new IllegalArgumentException("The specified string is too long.");
2052         }
2053         if (val.length() == 0) {
2054             switch (prefixLength) {
2055             case 1:
2056                 put((byte) 0);
2057                 break;
2058             case 2:
2059                 putShort((short) 0);
2060                 break;
2061             case 4:
2062                 putInt(0);
2063                 break;
2064             }
2065             return this;
2066         }
2067 
2068         int padMask;
2069         switch (padding) {
2070         case 0:
2071         case 1:
2072             padMask = 0;
2073             break;
2074         case 2:
2075             padMask = 1;
2076             break;
2077         case 4:
2078             padMask = 3;
2079             break;
2080         default:
2081             throw new IllegalArgumentException("padding: " + padding);
2082         }
2083 
2084         CharBuffer in = CharBuffer.wrap(val);
2085         skip(prefixLength); // make a room for the length field
2086         int oldPos = position();
2087         encoder.reset();
2088 
2089         int expandedState = 0;
2090 
2091         for (;;) {
2092             CoderResult cr;
2093             if (in.hasRemaining()) {
2094                 cr = encoder.encode(in, buf(), true);
2095             } else {
2096                 cr = encoder.flush(buf());
2097             }
2098 
2099             if (position() - oldPos > maxLength) {
2100                 throw new IllegalArgumentException("The specified string is too long.");
2101             }
2102 
2103             if (cr.isUnderflow()) {
2104                 break;
2105             }
2106             if (cr.isOverflow()) {
2107                 if (isAutoExpand()) {
2108                     switch (expandedState) {
2109                     case 0:
2110                         autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
2111                         expandedState++;
2112                         break;
2113                     case 1:
2114                         autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
2115                         expandedState++;
2116                         break;
2117                     default:
2118                         throw new RuntimeException("Expanded by "
2119                                 + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
2120                                 + " but that wasn't enough for '" + val + "'");
2121                     }
2122                     continue;
2123                 }
2124             } else {
2125                 expandedState = 0;
2126             }
2127             cr.throwException();
2128         }
2129 
2130         // Write the length field
2131         fill(padValue, padding - (position() - oldPos & padMask));
2132         int length = position() - oldPos;
2133         switch (prefixLength) {
2134         case 1:
2135             put(oldPos - 1, (byte) length);
2136             break;
2137         case 2:
2138             putShort(oldPos - 2, (short) length);
2139             break;
2140         case 4:
2141             putInt(oldPos - 4, length);
2142             break;
2143         }
2144         return this;
2145     }
2146 
2147     /**
2148      * {@inheritDoc}
2149      */
2150     @Override
2151     public Object getObject() throws ClassNotFoundException {
2152         return getObject(Thread.currentThread().getContextClassLoader());
2153     }
2154 
2155     /**
2156      * {@inheritDoc}
2157      */
2158     @Override
2159     public Object getObject(final ClassLoader classLoader) throws ClassNotFoundException {
2160         if (!prefixedDataAvailable(4)) {
2161             throw new BufferUnderflowException();
2162         }
2163 
2164         int length = getInt();
2165         if (length <= 4) {
2166             throw new BufferDataException("Object length should be greater than 4: " + length);
2167         }
2168 
2169         int oldLimit = limit();
2170         limit(position() + length);
2171         ObjectInputStream in = null;
2172         
2173         try {
2174             in = new ObjectInputStream(asInputStream()) {
2175                 @Override
2176                 protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
2177                     int type = read();
2178                     if (type < 0) {
2179                         throw new EOFException();
2180                     }
2181                     switch (type) {
2182                     case 0: // NON-Serializable class or Primitive types
2183                         return super.readClassDescriptor();
2184                     case 1: // Serializable class
2185                         String className = readUTF();
2186                         Class<?> clazz = Class.forName(className, true, classLoader);
2187                         return ObjectStreamClass.lookup(clazz);
2188                     default:
2189                         throw new StreamCorruptedException("Unexpected class descriptor type: " + type);
2190                     }
2191                 }
2192 
2193                 @Override
2194                 protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
2195                     Class<?> clazz = desc.forClass();
2196                     
2197                     if (clazz == null) {
2198                         String name = desc.getName();
2199                         try {
2200                             return Class.forName(name, false, classLoader);
2201                         } catch (ClassNotFoundException ex) {
2202                             return super.resolveClass(desc);
2203                         }
2204                     } else {
2205                         return clazz;
2206                     }
2207                 }
2208             };
2209             return in.readObject();
2210         } catch (IOException e) {
2211             throw new BufferDataException(e);
2212         } finally {
2213             try {
2214                 if (in != null) {
2215                     in.close();
2216                 }
2217             } catch (IOException ioe) {
2218                 // Nothing to do
2219             }
2220             
2221             limit(oldLimit);
2222         }
2223     }
2224 
2225     /**
2226      * {@inheritDoc}
2227      */
2228     @Override
2229     public IoBuffer putObject(Object o) {
2230         int oldPos = position();
2231         skip(4); // Make a room for the length field.
2232         ObjectOutputStream out = null;
2233         
2234         try {
2235             out = new ObjectOutputStream(asOutputStream()) {
2236                 @Override
2237                 protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
2238                     Class<?> clazz = desc.forClass();
2239                     
2240                     if (clazz.isArray() || clazz.isPrimitive() || !Serializable.class.isAssignableFrom(clazz)) {
2241                         write(0);
2242                         super.writeClassDescriptor(desc); 
2243                     } else {
2244                         // Serializable class
2245                         write(1);
2246                         writeUTF(desc.getName());                            
2247                     }
2248                 }
2249             };
2250             out.writeObject(o);
2251             out.flush();
2252         } catch (IOException e) {
2253             throw new BufferDataException(e);
2254         } finally {
2255             try {
2256                 if (out != null) {
2257                     out.close();
2258                 }
2259             } catch (IOException ioe) {
2260                 // Nothing to do
2261             }
2262         }
2263 
2264         // Fill the length field
2265         int newPos = position();
2266         position(oldPos);
2267         putInt(newPos - oldPos - 4);
2268         position(newPos);
2269         return this;
2270     }
2271 
2272     /**
2273      * {@inheritDoc}
2274      */
2275     @Override
2276     public boolean prefixedDataAvailable(int prefixLength) {
2277         return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
2278     }
2279 
2280     /**
2281      * {@inheritDoc}
2282      */
2283     @Override
2284     public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
2285         if (remaining() < prefixLength) {
2286             return false;
2287         }
2288 
2289         int dataLength;
2290         switch (prefixLength) {
2291         case 1:
2292             dataLength = getUnsigned(position());
2293             break;
2294         case 2:
2295             dataLength = getUnsignedShort(position());
2296             break;
2297         case 4:
2298             dataLength = getInt(position());
2299             break;
2300         default:
2301             throw new IllegalArgumentException("prefixLength: " + prefixLength);
2302         }
2303 
2304         if (dataLength < 0 || dataLength > maxDataLength) {
2305             throw new BufferDataException("dataLength: " + dataLength);
2306         }
2307 
2308         return remaining() - prefixLength >= dataLength;
2309     }
2310 
2311     /**
2312      * {@inheritDoc}
2313      */
2314     @Override
2315     public int indexOf(byte b) {
2316         if (hasArray()) {
2317             int arrayOffset = arrayOffset();
2318             int beginPos = arrayOffset + position();
2319             int limit = arrayOffset + limit();
2320             byte[] array = array();
2321 
2322             for (int i = beginPos; i < limit; i++) {
2323                 if (array[i] == b) {
2324                     return i - arrayOffset;
2325                 }
2326             }
2327         } else {
2328             int beginPos = position();
2329             int limit = limit();
2330 
2331             for (int i = beginPos; i < limit; i++) {
2332                 if (get(i) == b) {
2333                     return i;
2334                 }
2335             }
2336         }
2337 
2338         return -1;
2339     }
2340 
2341     /**
2342      * {@inheritDoc}
2343      */
2344     @Override
2345     public IoBuffer skip(int size) {
2346         autoExpand(size);
2347         return position(position() + size);
2348     }
2349 
2350     /**
2351      * {@inheritDoc}
2352      */
2353     @Override
2354     public IoBuffer fill(byte value, int size) {
2355         autoExpand(size);
2356         int q = size >>> 3;
2357             int r = size & 7;
2358 
2359             if (q > 0) {
2360                 int intValue = value & 0x000000FF | ( value << 8 ) & 0x0000FF00 | ( value << 16 ) & 0x00FF0000 | value << 24;
2361                 long longValue = intValue & 0x00000000FFFFFFFFL | (long)intValue << 32;
2362 
2363                 for (int i = q; i > 0; i--) {
2364                     putLong(longValue);
2365                 }
2366             }
2367 
2368             q = r >>> 2;
2369                 r = r & 3;
2370 
2371                 if (q > 0) {
2372                     int intValue = value & 0x000000FF | ( value << 8 ) & 0x0000FF00 | ( value << 16 ) & 0x00FF0000 | value << 24;
2373                     putInt(intValue);
2374                 }
2375 
2376                 q = r >> 1;
2377                     r = r & 1;
2378 
2379                     if (q > 0) {
2380                         short shortValue = (short) (value & 0x000FF | value << 8);
2381                         putShort(shortValue);
2382                     }
2383 
2384                     if (r > 0) {
2385                         put(value);
2386                     }
2387 
2388                     return this;
2389     }
2390 
2391     /**
2392      * {@inheritDoc}
2393      */
2394     @Override
2395     public IoBuffer fillAndReset(byte value, int size) {
2396         autoExpand(size);
2397         int pos = position();
2398         try {
2399             fill(value, size);
2400         } finally {
2401             position(pos);
2402         }
2403         return this;
2404     }
2405 
2406     /**
2407      * {@inheritDoc}
2408      */
2409     @Override
2410     public IoBuffer fill(int size) {
2411         autoExpand(size);
2412         int q = size >>> 3;
2413                     int r = size & 7;
2414 
2415                     for (int i = q; i > 0; i--) {
2416                         putLong(0L);
2417                     }
2418 
2419                     q = r >>> 2;
2420                 r = r & 3;
2421 
2422                 if (q > 0) {
2423                     putInt(0);
2424                 }
2425 
2426                 q = r >> 1;
2427             r = r & 1;
2428 
2429             if (q > 0) {
2430                 putShort((short) 0);
2431             }
2432 
2433             if (r > 0) {
2434                 put((byte) 0);
2435             }
2436 
2437             return this;
2438     }
2439 
2440     /**
2441      * {@inheritDoc}
2442      */
2443     @Override
2444     public IoBuffer fillAndReset(int size) {
2445         autoExpand(size);
2446         int pos = position();
2447         try {
2448             fill(size);
2449         } finally {
2450             position(pos);
2451         }
2452 
2453         return this;
2454     }
2455 
2456     /**
2457      * {@inheritDoc}
2458      */
2459     @Override
2460     public <E extends Enum<E>> E getEnum(Class<E> enumClass) {
2461         return toEnum(enumClass, getUnsigned());
2462     }
2463 
2464     /**
2465      * {@inheritDoc}
2466      */
2467     @Override
2468     public <E extends Enum<E>> E getEnum(int index, Class<E> enumClass) {
2469         return toEnum(enumClass, getUnsigned(index));
2470     }
2471 
2472     /**
2473      * {@inheritDoc}
2474      */
2475     @Override
2476     public <E extends Enum<E>> E getEnumShort(Class<E> enumClass) {
2477         return toEnum(enumClass, getUnsignedShort());
2478     }
2479 
2480     /**
2481      * {@inheritDoc}
2482      */
2483     @Override
2484     public <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass) {
2485         return toEnum(enumClass, getUnsignedShort(index));
2486     }
2487 
2488     /**
2489      * {@inheritDoc}
2490      */
2491     @Override
2492     public <E extends Enum<E>> E getEnumInt(Class<E> enumClass) {
2493         return toEnum(enumClass, getInt());
2494     }
2495 
2496     /**
2497      * {@inheritDoc}
2498      */
2499     public <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass) {
2500         return toEnum(enumClass, getInt(index));
2501     }
2502 
2503     /**
2504      * {@inheritDoc}
2505      */
2506     @Override
2507     public IoBuffer putEnum(Enum<?> e) {
2508         if (e.ordinal() > BYTE_MASK) {
2509             throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
2510         }
2511         return put((byte) e.ordinal());
2512     }
2513 
2514     /**
2515      * {@inheritDoc}
2516      */
2517     @Override
2518     public IoBuffer putEnum(int index, Enum<?> e) {
2519         if (e.ordinal() > BYTE_MASK) {
2520             throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
2521         }
2522         return put(index, (byte) e.ordinal());
2523     }
2524 
2525     /**
2526      * {@inheritDoc}
2527      */
2528     @Override
2529     public IoBuffer putEnumShort(Enum<?> e) {
2530         if (e.ordinal() > SHORT_MASK) {
2531             throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
2532         }
2533         return putShort((short) e.ordinal());
2534     }
2535 
2536     /**
2537      * {@inheritDoc}
2538      */
2539     @Override
2540     public IoBuffer putEnumShort(int index, Enum<?> e) {
2541         if (e.ordinal() > SHORT_MASK) {
2542             throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
2543         }
2544         return putShort(index, (short) e.ordinal());
2545     }
2546 
2547     /**
2548      * {@inheritDoc}
2549      */
2550     @Override
2551     public IoBuffer putEnumInt(Enum<?> e) {
2552         return putInt(e.ordinal());
2553     }
2554 
2555     /**
2556      * {@inheritDoc}
2557      */
2558     @Override
2559     public IoBuffer putEnumInt(int index, Enum<?> e) {
2560         return putInt(index, e.ordinal());
2561     }
2562 
2563     private <E> E toEnum(Class<E> enumClass, int i) {
2564         E[] enumConstants = enumClass.getEnumConstants();
2565         if (i > enumConstants.length) {
2566             throw new IndexOutOfBoundsException(String.format(
2567                     "%d is too large of an ordinal to convert to the enum %s", i, enumClass.getName()));
2568         }
2569         return enumConstants[i];
2570     }
2571 
2572     private String enumConversionErrorMessage(Enum<?> e, String type) {
2573         return String.format("%s.%s has an ordinal value too large for a %s", e.getClass().getName(), e.name(), type);
2574     }
2575 
2576     /**
2577      * {@inheritDoc}
2578      */
2579     @Override
2580     public <E extends Enum<E>> EnumSet<E> getEnumSet(Class<E> enumClass) {
2581         return toEnumSet(enumClass, get() & BYTE_MASK);
2582     }
2583 
2584     /**
2585      * {@inheritDoc}
2586      */
2587     @Override
2588     public <E extends Enum<E>> EnumSet<E> getEnumSet(int index, Class<E> enumClass) {
2589         return toEnumSet(enumClass, get(index) & BYTE_MASK);
2590     }
2591 
2592     /**
2593      * {@inheritDoc}
2594      */
2595     @Override
2596     public <E extends Enum<E>> EnumSet<E> getEnumSetShort(Class<E> enumClass) {
2597         return toEnumSet(enumClass, getShort() & SHORT_MASK);
2598     }
2599 
2600     /**
2601      * {@inheritDoc}
2602      */
2603     @Override
2604     public <E extends Enum<E>> EnumSet<E> getEnumSetShort(int index, Class<E> enumClass) {
2605         return toEnumSet(enumClass, getShort(index) & SHORT_MASK);
2606     }
2607 
2608     /**
2609      * {@inheritDoc}
2610      */
2611     @Override
2612     public <E extends Enum<E>> EnumSet<E> getEnumSetInt(Class<E> enumClass) {
2613         return toEnumSet(enumClass, getInt() & INT_MASK);
2614     }
2615 
2616     /**
2617      * {@inheritDoc}
2618      */
2619     @Override
2620     public <E extends Enum<E>> EnumSet<E> getEnumSetInt(int index, Class<E> enumClass) {
2621         return toEnumSet(enumClass, getInt(index) & INT_MASK);
2622     }
2623 
2624     /**
2625      * {@inheritDoc}
2626      */
2627     @Override
2628     public <E extends Enum<E>> EnumSet<E> getEnumSetLong(Class<E> enumClass) {
2629         return toEnumSet(enumClass, getLong());
2630     }
2631 
2632     /**
2633      * {@inheritDoc}
2634      */
2635     @Override
2636     public <E extends Enum<E>> EnumSet<E> getEnumSetLong(int index, Class<E> enumClass) {
2637         return toEnumSet(enumClass, getLong(index));
2638     }
2639 
2640     private <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> clazz, long vector) {
2641         EnumSet<E> set = EnumSet.noneOf(clazz);
2642         long mask = 1;
2643         for (E e : clazz.getEnumConstants()) {
2644             if ((mask & vector) == mask) {
2645                 set.add(e);
2646             }
2647             mask <<= 1;
2648         }
2649         return set;
2650     }
2651 
2652     /**
2653      * {@inheritDoc}
2654      */
2655     @Override
2656     public <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set) {
2657         long vector = toLong(set);
2658         if ((vector & ~BYTE_MASK) != 0) {
2659             throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
2660         }
2661         return put((byte) vector);
2662     }
2663 
2664     /**
2665      * {@inheritDoc}
2666      */
2667     @Override
2668     public <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set) {
2669         long vector = toLong(set);
2670         if ((vector & ~BYTE_MASK) != 0) {
2671             throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
2672         }
2673         return put(index, (byte) vector);
2674     }
2675 
2676     /**
2677      * {@inheritDoc}
2678      */
2679     @Override
2680     public <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set) {
2681         long vector = toLong(set);
2682         if ((vector & ~SHORT_MASK) != 0) {
2683             throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
2684         }
2685         return putShort((short) vector);
2686     }
2687 
2688     /**
2689      * {@inheritDoc}
2690      */
2691     @Override
2692     public <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set) {
2693         long vector = toLong(set);
2694         if ((vector & ~SHORT_MASK) != 0) {
2695             throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
2696         }
2697         return putShort(index, (short) vector);
2698     }
2699 
2700     /**
2701      * {@inheritDoc}
2702      */
2703     @Override
2704     public <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set) {
2705         long vector = toLong(set);
2706         if ((vector & ~INT_MASK) != 0) {
2707             throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
2708         }
2709         return putInt((int) vector);
2710     }
2711 
2712     /**
2713      * {@inheritDoc}
2714      */
2715     @Override
2716     public <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set) {
2717         long vector = toLong(set);
2718         if ((vector & ~INT_MASK) != 0) {
2719             throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
2720         }
2721         return putInt(index, (int) vector);
2722     }
2723 
2724     /**
2725      * {@inheritDoc}
2726      */
2727     @Override
2728     public <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set) {
2729         return putLong(toLong(set));
2730     }
2731 
2732     /**
2733      * {@inheritDoc}
2734      */
2735     @Override
2736     public <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set) {
2737         return putLong(index, toLong(set));
2738     }
2739 
2740     private <E extends Enum<E>> long toLong(Set<E> set) {
2741         long vector = 0;
2742         for (E e : set) {
2743             if (e.ordinal() >= Long.SIZE) {
2744                 throw new IllegalArgumentException("The enum set is too large to fit in a bit vector: " + set);
2745             }
2746             vector |= 1L << e.ordinal();
2747         }
2748         return vector;
2749     }
2750 
2751     /**
2752      * This method forwards the call to {@link #expand(int)} only when
2753      * <tt>autoExpand</tt> property is <tt>true</tt>.
2754      */
2755     private IoBuffer autoExpand(int expectedRemaining) {
2756         if (isAutoExpand()) {
2757             expand(expectedRemaining, true);
2758         }
2759         return this;
2760     }
2761 
2762     /**
2763      * This method forwards the call to {@link #expand(int)} only when
2764      * <tt>autoExpand</tt> property is <tt>true</tt>.
2765      */
2766     private IoBuffer autoExpand(int pos, int expectedRemaining) {
2767         if (isAutoExpand()) {
2768             expand(pos, expectedRemaining, true);
2769         }
2770         return this;
2771     }
2772 
2773     private static void checkFieldSize(int fieldSize) {
2774         if (fieldSize < 0) {
2775             throw new IllegalArgumentException("fieldSize cannot be negative: " + fieldSize);
2776         }
2777     }
2778 }