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