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( (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( index, (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( (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( index, (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( index, 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( index, (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)(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( index, (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( index, 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( index, (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( index, (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 pos = position();
1187         int limit = limit();
1188         
1189         if (index > limit) {
1190             throw new IllegalArgumentException("index: " + index);
1191         }
1192         
1193         int endIndex = index + length;
1194 
1195         if (endIndex > limit) {
1196             throw new IndexOutOfBoundsException("index + length (" + endIndex
1197                     + ") is greater " + "than limit (" + limit + ").");
1198         }
1199 
1200         clear();
1201         position(index);
1202         limit(endIndex);
1203 
1204         IoBuffer slice = slice();
1205         position(pos);
1206         limit(limit);
1207         
1208         return slice;
1209     }
1210 
1211     /**
1212      * {@inheritDoc}
1213      */
1214     @Override
1215     public final IoBuffer getSlice(int length) {
1216         if (length < 0) {
1217             throw new IllegalArgumentException("length: " + length);
1218         }
1219         int pos = position();
1220         int limit = limit();
1221         int nextPos = pos + length;
1222         if (limit < nextPos) {
1223             throw new IndexOutOfBoundsException("position + length (" + nextPos
1224                     + ") is greater " + "than limit (" + limit + ").");
1225         }
1226 
1227         limit(pos + length);
1228         IoBuffer slice = slice();
1229         position(nextPos);
1230         limit(limit);
1231         return slice;
1232     }
1233 
1234     /**
1235      * Implement this method to return the unexpandable slice of this
1236      * buffer.
1237      */
1238     protected abstract IoBuffer slice0();
1239 
1240     /**
1241      * {@inheritDoc}
1242      */
1243     @Override
1244     public int hashCode() {
1245         int h = 1;
1246         int p = position();
1247         for (int i = limit() - 1; i >= p; i--) {
1248             h = 31 * h + get(i);
1249         }
1250         return h;
1251     }
1252 
1253     /**
1254      * {@inheritDoc}
1255      */
1256     @Override
1257     public boolean equals(Object o) {
1258         if (!(o instanceof IoBuffer)) {
1259             return false;
1260         }
1261 
1262         IoBuffer that = (IoBuffer) o;
1263         if (this.remaining() != that.remaining()) {
1264             return false;
1265         }
1266 
1267         int p = this.position();
1268         for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
1269             byte v1 = this.get(i);
1270             byte v2 = that.get(j);
1271             if (v1 != v2) {
1272                 return false;
1273             }
1274         }
1275         return true;
1276     }
1277 
1278     /**
1279      * {@inheritDoc}
1280      */
1281     public int compareTo(IoBuffer that) {
1282         int n = this.position() + Math.min(this.remaining(), that.remaining());
1283         for (int i = this.position(), j = that.position(); i < n; i++, j++) {
1284             byte v1 = this.get(i);
1285             byte v2 = that.get(j);
1286             if (v1 == v2) {
1287                 continue;
1288             }
1289             if (v1 < v2) {
1290                 return -1;
1291             }
1292 
1293             return +1;
1294         }
1295         return this.remaining() - that.remaining();
1296     }
1297 
1298     /**
1299      * {@inheritDoc}
1300      */
1301     @Override
1302     public String toString() {
1303         StringBuilder buf = new StringBuilder();
1304         if (isDirect()) {
1305             buf.append("DirectBuffer");
1306         } else {
1307             buf.append("HeapBuffer");
1308         }
1309         buf.append("[pos=");
1310         buf.append(position());
1311         buf.append(" lim=");
1312         buf.append(limit());
1313         buf.append(" cap=");
1314         buf.append(capacity());
1315         buf.append(": ");
1316         buf.append(getHexDump(16));
1317         buf.append(']');
1318         return buf.toString();
1319     }
1320 
1321     /**
1322      * {@inheritDoc}
1323      */
1324     @Override
1325     public IoBuffer get(byte[] dst) {
1326         return get(dst, 0, dst.length);
1327     }
1328 
1329     /**
1330      * {@inheritDoc}
1331      */
1332     @Override
1333     public IoBuffer put(IoBuffer src) {
1334         return put(src.buf());
1335     }
1336 
1337     /**
1338      * {@inheritDoc}
1339      */
1340     @Override
1341     public IoBuffer put(byte[] src) {
1342         return put(src, 0, src.length);
1343     }
1344 
1345     /**
1346      * {@inheritDoc}
1347      */
1348     @Override
1349     public int getUnsignedShort() {
1350         return getShort() & 0xffff;
1351     }
1352 
1353     /**
1354      * {@inheritDoc}
1355      */
1356     @Override
1357     public int getUnsignedShort(int index) {
1358         return getShort(index) & 0xffff;
1359     }
1360 
1361     /**
1362      * {@inheritDoc}
1363      */
1364     @Override
1365     public long getUnsignedInt() {
1366         return getInt() & 0xffffffffL;
1367     }
1368 
1369     /**
1370      * {@inheritDoc}
1371      */
1372     @Override
1373     public int getMediumInt() {
1374         byte b1 = get();
1375         byte b2 = get();
1376         byte b3 = get();
1377         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1378             return getMediumInt(b1, b2, b3);
1379         }
1380 
1381         return getMediumInt(b3, b2, b1);
1382     }
1383 
1384     /**
1385      * {@inheritDoc}
1386      */
1387     @Override
1388     public int getUnsignedMediumInt() {
1389         int b1 = getUnsigned();
1390         int b2 = getUnsigned();
1391         int b3 = getUnsigned();
1392         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1393             return b1 << 16 | b2 << 8 | b3;
1394         }
1395 
1396         return b3 << 16 | b2 << 8 | b1;
1397     }
1398 
1399     /**
1400      * {@inheritDoc}
1401      */
1402     @Override
1403     public int getMediumInt(int index) {
1404         byte b1 = get(index);
1405         byte b2 = get(index + 1);
1406         byte b3 = get(index + 2);
1407         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1408             return getMediumInt(b1, b2, b3);
1409         }
1410 
1411         return getMediumInt(b3, b2, b1);
1412     }
1413 
1414     /**
1415      * {@inheritDoc}
1416      */
1417     @Override
1418     public int getUnsignedMediumInt(int index) {
1419         int b1 = getUnsigned(index);
1420         int b2 = getUnsigned(index + 1);
1421         int b3 = getUnsigned(index + 2);
1422         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1423             return b1 << 16 | b2 << 8 | b3;
1424         }
1425 
1426         return b3 << 16 | b2 << 8 | b1;
1427     }
1428 
1429     /**
1430      * {@inheritDoc}
1431      */
1432     private int getMediumInt(byte b1, byte b2, byte b3) {
1433         int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff;
1434         // Check to see if the medium int is negative (high bit in b1 set)
1435         if ((b1 & 0x80) == 0x80) {
1436             // Make the the whole int negative
1437             ret |= 0xff000000;
1438         }
1439         return ret;
1440     }
1441 
1442     /**
1443      * {@inheritDoc}
1444      */
1445     @Override
1446     public IoBuffer putMediumInt(int value) {
1447         byte b1 = (byte) (value >> 16);
1448         byte b2 = (byte) (value >> 8);
1449         byte b3 = (byte) value;
1450 
1451         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1452             put(b1).put(b2).put(b3);
1453         } else {
1454             put(b3).put(b2).put(b1);
1455         }
1456 
1457         return this;
1458     }
1459 
1460     /**
1461      * {@inheritDoc}
1462      */
1463     @Override
1464     public IoBuffer putMediumInt(int index, int value) {
1465         byte b1 = (byte) (value >> 16);
1466         byte b2 = (byte) (value >> 8);
1467         byte b3 = (byte) value;
1468 
1469         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1470             put(index, b1).put(index + 1, b2).put(index + 2, b3);
1471         } else {
1472             put(index, b3).put(index + 1, b2).put(index + 2, b1);
1473         }
1474 
1475         return this;
1476     }
1477 
1478     /**
1479      * {@inheritDoc}
1480      */
1481     @Override
1482     public long getUnsignedInt(int index) {
1483         return getInt(index) & 0xffffffffL;
1484     }
1485 
1486     /**
1487      * {@inheritDoc}
1488      */
1489     @Override
1490     public InputStream asInputStream() {
1491         return new InputStream() {
1492             @Override
1493             public int available() {
1494                 return AbstractIoBuffer.this.remaining();
1495             }
1496 
1497             @Override
1498             public synchronized void mark(int readlimit) {
1499                 AbstractIoBuffer.this.mark();
1500             }
1501 
1502             @Override
1503             public boolean markSupported() {
1504                 return true;
1505             }
1506 
1507             @Override
1508             public int read() {
1509                 if (AbstractIoBuffer.this.hasRemaining()) {
1510                     return AbstractIoBuffer.this.get() & 0xff;
1511                 }
1512 
1513                 return -1;
1514             }
1515 
1516             @Override
1517             public int read(byte[] b, int off, int len) {
1518                 int remaining = AbstractIoBuffer.this.remaining();
1519                 if (remaining > 0) {
1520                     int readBytes = Math.min(remaining, len);
1521                     AbstractIoBuffer.this.get(b, off, readBytes);
1522                     return readBytes;
1523                 }
1524 
1525                 return -1;
1526             }
1527 
1528             @Override
1529             public synchronized void reset() {
1530                 AbstractIoBuffer.this.reset();
1531             }
1532 
1533             @Override
1534             public long skip(long n) {
1535                 int bytes;
1536                 if (n > Integer.MAX_VALUE) {
1537                     bytes = AbstractIoBuffer.this.remaining();
1538                 } else {
1539                     bytes = Math
1540                             .min(AbstractIoBuffer.this.remaining(), (int) n);
1541                 }
1542                 AbstractIoBuffer.this.skip(bytes);
1543                 return bytes;
1544             }
1545         };
1546     }
1547 
1548     /**
1549      * {@inheritDoc}
1550      */
1551     @Override
1552     public OutputStream asOutputStream() {
1553         return new OutputStream() {
1554             @Override
1555             public void write(byte[] b, int off, int len) {
1556                 AbstractIoBuffer.this.put(b, off, len);
1557             }
1558 
1559             @Override
1560             public void write(int b) {
1561                 AbstractIoBuffer.this.put((byte) b);
1562             }
1563         };
1564     }
1565 
1566     /**
1567      * {@inheritDoc}
1568      */
1569     @Override
1570     public String getHexDump() {
1571         return this.getHexDump(Integer.MAX_VALUE);
1572     }
1573 
1574     /**
1575      * {@inheritDoc}
1576      */
1577     @Override
1578     public String getHexDump(int lengthLimit) {
1579         return IoBufferHexDumper.getHexdump(this, lengthLimit);
1580     }
1581 
1582     /**
1583      * {@inheritDoc}
1584      */
1585     @Override
1586     public String getString(CharsetDecoder decoder)
1587             throws CharacterCodingException {
1588         if (!hasRemaining()) {
1589             return "";
1590         }
1591 
1592         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1593 
1594         int oldPos = position();
1595         int oldLimit = limit();
1596         int end = -1;
1597         int newPos;
1598 
1599         if (!utf16) {
1600             end = indexOf((byte) 0x00);
1601             if (end < 0) {
1602                 newPos = end = oldLimit;
1603             } else {
1604                 newPos = end + 1;
1605             }
1606         } else {
1607             int i = oldPos;
1608             for (;;) {
1609                 boolean wasZero = get(i) == 0;
1610                 i++;
1611 
1612                 if (i >= oldLimit) {
1613                     break;
1614                 }
1615 
1616                 if (get(i) != 0) {
1617                     i++;
1618                     if (i >= oldLimit) {
1619                         break;
1620                     }
1621 
1622                     continue;
1623                 }
1624 
1625                 if (wasZero) {
1626                     end = i - 1;
1627                     break;
1628                 }
1629             }
1630 
1631             if (end < 0) {
1632                 newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE);
1633             } else {
1634                 if (end + 2 <= oldLimit) {
1635                     newPos = end + 2;
1636                 } else {
1637                     newPos = end;
1638                 }
1639             }
1640         }
1641 
1642         if (oldPos == end) {
1643             position(newPos);
1644             return "";
1645         }
1646 
1647         limit(end);
1648         decoder.reset();
1649 
1650         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1651         CharBuffer out = CharBuffer.allocate(expectedLength);
1652         for (;;) {
1653             CoderResult cr;
1654             if (hasRemaining()) {
1655                 cr = decoder.decode(buf(), out, true);
1656             } else {
1657                 cr = decoder.flush(out);
1658             }
1659 
1660             if (cr.isUnderflow()) {
1661                 break;
1662             }
1663 
1664             if (cr.isOverflow()) {
1665                 CharBuffer o = CharBuffer.allocate(out.capacity()
1666                         + expectedLength);
1667                 out.flip();
1668                 o.put(out);
1669                 out = o;
1670                 continue;
1671             }
1672 
1673             if (cr.isError()) {
1674                 // Revert the buffer back to the previous state.
1675                 limit(oldLimit);
1676                 position(oldPos);
1677                 cr.throwException();
1678             }
1679         }
1680 
1681         limit(oldLimit);
1682         position(newPos);
1683         return out.flip().toString();
1684     }
1685 
1686     /**
1687      * {@inheritDoc}
1688      */
1689     @Override
1690     public String getString(int fieldSize, CharsetDecoder decoder)
1691             throws CharacterCodingException {
1692         checkFieldSize(fieldSize);
1693 
1694         if (fieldSize == 0) {
1695             return "";
1696         }
1697 
1698         if (!hasRemaining()) {
1699             return "";
1700         }
1701 
1702         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1703 
1704         if (utf16 && (fieldSize & 1) != 0) {
1705             throw new IllegalArgumentException("fieldSize is not even.");
1706         }
1707 
1708         int oldPos = position();
1709         int oldLimit = limit();
1710         int end = oldPos + fieldSize;
1711 
1712         if (oldLimit < end) {
1713             throw new BufferUnderflowException();
1714         }
1715 
1716         int i;
1717 
1718         if (!utf16) {
1719             for (i = oldPos; i < end; i++) {
1720                 if (get(i) == 0) {
1721                     break;
1722                 }
1723             }
1724 
1725             if (i == end) {
1726                 limit(end);
1727             } else {
1728                 limit(i);
1729             }
1730         } else {
1731             for (i = oldPos; i < end; i += 2) {
1732                 if (get(i) == 0 && get(i + 1) == 0) {
1733                     break;
1734                 }
1735             }
1736 
1737             if (i == end) {
1738                 limit(end);
1739             } else {
1740                 limit(i);
1741             }
1742         }
1743 
1744         if (!hasRemaining()) {
1745             limit(oldLimit);
1746             position(end);
1747             return "";
1748         }
1749         decoder.reset();
1750 
1751         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1752         CharBuffer out = CharBuffer.allocate(expectedLength);
1753         for (;;) {
1754             CoderResult cr;
1755             if (hasRemaining()) {
1756                 cr = decoder.decode(buf(), out, true);
1757             } else {
1758                 cr = decoder.flush(out);
1759             }
1760 
1761             if (cr.isUnderflow()) {
1762                 break;
1763             }
1764 
1765             if (cr.isOverflow()) {
1766                 CharBuffer o = CharBuffer.allocate(out.capacity()
1767                         + expectedLength);
1768                 out.flip();
1769                 o.put(out);
1770                 out = o;
1771                 continue;
1772             }
1773 
1774             if (cr.isError()) {
1775                 // Revert the buffer back to the previous state.
1776                 limit(oldLimit);
1777                 position(oldPos);
1778                 cr.throwException();
1779             }
1780         }
1781 
1782         limit(oldLimit);
1783         position(end);
1784         return out.flip().toString();
1785     }
1786 
1787     /**
1788      * {@inheritDoc}
1789      */
1790     @Override
1791     public IoBuffer putString(CharSequence val, CharsetEncoder encoder)
1792             throws CharacterCodingException {
1793         if (val.length() == 0) {
1794             return this;
1795         }
1796 
1797         CharBuffer in = CharBuffer.wrap(val);
1798         encoder.reset();
1799 
1800         int expandedState = 0;
1801 
1802         for (;;) {
1803             CoderResult cr;
1804             if (in.hasRemaining()) {
1805                 cr = encoder.encode(in, buf(), true);
1806             } else {
1807                 cr = encoder.flush(buf());
1808             }
1809 
1810             if (cr.isUnderflow()) {
1811                 break;
1812             }
1813             if (cr.isOverflow()) {
1814                 if (isAutoExpand()) {
1815                     switch (expandedState) {
1816                     case 0:
1817                         autoExpand((int) Math.ceil(in.remaining()
1818                                 * encoder.averageBytesPerChar()));
1819                         expandedState++;
1820                         break;
1821                     case 1:
1822                         autoExpand((int) Math.ceil(in.remaining()
1823                                 * encoder.maxBytesPerChar()));
1824                         expandedState++;
1825                         break;
1826                     default:
1827                         throw new RuntimeException("Expanded by "
1828                                 + (int) Math.ceil(in.remaining()
1829                                         * encoder.maxBytesPerChar())
1830                                 + " but that wasn't enough for '" + val + "'");
1831                     }
1832                     continue;
1833                 }
1834             } else {
1835                 expandedState = 0;
1836             }
1837             cr.throwException();
1838         }
1839         return this;
1840     }
1841 
1842     /**
1843      * {@inheritDoc}
1844      */
1845     @Override
1846     public IoBuffer putString(CharSequence val, int fieldSize,
1847             CharsetEncoder encoder) throws CharacterCodingException {
1848         checkFieldSize(fieldSize);
1849 
1850         if (fieldSize == 0) {
1851             return this;
1852         }
1853 
1854         autoExpand(fieldSize);
1855 
1856         boolean utf16 = encoder.charset().name().startsWith("UTF-16");
1857 
1858         if (utf16 && (fieldSize & 1) != 0) {
1859             throw new IllegalArgumentException("fieldSize is not even.");
1860         }
1861 
1862         int oldLimit = limit();
1863         int end = position() + fieldSize;
1864 
1865         if (oldLimit < end) {
1866             throw new BufferOverflowException();
1867         }
1868 
1869         if (val.length() == 0) {
1870             if (!utf16) {
1871                 put((byte) 0x00);
1872             } else {
1873                 put((byte) 0x00);
1874                 put((byte) 0x00);
1875             }
1876             position(end);
1877             return this;
1878         }
1879 
1880         CharBuffer in = CharBuffer.wrap(val);
1881         limit(end);
1882         encoder.reset();
1883 
1884         for (;;) {
1885             CoderResult cr;
1886             if (in.hasRemaining()) {
1887                 cr = encoder.encode(in, buf(), true);
1888             } else {
1889                 cr = encoder.flush(buf());
1890             }
1891 
1892             if (cr.isUnderflow() || cr.isOverflow()) {
1893                 break;
1894             }
1895             cr.throwException();
1896         }
1897 
1898         limit(oldLimit);
1899 
1900         if (position() < end) {
1901             if (!utf16) {
1902                 put((byte) 0x00);
1903             } else {
1904                 put((byte) 0x00);
1905                 put((byte) 0x00);
1906             }
1907         }
1908 
1909         position(end);
1910         return this;
1911     }
1912 
1913     /**
1914      * {@inheritDoc}
1915      */
1916     @Override
1917     public String getPrefixedString(CharsetDecoder decoder)
1918             throws CharacterCodingException {
1919         return getPrefixedString(2, decoder);
1920     }
1921 
1922     /**
1923      * Reads a string which has a length field before the actual
1924      * encoded string, using the specified <code>decoder</code> and returns it.
1925      *
1926      * @param prefixLength the length of the length field (1, 2, or 4)
1927      * @param decoder the decoder to use for decoding the string
1928      * @return the prefixed string
1929      * @throws CharacterCodingException when decoding fails
1930      * @throws BufferUnderflowException when there is not enough data available
1931      */
1932     @Override
1933     public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
1934             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(
1961                     "fieldSize is not even for a UTF-16 string.");
1962         }
1963 
1964         int oldLimit = limit();
1965         int end = position() + fieldSize;
1966 
1967         if (oldLimit < end) {
1968             throw new BufferUnderflowException();
1969         }
1970 
1971         limit(end);
1972         decoder.reset();
1973 
1974         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1975         CharBuffer out = CharBuffer.allocate(expectedLength);
1976         for (;;) {
1977             CoderResult cr;
1978             if (hasRemaining()) {
1979                 cr = decoder.decode(buf(), out, true);
1980             } else {
1981                 cr = decoder.flush(out);
1982             }
1983 
1984             if (cr.isUnderflow()) {
1985                 break;
1986             }
1987 
1988             if (cr.isOverflow()) {
1989                 CharBuffer o = CharBuffer.allocate(out.capacity()
1990                         + expectedLength);
1991                 out.flip();
1992                 o.put(out);
1993                 out = o;
1994                 continue;
1995             }
1996 
1997             cr.throwException();
1998         }
1999 
2000         limit(oldLimit);
2001         position(end);
2002         return out.flip().toString();
2003     }
2004 
2005     /**
2006      * {@inheritDoc}
2007      */
2008     @Override
2009     public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
2010             throws CharacterCodingException {
2011         return putPrefixedString(in, 2, 0, encoder);
2012     }
2013 
2014     /**
2015      * {@inheritDoc}
2016      */
2017     @Override
2018     public IoBuffer putPrefixedString(CharSequence in, int prefixLength,
2019             CharsetEncoder encoder) throws CharacterCodingException {
2020         return putPrefixedString(in, prefixLength, 0, encoder);
2021     }
2022 
2023     /**
2024      * {@inheritDoc}
2025      */
2026     @Override
2027     public IoBuffer putPrefixedString(CharSequence in, int prefixLength,
2028             int padding, CharsetEncoder encoder)
2029             throws CharacterCodingException {
2030         return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
2031     }
2032 
2033     /**
2034      * {@inheritDoc}
2035      */
2036     @Override
2037     public IoBuffer putPrefixedString(CharSequence val, int prefixLength,
2038             int padding, byte padValue, CharsetEncoder encoder)
2039             throws CharacterCodingException {
2040         int maxLength;
2041         switch (prefixLength) {
2042         case 1:
2043             maxLength = 255;
2044             break;
2045         case 2:
2046             maxLength = 65535;
2047             break;
2048         case 4:
2049             maxLength = Integer.MAX_VALUE;
2050             break;
2051         default:
2052             throw new IllegalArgumentException("prefixLength: " + prefixLength);
2053         }
2054 
2055         if (val.length() > maxLength) {
2056             throw new IllegalArgumentException(
2057                     "The specified string is too long.");
2058         }
2059         if (val.length() == 0) {
2060             switch (prefixLength) {
2061             case 1:
2062                 put((byte) 0);
2063                 break;
2064             case 2:
2065                 putShort((short) 0);
2066                 break;
2067             case 4:
2068                 putInt(0);
2069                 break;
2070             }
2071             return this;
2072         }
2073 
2074         int padMask;
2075         switch (padding) {
2076         case 0:
2077         case 1:
2078             padMask = 0;
2079             break;
2080         case 2:
2081             padMask = 1;
2082             break;
2083         case 4:
2084             padMask = 3;
2085             break;
2086         default:
2087             throw new IllegalArgumentException("padding: " + padding);
2088         }
2089 
2090         CharBuffer in = CharBuffer.wrap(val);
2091         skip(prefixLength); // make a room for the length field
2092         int oldPos = position();
2093         encoder.reset();
2094 
2095         int expandedState = 0;
2096 
2097         for (;;) {
2098             CoderResult cr;
2099             if (in.hasRemaining()) {
2100                 cr = encoder.encode(in, buf(), true);
2101             } else {
2102                 cr = encoder.flush(buf());
2103             }
2104 
2105             if (position() - oldPos > maxLength) {
2106                 throw new IllegalArgumentException(
2107                         "The specified string is too long.");
2108             }
2109 
2110             if (cr.isUnderflow()) {
2111                 break;
2112             }
2113             if (cr.isOverflow()) {
2114                 if (isAutoExpand()) {
2115                     switch (expandedState) {
2116                     case 0:
2117                         autoExpand((int) Math.ceil(in.remaining()
2118                                 * encoder.averageBytesPerChar()));
2119                         expandedState++;
2120                         break;
2121                     case 1:
2122                         autoExpand((int) Math.ceil(in.remaining()
2123                                 * encoder.maxBytesPerChar()));
2124                         expandedState++;
2125                         break;
2126                     default:
2127                         throw new RuntimeException("Expanded by "
2128                                 + (int) Math.ceil(in.remaining()
2129                                         * encoder.maxBytesPerChar())
2130                                 + " but that wasn't enough for '" + val + "'");
2131                     }
2132                     continue;
2133                 }
2134             } else {
2135                 expandedState = 0;
2136             }
2137             cr.throwException();
2138         }
2139 
2140         // Write the length field
2141         fill(padValue, padding - (position() - oldPos & padMask));
2142         int length = position() - oldPos;
2143         switch (prefixLength) {
2144         case 1:
2145             put(oldPos - 1, (byte) length);
2146             break;
2147         case 2:
2148             putShort(oldPos - 2, (short) length);
2149             break;
2150         case 4:
2151             putInt(oldPos - 4, length);
2152             break;
2153         }
2154         return this;
2155     }
2156 
2157     /**
2158      * {@inheritDoc}
2159      */
2160     @Override
2161     public Object getObject() throws ClassNotFoundException {
2162         return getObject(Thread.currentThread().getContextClassLoader());
2163     }
2164 
2165     /**
2166      * {@inheritDoc}
2167      */
2168     @Override
2169     public Object getObject(final ClassLoader classLoader)
2170             throws ClassNotFoundException {
2171         if (!prefixedDataAvailable(4)) {
2172             throw new BufferUnderflowException();
2173         }
2174 
2175         int length = getInt();
2176         if (length <= 4) {
2177             throw new BufferDataException(
2178                     "Object length should be greater than 4: " + length);
2179         }
2180 
2181         int oldLimit = limit();
2182         limit(position() + length);
2183         try {
2184             ObjectInputStream in = new ObjectInputStream(asInputStream()) {
2185                 @Override
2186                 protected ObjectStreamClass readClassDescriptor()
2187                         throws IOException, ClassNotFoundException {
2188                     int type = read();
2189                     if (type < 0) {
2190                         throw new EOFException();
2191                     }
2192                     switch (type) {
2193                     case 0: // NON-Serializable class or Primitive types
2194                         return super.readClassDescriptor();
2195                     case 1: // Serializable class
2196                         String className = readUTF();
2197                         Class<?> clazz = Class.forName(className, true,
2198                                 classLoader);
2199                         return ObjectStreamClass.lookup(clazz);
2200                     default:
2201                         throw new StreamCorruptedException(
2202                                 "Unexpected class descriptor type: " + type);
2203                     }
2204                 }
2205 
2206                 @Override
2207                 protected Class<?> resolveClass(ObjectStreamClass desc)
2208                         throws IOException, ClassNotFoundException {
2209                     String name = desc.getName();
2210                     try {
2211                         return Class.forName(name, false, classLoader);
2212                     } catch (ClassNotFoundException ex) {
2213                         return super.resolveClass(desc);
2214                     }
2215                 }
2216             };
2217             return in.readObject();
2218         } catch (IOException e) {
2219             throw new BufferDataException(e);
2220         } finally {
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         try {
2233             ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
2234                 @Override
2235                 protected void writeClassDescriptor(ObjectStreamClass desc)
2236                         throws IOException {
2237                     try {
2238                         Class<?> clz = Class.forName(desc.getName());
2239                         if (!Serializable.class.isAssignableFrom(clz)) { // NON-Serializable class
2240                           write(0);
2241                           super.writeClassDescriptor(desc);
2242                         } else { // Serializable class
2243                           write(1);
2244                           writeUTF(desc.getName());
2245                         }
2246                       }
2247                       catch (ClassNotFoundException ex) { // Primitive types
2248                         write(0);
2249                         super.writeClassDescriptor(desc);
2250                       }
2251                 }
2252             };
2253             out.writeObject(o);
2254             out.flush();
2255         } catch (IOException e) {
2256             throw new BufferDataException(e);
2257         }
2258 
2259         // Fill the length field
2260         int newPos = position();
2261         position(oldPos);
2262         putInt(newPos - oldPos - 4);
2263         position(newPos);
2264         return this;
2265     }
2266 
2267     /**
2268      * {@inheritDoc}
2269      */
2270     @Override
2271     public boolean prefixedDataAvailable(int prefixLength) {
2272         return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
2273     }
2274 
2275     /**
2276      * {@inheritDoc}
2277      */
2278     @Override
2279     public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
2280         if (remaining() < prefixLength) {
2281             return false;
2282         }
2283 
2284         int dataLength;
2285         switch (prefixLength) {
2286         case 1:
2287             dataLength = getUnsigned(position());
2288             break;
2289         case 2:
2290             dataLength = getUnsignedShort(position());
2291             break;
2292         case 4:
2293             dataLength = getInt(position());
2294             break;
2295         default:
2296             throw new IllegalArgumentException("prefixLength: " + prefixLength);
2297         }
2298 
2299         if (dataLength < 0 || dataLength > maxDataLength) {
2300             throw new BufferDataException("dataLength: " + dataLength);
2301         }
2302 
2303         return remaining() - prefixLength >= dataLength;
2304     }
2305 
2306     /**
2307      * {@inheritDoc}
2308      */
2309     @Override
2310     public int indexOf(byte b) {
2311         if (hasArray()) {
2312             int arrayOffset = arrayOffset();
2313             int beginPos = arrayOffset + position();
2314             int limit = arrayOffset + limit();
2315             byte[] array = array();
2316 
2317             for (int i = beginPos; i < limit; i++) {
2318                 if (array[i] == b) {
2319                     return i - arrayOffset;
2320                 }
2321             }
2322         } else {
2323             int beginPos = position();
2324             int limit = limit();
2325 
2326             for (int i = beginPos; i < limit; i++) {
2327                 if (get(i) == b) {
2328                     return i;
2329                 }
2330             }
2331         }
2332 
2333         return -1;
2334     }
2335 
2336     /**
2337      * {@inheritDoc}
2338      */
2339     @Override
2340     public IoBuffer skip(int size) {
2341         autoExpand(size);
2342         return position(position() + size);
2343     }
2344 
2345     /**
2346      * {@inheritDoc}
2347      */
2348     @Override
2349     public IoBuffer fill(byte value, int size) {
2350         autoExpand(size);
2351         int q = size >>> 3;
2352         int r = size & 7;
2353 
2354         if (q > 0) {
2355             int intValue = value | value << 8 | value << 16 | value << 24;
2356             long longValue = intValue;
2357             longValue <<= 32;
2358             longValue |= intValue;
2359 
2360             for (int i = q; i > 0; i--) {
2361                 putLong(longValue);
2362             }
2363         }
2364 
2365         q = r >>> 2;
2366         r = r & 3;
2367 
2368         if (q > 0) {
2369             int intValue = value | value << 8 | value << 16 | value << 24;
2370             putInt(intValue);
2371         }
2372 
2373         q = r >> 1;
2374         r = r & 1;
2375 
2376         if (q > 0) {
2377             short shortValue = (short) (value | value << 8);
2378             putShort(shortValue);
2379         }
2380 
2381         if (r > 0) {
2382             put(value);
2383         }
2384 
2385         return this;
2386     }
2387 
2388     /**
2389      * {@inheritDoc}
2390      */
2391     @Override
2392     public IoBuffer fillAndReset(byte value, int size) {
2393         autoExpand(size);
2394         int pos = position();
2395         try {
2396             fill(value, size);
2397         } finally {
2398             position(pos);
2399         }
2400         return this;
2401     }
2402 
2403     /**
2404      * {@inheritDoc}
2405      */
2406     @Override
2407     public IoBuffer fill(int size) {
2408         autoExpand(size);
2409         int q = size >>> 3;
2410         int r = size & 7;
2411 
2412         for (int i = q; i > 0; i--) {
2413             putLong(0L);
2414         }
2415 
2416         q = r >>> 2;
2417         r = r & 3;
2418 
2419         if (q > 0) {
2420             putInt(0);
2421         }
2422 
2423         q = r >> 1;
2424         r = r & 1;
2425 
2426         if (q > 0) {
2427             putShort((short) 0);
2428         }
2429 
2430         if (r > 0) {
2431             put((byte) 0);
2432         }
2433 
2434         return this;
2435     }
2436 
2437     /**
2438      * {@inheritDoc}
2439      */
2440     @Override
2441     public IoBuffer fillAndReset(int size) {
2442         autoExpand(size);
2443         int pos = position();
2444         try {
2445             fill(size);
2446         } finally {
2447             position(pos);
2448         }
2449 
2450         return this;
2451     }
2452 
2453     /**
2454      * {@inheritDoc}
2455      */
2456     @Override
2457     public <E extends Enum<E>> E getEnum(Class<E> enumClass) {
2458         return toEnum(enumClass, getUnsigned());
2459     }
2460 
2461     /**
2462      * {@inheritDoc}
2463      */
2464     @Override
2465     public <E extends Enum<E>> E getEnum(int index, Class<E> enumClass) {
2466         return toEnum(enumClass, getUnsigned(index));
2467     }
2468 
2469     /**
2470      * {@inheritDoc}
2471      */
2472     @Override
2473     public <E extends Enum<E>> E getEnumShort(Class<E> enumClass) {
2474         return toEnum(enumClass, getUnsignedShort());
2475     }
2476 
2477     /**
2478      * {@inheritDoc}
2479      */
2480     @Override
2481     public <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass) {
2482         return toEnum(enumClass, getUnsignedShort(index));
2483     }
2484 
2485     /**
2486      * {@inheritDoc}
2487      */
2488     @Override
2489     public <E extends Enum<E>> E getEnumInt(Class<E> enumClass) {
2490         return toEnum(enumClass, getInt());
2491     }
2492 
2493     /**
2494      * {@inheritDoc}
2495      */
2496     public <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass) {
2497         return toEnum(enumClass, getInt(index));
2498     }
2499 
2500     /**
2501      * {@inheritDoc}
2502      */
2503     @Override
2504     public IoBuffer putEnum(Enum<?> e) {
2505         if (e.ordinal() > BYTE_MASK) {
2506             throw new IllegalArgumentException(enumConversionErrorMessage(e,
2507                     "byte"));
2508         }
2509         return put((byte) e.ordinal());
2510     }
2511 
2512     /**
2513      * {@inheritDoc}
2514      */
2515     @Override
2516     public IoBuffer putEnum(int index, Enum<?> e) {
2517         if (e.ordinal() > BYTE_MASK) {
2518             throw new IllegalArgumentException(enumConversionErrorMessage(e,
2519                     "byte"));
2520         }
2521         return put(index, (byte) e.ordinal());
2522     }
2523 
2524     /**
2525      * {@inheritDoc}
2526      */
2527     @Override
2528     public IoBuffer putEnumShort(Enum<?> e) {
2529         if (e.ordinal() > SHORT_MASK) {
2530             throw new IllegalArgumentException(enumConversionErrorMessage(e,
2531                     "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,
2543                     "short"));
2544         }
2545         return putShort(index, (short) e.ordinal());
2546     }
2547 
2548     /**
2549      * {@inheritDoc}
2550      */
2551     @Override
2552     public IoBuffer putEnumInt(Enum<?> e) {
2553         return putInt(e.ordinal());
2554     }
2555 
2556     /**
2557      * {@inheritDoc}
2558      */
2559     @Override
2560     public IoBuffer putEnumInt(int index, Enum<?> e) {
2561         return putInt(index, e.ordinal());
2562     }
2563 
2564     private <E> E toEnum(Class<E> enumClass, int i) {
2565         E[] enumConstants = enumClass.getEnumConstants();
2566         if (i > enumConstants.length) {
2567             throw new IndexOutOfBoundsException(String.format(
2568                     "%d is too large of an ordinal to convert to the enum %s",
2569                     i, enumClass.getName()));
2570         }
2571         return enumConstants[i];
2572     }
2573 
2574     private String enumConversionErrorMessage(Enum<?> e, String type) {
2575         return String.format("%s.%s has an ordinal value too large for a %s", e
2576                 .getClass().getName(), e.name(), type);
2577     }
2578 
2579     /**
2580      * {@inheritDoc}
2581      */
2582     @Override
2583     public <E extends Enum<E>> EnumSet<E> getEnumSet(Class<E> enumClass) {
2584         return toEnumSet(enumClass, get() & BYTE_MASK);
2585     }
2586 
2587     /**
2588      * {@inheritDoc}
2589      */
2590     @Override
2591     public <E extends Enum<E>> EnumSet<E> getEnumSet(int index,
2592             Class<E> enumClass) {
2593         return toEnumSet(enumClass, get(index) & BYTE_MASK);
2594     }
2595 
2596     /**
2597      * {@inheritDoc}
2598      */
2599     @Override
2600     public <E extends Enum<E>> EnumSet<E> getEnumSetShort(Class<E> enumClass) {
2601         return toEnumSet(enumClass, getShort() & SHORT_MASK);
2602     }
2603 
2604     /**
2605      * {@inheritDoc}
2606      */
2607     @Override
2608     public <E extends Enum<E>> EnumSet<E> getEnumSetShort(int index,
2609             Class<E> enumClass) {
2610         return toEnumSet(enumClass, getShort(index) & SHORT_MASK);
2611     }
2612 
2613     /**
2614      * {@inheritDoc}
2615      */
2616     @Override
2617     public <E extends Enum<E>> EnumSet<E> getEnumSetInt(Class<E> enumClass) {
2618         return toEnumSet(enumClass, getInt() & INT_MASK);
2619     }
2620 
2621     /**
2622      * {@inheritDoc}
2623      */
2624     @Override
2625     public <E extends Enum<E>> EnumSet<E> getEnumSetInt(int index,
2626             Class<E> enumClass) {
2627         return toEnumSet(enumClass, getInt(index) & INT_MASK);
2628     }
2629 
2630     /**
2631      * {@inheritDoc}
2632      */
2633     @Override
2634     public <E extends Enum<E>> EnumSet<E> getEnumSetLong(Class<E> enumClass) {
2635         return toEnumSet(enumClass, getLong());
2636     }
2637 
2638     /**
2639      * {@inheritDoc}
2640      */
2641     @Override
2642     public <E extends Enum<E>> EnumSet<E> getEnumSetLong(int index,
2643             Class<E> enumClass) {
2644         return toEnumSet(enumClass, getLong(index));
2645     }
2646 
2647     private <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> clazz, long vector) {
2648         EnumSet<E> set = EnumSet.noneOf(clazz);
2649         long mask = 1;
2650         for (E e : clazz.getEnumConstants()) {
2651             if ((mask & vector) == mask) {
2652                 set.add(e);
2653             }
2654             mask <<= 1;
2655         }
2656         return set;
2657     }
2658 
2659     /**
2660      * {@inheritDoc}
2661      */
2662     @Override
2663     public <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set) {
2664         long vector = toLong(set);
2665         if ((vector & ~BYTE_MASK) != 0) {
2666             throw new IllegalArgumentException(
2667                     "The enum set is too large to fit in a byte: " + set);
2668         }
2669         return put((byte) vector);
2670     }
2671 
2672     /**
2673      * {@inheritDoc}
2674      */
2675     @Override
2676     public <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set) {
2677         long vector = toLong(set);
2678         if ((vector & ~BYTE_MASK) != 0) {
2679             throw new IllegalArgumentException(
2680                     "The enum set is too large to fit in a byte: " + set);
2681         }
2682         return put(index, (byte) vector);
2683     }
2684 
2685     /**
2686      * {@inheritDoc}
2687      */
2688     @Override
2689     public <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set) {
2690         long vector = toLong(set);
2691         if ((vector & ~SHORT_MASK) != 0) {
2692             throw new IllegalArgumentException(
2693                     "The enum set is too large to fit in a short: " + set);
2694         }
2695         return putShort((short) vector);
2696     }
2697 
2698     /**
2699      * {@inheritDoc}
2700      */
2701     @Override
2702     public <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set) {
2703         long vector = toLong(set);
2704         if ((vector & ~SHORT_MASK) != 0) {
2705             throw new IllegalArgumentException(
2706                     "The enum set is too large to fit in a short: " + set);
2707         }
2708         return putShort(index, (short) vector);
2709     }
2710 
2711     /**
2712      * {@inheritDoc}
2713      */
2714     @Override
2715     public <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set) {
2716         long vector = toLong(set);
2717         if ((vector & ~INT_MASK) != 0) {
2718             throw new IllegalArgumentException(
2719                     "The enum set is too large to fit in an int: " + set);
2720         }
2721         return putInt((int) vector);
2722     }
2723 
2724     /**
2725      * {@inheritDoc}
2726      */
2727     @Override
2728     public <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set) {
2729         long vector = toLong(set);
2730         if ((vector & ~INT_MASK) != 0) {
2731             throw new IllegalArgumentException(
2732                     "The enum set is too large to fit in an int: " + set);
2733         }
2734         return putInt(index, (int) vector);
2735     }
2736 
2737     /**
2738      * {@inheritDoc}
2739      */
2740     @Override
2741     public <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set) {
2742         return putLong(toLong(set));
2743     }
2744 
2745     /**
2746      * {@inheritDoc}
2747      */
2748     @Override
2749     public <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set) {
2750         return putLong(index, toLong(set));
2751     }
2752 
2753     private <E extends Enum<E>> long toLong(Set<E> set) {
2754         long vector = 0;
2755         for (E e : set) {
2756             if (e.ordinal() >= Long.SIZE) {
2757                 throw new IllegalArgumentException(
2758                         "The enum set is too large to fit in a bit vector: "
2759                                 + set);
2760             }
2761             vector |= 1L << e.ordinal();
2762         }
2763         return vector;
2764     }
2765 
2766     /**
2767      * This method forwards the call to {@link #expand(int)} only when
2768      * <tt>autoExpand</tt> property is <tt>true</tt>.
2769      */
2770     private IoBuffer autoExpand(int expectedRemaining) {
2771         if (isAutoExpand()) {
2772             expand(expectedRemaining, true);
2773         }
2774         return this;
2775     }
2776 
2777     /**
2778      * This method forwards the call to {@link #expand(int)} only when
2779      * <tt>autoExpand</tt> property is <tt>true</tt>.
2780      */
2781     private IoBuffer autoExpand(int pos, int expectedRemaining) {
2782         if (isAutoExpand()) {
2783             expand(pos, expectedRemaining, true);
2784         }
2785         return this;
2786     }
2787 
2788     private static void checkFieldSize(int fieldSize) {
2789         if (fieldSize < 0) {
2790             throw new IllegalArgumentException("fieldSize cannot be negative: "
2791                     + fieldSize);
2792         }
2793     }
2794 }