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.StreamCorruptedException;
30  import java.nio.BufferOverflowException;
31  import java.nio.BufferUnderflowException;
32  import java.nio.ByteBuffer;
33  import java.nio.ByteOrder;
34  import java.nio.CharBuffer;
35  import java.nio.DoubleBuffer;
36  import java.nio.FloatBuffer;
37  import java.nio.IntBuffer;
38  import java.nio.LongBuffer;
39  import java.nio.ShortBuffer;
40  import java.nio.charset.CharacterCodingException;
41  import java.nio.charset.CharsetDecoder;
42  import java.nio.charset.CharsetEncoder;
43  import java.nio.charset.CoderResult;
44  import java.util.EnumSet;
45  import java.util.Set;
46  
47  /**
48   * A base implementation of {@link IoBuffer}.  This implementation
49   * assumes that {@link IoBuffer#buf()} always returns a correct NIO
50   * {@link ByteBuffer} instance.  Most implementations could
51   * extend this class and implement their own buffer management mechanism.
52   *
53   * @author The Apache MINA Project (dev@mina.apache.org)
54   * @version $Rev: 748210 $, $Date: 2009-02-26 18:05:40 +0100 (Thu, 26 Feb 2009) $
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     @Override
518     public final byte get(int index) {
519         return buf().get(index);
520     }
521 
522     /**
523      * {@inheritDoc}
524      */
525     @Override
526     public final short getUnsigned(int index) {
527         return (short) (get(index) & 0xff);
528     }
529 
530     /**
531      * {@inheritDoc}
532      */
533     @Override
534     public final IoBuffer put(int index, byte b) {
535         autoExpand(index, 1);
536         buf().put(index, b);
537         return this;
538     }
539 
540     /**
541      * {@inheritDoc}
542      */
543     @Override
544     public final IoBuffer get(byte[] dst, int offset, int length) {
545         buf().get(dst, offset, length);
546         return this;
547     }
548 
549     /**
550      * {@inheritDoc}
551      */
552     @Override
553     public final IoBuffer put(ByteBuffer src) {
554         autoExpand(src.remaining());
555         buf().put(src);
556         return this;
557     }
558 
559     /**
560      * {@inheritDoc}
561      */
562     @Override
563     public final IoBuffer put(byte[] src, int offset, int length) {
564         autoExpand(length);
565         buf().put(src, offset, length);
566         return this;
567     }
568 
569     /**
570      * {@inheritDoc}
571      */
572     @Override
573     public final IoBuffer compact() {
574         int remaining = remaining();
575         int capacity = capacity();
576 
577         if (capacity == 0) {
578             return this;
579         }
580 
581         if (isAutoShrink() && remaining <= capacity >>> 2
582                 && capacity > minimumCapacity) {
583             int newCapacity = capacity;
584             int minCapacity = Math.max(minimumCapacity, remaining << 1);
585             for (;;) {
586                 if (newCapacity >>> 1 < minCapacity) {
587                     break;
588                 }
589                 newCapacity >>>= 1;
590             }
591 
592             newCapacity = Math.max(minCapacity, newCapacity);
593 
594             if (newCapacity == capacity) {
595                 return this;
596             }
597 
598             // Shrink and compact:
599             //// Save the state.
600             ByteOrder bo = order();
601 
602             //// Sanity check.
603             if (remaining > newCapacity) {
604                 throw new IllegalStateException(
605                         "The amount of the remaining bytes is greater than "
606                                 + "the new capacity.");
607             }
608 
609             //// Reallocate.
610             ByteBuffer oldBuf = buf();
611             ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity,
612                     isDirect());
613             newBuf.put(oldBuf);
614             buf(newBuf);
615 
616             //// Restore the state.
617             buf().order(bo);
618         } else {
619             buf().compact();
620         }
621         mark = -1;
622         return this;
623     }
624 
625     /**
626      * {@inheritDoc}
627      */
628     @Override
629     public final ByteOrder order() {
630         return buf().order();
631     }
632 
633     /**
634      * {@inheritDoc}
635      */
636     @Override
637     public final IoBuffer order(ByteOrder bo) {
638         buf().order(bo);
639         return this;
640     }
641 
642     /**
643      * {@inheritDoc}
644      */
645     @Override
646     public final char getChar() {
647         return buf().getChar();
648     }
649 
650     /**
651      * {@inheritDoc}
652      */
653     @Override
654     public final IoBuffer putChar(char value) {
655         autoExpand(2);
656         buf().putChar(value);
657         return this;
658     }
659 
660     /**
661      * {@inheritDoc}
662      */
663     @Override
664     public final char getChar(int index) {
665         return buf().getChar(index);
666     }
667 
668     /**
669      * {@inheritDoc}
670      */
671     @Override
672     public final IoBuffer putChar(int index, char value) {
673         autoExpand(index, 2);
674         buf().putChar(index, value);
675         return this;
676     }
677 
678     /**
679      * {@inheritDoc}
680      */
681     @Override
682     public final CharBuffer asCharBuffer() {
683         return buf().asCharBuffer();
684     }
685 
686     /**
687      * {@inheritDoc}
688      */
689     @Override
690     public final short getShort() {
691         return buf().getShort();
692     }
693 
694     /**
695      * {@inheritDoc}
696      */
697     @Override
698     public final IoBuffer putShort(short value) {
699         autoExpand(2);
700         buf().putShort(value);
701         return this;
702     }
703 
704     /**
705      * {@inheritDoc}
706      */
707     @Override
708     public final short getShort(int index) {
709         return buf().getShort(index);
710     }
711 
712     /**
713      * {@inheritDoc}
714      */
715     @Override
716     public final IoBuffer putShort(int index, short value) {
717         autoExpand(index, 2);
718         buf().putShort(index, value);
719         return this;
720     }
721 
722     /**
723      * {@inheritDoc}
724      */
725     @Override
726     public final ShortBuffer asShortBuffer() {
727         return buf().asShortBuffer();
728     }
729 
730     /**
731      * {@inheritDoc}
732      */
733     @Override
734     public final int getInt() {
735         return buf().getInt();
736     }
737 
738     /**
739      * {@inheritDoc}
740      */
741     @Override
742     public final IoBuffer putInt(int value) {
743         autoExpand(4);
744         buf().putInt(value);
745         return this;
746     }
747 
748     /**
749      * {@inheritDoc}
750      */
751     @Override
752     public final int getInt(int index) {
753         return buf().getInt(index);
754     }
755 
756     /**
757      * {@inheritDoc}
758      */
759     @Override
760     public final IoBuffer putInt(int index, int value) {
761         autoExpand(index, 4);
762         buf().putInt(index, value);
763         return this;
764     }
765 
766     /**
767      * {@inheritDoc}
768      */
769     @Override
770     public final IntBuffer asIntBuffer() {
771         return buf().asIntBuffer();
772     }
773 
774     /**
775      * {@inheritDoc}
776      */
777     @Override
778     public final long getLong() {
779         return buf().getLong();
780     }
781 
782     /**
783      * {@inheritDoc}
784      */
785     @Override
786     public final IoBuffer putLong(long value) {
787         autoExpand(8);
788         buf().putLong(value);
789         return this;
790     }
791 
792     /**
793      * {@inheritDoc}
794      */
795     @Override
796     public final long getLong(int index) {
797         return buf().getLong(index);
798     }
799 
800     /**
801      * {@inheritDoc}
802      */
803     @Override
804     public final IoBuffer putLong(int index, long value) {
805         autoExpand(index, 8);
806         buf().putLong(index, value);
807         return this;
808     }
809 
810     /**
811      * {@inheritDoc}
812      */
813     @Override
814     public final LongBuffer asLongBuffer() {
815         return buf().asLongBuffer();
816     }
817 
818     /**
819      * {@inheritDoc}
820      */
821     @Override
822     public final float getFloat() {
823         return buf().getFloat();
824     }
825 
826     /**
827      * {@inheritDoc}
828      */
829     @Override
830     public final IoBuffer putFloat(float value) {
831         autoExpand(4);
832         buf().putFloat(value);
833         return this;
834     }
835 
836     /**
837      * {@inheritDoc}
838      */
839     @Override
840     public final float getFloat(int index) {
841         return buf().getFloat(index);
842     }
843 
844     /**
845      * {@inheritDoc}
846      */
847     @Override
848     public final IoBuffer putFloat(int index, float value) {
849         autoExpand(index, 4);
850         buf().putFloat(index, value);
851         return this;
852     }
853 
854     /**
855      * {@inheritDoc}
856      */
857     @Override
858     public final FloatBuffer asFloatBuffer() {
859         return buf().asFloatBuffer();
860     }
861 
862     /**
863      * {@inheritDoc}
864      */
865     @Override
866     public final double getDouble() {
867         return buf().getDouble();
868     }
869 
870     /**
871      * {@inheritDoc}
872      */
873     @Override
874     public final IoBuffer putDouble(double value) {
875         autoExpand(8);
876         buf().putDouble(value);
877         return this;
878     }
879 
880     /**
881      * {@inheritDoc}
882      */
883     @Override
884     public final double getDouble(int index) {
885         return buf().getDouble(index);
886     }
887 
888     /**
889      * {@inheritDoc}
890      */
891     @Override
892     public final IoBuffer putDouble(int index, double value) {
893         autoExpand(index, 8);
894         buf().putDouble(index, value);
895         return this;
896     }
897 
898     /**
899      * {@inheritDoc}
900      */
901     @Override
902     public final DoubleBuffer asDoubleBuffer() {
903         return buf().asDoubleBuffer();
904     }
905 
906     /**
907      * {@inheritDoc}
908      */
909     @Override
910     public final IoBuffer asReadOnlyBuffer() {
911         recapacityAllowed = false;
912         return asReadOnlyBuffer0();
913     }
914 
915     /**
916      * Implement this method to return the unexpandable read only version of
917      * this buffer.
918      */
919     protected abstract IoBuffer asReadOnlyBuffer0();
920 
921     /**
922      * {@inheritDoc}
923      */
924     @Override
925     public final IoBuffer duplicate() {
926         recapacityAllowed = false;
927         return duplicate0();
928     }
929 
930     /**
931      * Implement this method to return the unexpandable duplicate of this
932      * buffer.
933      */
934     protected abstract IoBuffer duplicate0();
935 
936     /**
937      * {@inheritDoc}
938      */
939     @Override
940     public final IoBuffer slice() {
941         recapacityAllowed = false;
942         return slice0();
943     }
944 
945     /**
946      * {@inheritDoc}
947      */
948     @Override
949     public final IoBuffer getSlice(int index, int length) {
950         if (length < 0) {
951             throw new IllegalArgumentException("length: " + length);
952         }
953         
954         int limit = limit();
955         
956         if (index > limit) {
957             throw new IllegalArgumentException("index: " + index);
958         }
959         
960         int endIndex = index + length;
961 
962         if (capacity() < endIndex) {
963             throw new IndexOutOfBoundsException("index + length (" + endIndex
964                     + ") is greater " + "than capacity (" + capacity() + ").");
965         }
966 
967         clear();
968         position(index);
969         limit(endIndex);
970 
971         IoBuffer slice = slice();
972         position(index);
973         limit(limit);
974         return slice;
975     }
976 
977     /**
978      * {@inheritDoc}
979      */
980     @Override
981     public final IoBuffer getSlice(int length) {
982         if (length < 0) {
983             throw new IllegalArgumentException("length: " + length);
984         }
985         int pos = position();
986         int limit = limit();
987         int nextPos = pos + length;
988         if (limit < nextPos) {
989             throw new IndexOutOfBoundsException("position + length (" + nextPos
990                     + ") is greater " + "than limit (" + limit + ").");
991         }
992 
993         limit(pos + length);
994         IoBuffer slice = slice();
995         position(nextPos);
996         limit(limit);
997         return slice;
998     }
999 
1000     /**
1001      * Implement this method to return the unexpandable slice of this
1002      * buffer.
1003      */
1004     protected abstract IoBuffer slice0();
1005 
1006     /**
1007      * {@inheritDoc}
1008      */
1009     @Override
1010     public int hashCode() {
1011         int h = 1;
1012         int p = position();
1013         for (int i = limit() - 1; i >= p; i--) {
1014             h = 31 * h + get(i);
1015         }
1016         return h;
1017     }
1018 
1019     /**
1020      * {@inheritDoc}
1021      */
1022     @Override
1023     public boolean equals(Object o) {
1024         if (!(o instanceof IoBuffer)) {
1025             return false;
1026         }
1027 
1028         IoBuffer that = (IoBuffer) o;
1029         if (this.remaining() != that.remaining()) {
1030             return false;
1031         }
1032 
1033         int p = this.position();
1034         for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
1035             byte v1 = this.get(i);
1036             byte v2 = that.get(j);
1037             if (v1 != v2) {
1038                 return false;
1039             }
1040         }
1041         return true;
1042     }
1043 
1044     /**
1045      * {@inheritDoc}
1046      */
1047     public int compareTo(IoBuffer that) {
1048         int n = this.position() + Math.min(this.remaining(), that.remaining());
1049         for (int i = this.position(), j = that.position(); i < n; i++, j++) {
1050             byte v1 = this.get(i);
1051             byte v2 = that.get(j);
1052             if (v1 == v2) {
1053                 continue;
1054             }
1055             if (v1 < v2) {
1056                 return -1;
1057             }
1058 
1059             return +1;
1060         }
1061         return this.remaining() - that.remaining();
1062     }
1063 
1064     /**
1065      * {@inheritDoc}
1066      */
1067     @Override
1068     public String toString() {
1069         StringBuilder buf = new StringBuilder();
1070         if (isDirect()) {
1071             buf.append("DirectBuffer");
1072         } else {
1073             buf.append("HeapBuffer");
1074         }
1075         buf.append("[pos=");
1076         buf.append(position());
1077         buf.append(" lim=");
1078         buf.append(limit());
1079         buf.append(" cap=");
1080         buf.append(capacity());
1081         buf.append(": ");
1082         buf.append(getHexDump(16));
1083         buf.append(']');
1084         return buf.toString();
1085     }
1086 
1087     /**
1088      * {@inheritDoc}
1089      */
1090     @Override
1091     public IoBuffer get(byte[] dst) {
1092         return get(dst, 0, dst.length);
1093     }
1094 
1095     /**
1096      * {@inheritDoc}
1097      */
1098     @Override
1099     public IoBuffer put(IoBuffer src) {
1100         return put(src.buf());
1101     }
1102 
1103     /**
1104      * {@inheritDoc}
1105      */
1106     @Override
1107     public IoBuffer put(byte[] src) {
1108         return put(src, 0, src.length);
1109     }
1110 
1111     /**
1112      * {@inheritDoc}
1113      */
1114     @Override
1115     public int getUnsignedShort() {
1116         return getShort() & 0xffff;
1117     }
1118 
1119     /**
1120      * {@inheritDoc}
1121      */
1122     @Override
1123     public int getUnsignedShort(int index) {
1124         return getShort(index) & 0xffff;
1125     }
1126 
1127     /**
1128      * {@inheritDoc}
1129      */
1130     @Override
1131     public long getUnsignedInt() {
1132         return getInt() & 0xffffffffL;
1133     }
1134 
1135     /**
1136      * {@inheritDoc}
1137      */
1138     @Override
1139     public int getMediumInt() {
1140         byte b1 = get();
1141         byte b2 = get();
1142         byte b3 = get();
1143         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1144             return getMediumInt(b1, b2, b3);
1145         } else {
1146             return getMediumInt(b3, b2, b1);
1147         }
1148     }
1149 
1150     /**
1151      * {@inheritDoc}
1152      */
1153     @Override
1154     public int getUnsignedMediumInt() {
1155         int b1 = getUnsigned();
1156         int b2 = getUnsigned();
1157         int b3 = getUnsigned();
1158         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1159             return b1 << 16 | b2 << 8 | b3;
1160         } else {
1161             return b3 << 16 | b2 << 8 | b1;
1162         }
1163     }
1164 
1165     /**
1166      * {@inheritDoc}
1167      */
1168     @Override
1169     public int getMediumInt(int index) {
1170         byte b1 = get(index);
1171         byte b2 = get(index + 1);
1172         byte b3 = get(index + 2);
1173         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1174             return getMediumInt(b1, b2, b3);
1175         } else {
1176             return getMediumInt(b3, b2, b1);
1177         }
1178     }
1179 
1180     /**
1181      * {@inheritDoc}
1182      */
1183     @Override
1184     public int getUnsignedMediumInt(int index) {
1185         int b1 = getUnsigned(index);
1186         int b2 = getUnsigned(index + 1);
1187         int b3 = getUnsigned(index + 2);
1188         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1189             return b1 << 16 | b2 << 8 | b3;
1190         } else {
1191             return b3 << 16 | b2 << 8 | b1;
1192         }
1193     }
1194 
1195     /**
1196      * {@inheritDoc}
1197      */
1198     private int getMediumInt(byte b1, byte b2, byte b3) {
1199         int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff;
1200         // Check to see if the medium int is negative (high bit in b1 set)
1201         if ((b1 & 0x80) == 0x80) {
1202             // Make the the whole int negative
1203             ret |= 0xff000000;
1204         }
1205         return ret;
1206     }
1207 
1208     /**
1209      * {@inheritDoc}
1210      */
1211     @Override
1212     public IoBuffer putMediumInt(int value) {
1213         byte b1 = (byte) (value >> 16);
1214         byte b2 = (byte) (value >> 8);
1215         byte b3 = (byte) value;
1216 
1217         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1218             put(b1).put(b2).put(b3);
1219         } else {
1220             put(b3).put(b2).put(b1);
1221         }
1222 
1223         return this;
1224     }
1225 
1226     /**
1227      * {@inheritDoc}
1228      */
1229     @Override
1230     public IoBuffer putMediumInt(int index, int value) {
1231         byte b1 = (byte) (value >> 16);
1232         byte b2 = (byte) (value >> 8);
1233         byte b3 = (byte) value;
1234 
1235         if (ByteOrder.BIG_ENDIAN.equals(order())) {
1236             put(index, b1).put(index + 1, b2).put(index + 2, b3);
1237         } else {
1238             put(index, b3).put(index + 1, b2).put(index + 2, b1);
1239         }
1240 
1241         return this;
1242     }
1243 
1244     /**
1245      * {@inheritDoc}
1246      */
1247     @Override
1248     public long getUnsignedInt(int index) {
1249         return getInt(index) & 0xffffffffL;
1250     }
1251 
1252     /**
1253      * {@inheritDoc}
1254      */
1255     @Override
1256     public InputStream asInputStream() {
1257         return new InputStream() {
1258             @Override
1259             public int available() {
1260                 return AbstractIoBuffer.this.remaining();
1261             }
1262 
1263             @Override
1264             public synchronized void mark(int readlimit) {
1265                 AbstractIoBuffer.this.mark();
1266             }
1267 
1268             @Override
1269             public boolean markSupported() {
1270                 return true;
1271             }
1272 
1273             @Override
1274             public int read() {
1275                 if (AbstractIoBuffer.this.hasRemaining()) {
1276                     return AbstractIoBuffer.this.get() & 0xff;
1277                 } else {
1278                     return -1;
1279                 }
1280             }
1281 
1282             @Override
1283             public int read(byte[] b, int off, int len) {
1284                 int remaining = AbstractIoBuffer.this.remaining();
1285                 if (remaining > 0) {
1286                     int readBytes = Math.min(remaining, len);
1287                     AbstractIoBuffer.this.get(b, off, readBytes);
1288                     return readBytes;
1289                 } else {
1290                     return -1;
1291                 }
1292             }
1293 
1294             @Override
1295             public synchronized void reset() {
1296                 AbstractIoBuffer.this.reset();
1297             }
1298 
1299             @Override
1300             public long skip(long n) {
1301                 int bytes;
1302                 if (n > Integer.MAX_VALUE) {
1303                     bytes = AbstractIoBuffer.this.remaining();
1304                 } else {
1305                     bytes = Math
1306                             .min(AbstractIoBuffer.this.remaining(), (int) n);
1307                 }
1308                 AbstractIoBuffer.this.skip(bytes);
1309                 return bytes;
1310             }
1311         };
1312     }
1313 
1314     /**
1315      * {@inheritDoc}
1316      */
1317     @Override
1318     public OutputStream asOutputStream() {
1319         return new OutputStream() {
1320             @Override
1321             public void write(byte[] b, int off, int len) {
1322                 AbstractIoBuffer.this.put(b, off, len);
1323             }
1324 
1325             @Override
1326             public void write(int b) {
1327                 AbstractIoBuffer.this.put((byte) b);
1328             }
1329         };
1330     }
1331 
1332     /**
1333      * {@inheritDoc}
1334      */
1335     @Override
1336     public String getHexDump() {
1337         return this.getHexDump(Integer.MAX_VALUE);
1338     }
1339 
1340     /**
1341      * {@inheritDoc}
1342      */
1343     @Override
1344     public String getHexDump(int lengthLimit) {
1345         return IoBufferHexDumper.getHexdump(this, lengthLimit);
1346     }
1347 
1348     /**
1349      * {@inheritDoc}
1350      */
1351     @Override
1352     public String getString(CharsetDecoder decoder)
1353             throws CharacterCodingException {
1354         if (!hasRemaining()) {
1355             return "";
1356         }
1357 
1358         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1359 
1360         int oldPos = position();
1361         int oldLimit = limit();
1362         int end = -1;
1363         int newPos;
1364 
1365         if (!utf16) {
1366             end = indexOf((byte) 0x00);
1367             if (end < 0) {
1368                 newPos = end = oldLimit;
1369             } else {
1370                 newPos = end + 1;
1371             }
1372         } else {
1373             int i = oldPos;
1374             for (;;) {
1375                 boolean wasZero = get(i) == 0;
1376                 i++;
1377 
1378                 if (i >= oldLimit) {
1379                     break;
1380                 }
1381 
1382                 if (get(i) != 0) {
1383                     i++;
1384                     if (i >= oldLimit) {
1385                         break;
1386                     } else {
1387                         continue;
1388                     }
1389                 }
1390 
1391                 if (wasZero) {
1392                     end = i - 1;
1393                     break;
1394                 }
1395             }
1396 
1397             if (end < 0) {
1398                 newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE);
1399             } else {
1400                 if (end + 2 <= oldLimit) {
1401                     newPos = end + 2;
1402                 } else {
1403                     newPos = end;
1404                 }
1405             }
1406         }
1407 
1408         if (oldPos == end) {
1409             position(newPos);
1410             return "";
1411         }
1412 
1413         limit(end);
1414         decoder.reset();
1415 
1416         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1417         CharBuffer out = CharBuffer.allocate(expectedLength);
1418         for (;;) {
1419             CoderResult cr;
1420             if (hasRemaining()) {
1421                 cr = decoder.decode(buf(), out, true);
1422             } else {
1423                 cr = decoder.flush(out);
1424             }
1425 
1426             if (cr.isUnderflow()) {
1427                 break;
1428             }
1429 
1430             if (cr.isOverflow()) {
1431                 CharBuffer o = CharBuffer.allocate(out.capacity()
1432                         + expectedLength);
1433                 out.flip();
1434                 o.put(out);
1435                 out = o;
1436                 continue;
1437             }
1438 
1439             if (cr.isError()) {
1440                 // Revert the buffer back to the previous state.
1441                 limit(oldLimit);
1442                 position(oldPos);
1443                 cr.throwException();
1444             }
1445         }
1446 
1447         limit(oldLimit);
1448         position(newPos);
1449         return out.flip().toString();
1450     }
1451 
1452     /**
1453      * {@inheritDoc}
1454      */
1455     @Override
1456     public String getString(int fieldSize, CharsetDecoder decoder)
1457             throws CharacterCodingException {
1458         checkFieldSize(fieldSize);
1459 
1460         if (fieldSize == 0) {
1461             return "";
1462         }
1463 
1464         if (!hasRemaining()) {
1465             return "";
1466         }
1467 
1468         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1469 
1470         if (utf16 && (fieldSize & 1) != 0) {
1471             throw new IllegalArgumentException("fieldSize is not even.");
1472         }
1473 
1474         int oldPos = position();
1475         int oldLimit = limit();
1476         int end = oldPos + fieldSize;
1477 
1478         if (oldLimit < end) {
1479             throw new BufferUnderflowException();
1480         }
1481 
1482         int i;
1483 
1484         if (!utf16) {
1485             for (i = oldPos; i < end; i++) {
1486                 if (get(i) == 0) {
1487                     break;
1488                 }
1489             }
1490 
1491             if (i == end) {
1492                 limit(end);
1493             } else {
1494                 limit(i);
1495             }
1496         } else {
1497             for (i = oldPos; i < end; i += 2) {
1498                 if (get(i) == 0 && get(i + 1) == 0) {
1499                     break;
1500                 }
1501             }
1502 
1503             if (i == end) {
1504                 limit(end);
1505             } else {
1506                 limit(i);
1507             }
1508         }
1509 
1510         if (!hasRemaining()) {
1511             limit(oldLimit);
1512             position(end);
1513             return "";
1514         }
1515         decoder.reset();
1516 
1517         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1518         CharBuffer out = CharBuffer.allocate(expectedLength);
1519         for (;;) {
1520             CoderResult cr;
1521             if (hasRemaining()) {
1522                 cr = decoder.decode(buf(), out, true);
1523             } else {
1524                 cr = decoder.flush(out);
1525             }
1526 
1527             if (cr.isUnderflow()) {
1528                 break;
1529             }
1530 
1531             if (cr.isOverflow()) {
1532                 CharBuffer o = CharBuffer.allocate(out.capacity()
1533                         + expectedLength);
1534                 out.flip();
1535                 o.put(out);
1536                 out = o;
1537                 continue;
1538             }
1539 
1540             if (cr.isError()) {
1541                 // Revert the buffer back to the previous state.
1542                 limit(oldLimit);
1543                 position(oldPos);
1544                 cr.throwException();
1545             }
1546         }
1547 
1548         limit(oldLimit);
1549         position(end);
1550         return out.flip().toString();
1551     }
1552 
1553     /**
1554      * {@inheritDoc}
1555      */
1556     @Override
1557     public IoBuffer putString(CharSequence val, CharsetEncoder encoder)
1558             throws CharacterCodingException {
1559         if (val.length() == 0) {
1560             return this;
1561         }
1562 
1563         CharBuffer in = CharBuffer.wrap(val);
1564         encoder.reset();
1565 
1566         int expandedState = 0;
1567 
1568         for (;;) {
1569             CoderResult cr;
1570             if (in.hasRemaining()) {
1571                 cr = encoder.encode(in, buf(), true);
1572             } else {
1573                 cr = encoder.flush(buf());
1574             }
1575 
1576             if (cr.isUnderflow()) {
1577                 break;
1578             }
1579             if (cr.isOverflow()) {
1580                 if (isAutoExpand()) {
1581                     switch (expandedState) {
1582                     case 0:
1583                         autoExpand((int) Math.ceil(in.remaining()
1584                                 * encoder.averageBytesPerChar()));
1585                         expandedState++;
1586                         break;
1587                     case 1:
1588                         autoExpand((int) Math.ceil(in.remaining()
1589                                 * encoder.maxBytesPerChar()));
1590                         expandedState++;
1591                         break;
1592                     default:
1593                         throw new RuntimeException("Expanded by "
1594                                 + (int) Math.ceil(in.remaining()
1595                                         * encoder.maxBytesPerChar())
1596                                 + " but that wasn't enough for '" + val + "'");
1597                     }
1598                     continue;
1599                 }
1600             } else {
1601                 expandedState = 0;
1602             }
1603             cr.throwException();
1604         }
1605         return this;
1606     }
1607 
1608     /**
1609      * {@inheritDoc}
1610      */
1611     @Override
1612     public IoBuffer putString(CharSequence val, int fieldSize,
1613             CharsetEncoder encoder) throws CharacterCodingException {
1614         checkFieldSize(fieldSize);
1615 
1616         if (fieldSize == 0) {
1617             return this;
1618         }
1619 
1620         autoExpand(fieldSize);
1621 
1622         boolean utf16 = encoder.charset().name().startsWith("UTF-16");
1623 
1624         if (utf16 && (fieldSize & 1) != 0) {
1625             throw new IllegalArgumentException("fieldSize is not even.");
1626         }
1627 
1628         int oldLimit = limit();
1629         int end = position() + fieldSize;
1630 
1631         if (oldLimit < end) {
1632             throw new BufferOverflowException();
1633         }
1634 
1635         if (val.length() == 0) {
1636             if (!utf16) {
1637                 put((byte) 0x00);
1638             } else {
1639                 put((byte) 0x00);
1640                 put((byte) 0x00);
1641             }
1642             position(end);
1643             return this;
1644         }
1645 
1646         CharBuffer in = CharBuffer.wrap(val);
1647         limit(end);
1648         encoder.reset();
1649 
1650         for (;;) {
1651             CoderResult cr;
1652             if (in.hasRemaining()) {
1653                 cr = encoder.encode(in, buf(), true);
1654             } else {
1655                 cr = encoder.flush(buf());
1656             }
1657 
1658             if (cr.isUnderflow() || cr.isOverflow()) {
1659                 break;
1660             }
1661             cr.throwException();
1662         }
1663 
1664         limit(oldLimit);
1665 
1666         if (position() < end) {
1667             if (!utf16) {
1668                 put((byte) 0x00);
1669             } else {
1670                 put((byte) 0x00);
1671                 put((byte) 0x00);
1672             }
1673         }
1674 
1675         position(end);
1676         return this;
1677     }
1678 
1679     /**
1680      * {@inheritDoc}
1681      */
1682     @Override
1683     public String getPrefixedString(CharsetDecoder decoder)
1684             throws CharacterCodingException {
1685         return getPrefixedString(2, decoder);
1686     }
1687 
1688     /**
1689      * Reads a string which has a length field before the actual
1690      * encoded string, using the specified <code>decoder</code> and returns it.
1691      *
1692      * @param prefixLength the length of the length field (1, 2, or 4)
1693      * @param decoder the decoder to use for decoding the string
1694      * @return the prefixed string
1695      * @throws CharacterCodingException when decoding fails
1696      * @throws BufferUnderflowException when there is not enough data available
1697      */
1698     @Override
1699     public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
1700             throws CharacterCodingException {
1701         if (!prefixedDataAvailable(prefixLength)) {
1702             throw new BufferUnderflowException();
1703         }
1704 
1705         int fieldSize = 0;
1706 
1707         switch (prefixLength) {
1708         case 1:
1709             fieldSize = getUnsigned();
1710             break;
1711         case 2:
1712             fieldSize = getUnsignedShort();
1713             break;
1714         case 4:
1715             fieldSize = getInt();
1716             break;
1717         }
1718 
1719         if (fieldSize == 0) {
1720             return "";
1721         }
1722 
1723         boolean utf16 = decoder.charset().name().startsWith("UTF-16");
1724 
1725         if (utf16 && (fieldSize & 1) != 0) {
1726             throw new BufferDataException(
1727                     "fieldSize is not even for a UTF-16 string.");
1728         }
1729 
1730         int oldLimit = limit();
1731         int end = position() + fieldSize;
1732 
1733         if (oldLimit < end) {
1734             throw new BufferUnderflowException();
1735         }
1736 
1737         limit(end);
1738         decoder.reset();
1739 
1740         int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
1741         CharBuffer out = CharBuffer.allocate(expectedLength);
1742         for (;;) {
1743             CoderResult cr;
1744             if (hasRemaining()) {
1745                 cr = decoder.decode(buf(), out, true);
1746             } else {
1747                 cr = decoder.flush(out);
1748             }
1749 
1750             if (cr.isUnderflow()) {
1751                 break;
1752             }
1753 
1754             if (cr.isOverflow()) {
1755                 CharBuffer o = CharBuffer.allocate(out.capacity()
1756                         + expectedLength);
1757                 out.flip();
1758                 o.put(out);
1759                 out = o;
1760                 continue;
1761             }
1762 
1763             cr.throwException();
1764         }
1765 
1766         limit(oldLimit);
1767         position(end);
1768         return out.flip().toString();
1769     }
1770 
1771     /**
1772      * {@inheritDoc}
1773      */
1774     @Override
1775     public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
1776             throws CharacterCodingException {
1777         return putPrefixedString(in, 2, 0, encoder);
1778     }
1779 
1780     /**
1781      * {@inheritDoc}
1782      */
1783     @Override
1784     public IoBuffer putPrefixedString(CharSequence in, int prefixLength,
1785             CharsetEncoder encoder) throws CharacterCodingException {
1786         return putPrefixedString(in, prefixLength, 0, encoder);
1787     }
1788 
1789     /**
1790      * {@inheritDoc}
1791      */
1792     @Override
1793     public IoBuffer putPrefixedString(CharSequence in, int prefixLength,
1794             int padding, CharsetEncoder encoder)
1795             throws CharacterCodingException {
1796         return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
1797     }
1798 
1799     /**
1800      * {@inheritDoc}
1801      */
1802     @Override
1803     public IoBuffer putPrefixedString(CharSequence val, int prefixLength,
1804             int padding, byte padValue, CharsetEncoder encoder)
1805             throws CharacterCodingException {
1806         int maxLength;
1807         switch (prefixLength) {
1808         case 1:
1809             maxLength = 255;
1810             break;
1811         case 2:
1812             maxLength = 65535;
1813             break;
1814         case 4:
1815             maxLength = Integer.MAX_VALUE;
1816             break;
1817         default:
1818             throw new IllegalArgumentException("prefixLength: " + prefixLength);
1819         }
1820 
1821         if (val.length() > maxLength) {
1822             throw new IllegalArgumentException(
1823                     "The specified string is too long.");
1824         }
1825         if (val.length() == 0) {
1826             switch (prefixLength) {
1827             case 1:
1828                 put((byte) 0);
1829                 break;
1830             case 2:
1831                 putShort((short) 0);
1832                 break;
1833             case 4:
1834                 putInt(0);
1835                 break;
1836             }
1837             return this;
1838         }
1839 
1840         int padMask;
1841         switch (padding) {
1842         case 0:
1843         case 1:
1844             padMask = 0;
1845             break;
1846         case 2:
1847             padMask = 1;
1848             break;
1849         case 4:
1850             padMask = 3;
1851             break;
1852         default:
1853             throw new IllegalArgumentException("padding: " + padding);
1854         }
1855 
1856         CharBuffer in = CharBuffer.wrap(val);
1857         skip(prefixLength); // make a room for the length field
1858         int oldPos = position();
1859         encoder.reset();
1860 
1861         int expandedState = 0;
1862 
1863         for (;;) {
1864             CoderResult cr;
1865             if (in.hasRemaining()) {
1866                 cr = encoder.encode(in, buf(), true);
1867             } else {
1868                 cr = encoder.flush(buf());
1869             }
1870 
1871             if (position() - oldPos > maxLength) {
1872                 throw new IllegalArgumentException(
1873                         "The specified string is too long.");
1874             }
1875 
1876             if (cr.isUnderflow()) {
1877                 break;
1878             }
1879             if (cr.isOverflow()) {
1880                 if (isAutoExpand()) {
1881                     switch (expandedState) {
1882                     case 0:
1883                         autoExpand((int) Math.ceil(in.remaining()
1884                                 * encoder.averageBytesPerChar()));
1885                         expandedState++;
1886                         break;
1887                     case 1:
1888                         autoExpand((int) Math.ceil(in.remaining()
1889                                 * encoder.maxBytesPerChar()));
1890                         expandedState++;
1891                         break;
1892                     default:
1893                         throw new RuntimeException("Expanded by "
1894                                 + (int) Math.ceil(in.remaining()
1895                                         * encoder.maxBytesPerChar())
1896                                 + " but that wasn't enough for '" + val + "'");
1897                     }
1898                     continue;
1899                 }
1900             } else {
1901                 expandedState = 0;
1902             }
1903             cr.throwException();
1904         }
1905 
1906         // Write the length field
1907         fill(padValue, padding - (position() - oldPos & padMask));
1908         int length = position() - oldPos;
1909         switch (prefixLength) {
1910         case 1:
1911             put(oldPos - 1, (byte) length);
1912             break;
1913         case 2:
1914             putShort(oldPos - 2, (short) length);
1915             break;
1916         case 4:
1917             putInt(oldPos - 4, length);
1918             break;
1919         }
1920         return this;
1921     }
1922 
1923     /**
1924      * {@inheritDoc}
1925      */
1926     @Override
1927     public Object getObject() throws ClassNotFoundException {
1928         return getObject(Thread.currentThread().getContextClassLoader());
1929     }
1930 
1931     /**
1932      * {@inheritDoc}
1933      */
1934     @Override
1935     public Object getObject(final ClassLoader classLoader)
1936             throws ClassNotFoundException {
1937         if (!prefixedDataAvailable(4)) {
1938             throw new BufferUnderflowException();
1939         }
1940 
1941         int length = getInt();
1942         if (length <= 4) {
1943             throw new BufferDataException(
1944                     "Object length should be greater than 4: " + length);
1945         }
1946 
1947         int oldLimit = limit();
1948         limit(position() + length);
1949         try {
1950             ObjectInputStream in = new ObjectInputStream(asInputStream()) {
1951                 @Override
1952                 protected ObjectStreamClass readClassDescriptor()
1953                         throws IOException, ClassNotFoundException {
1954                     int type = read();
1955                     if (type < 0) {
1956                         throw new EOFException();
1957                     }
1958                     switch (type) {
1959                     case 0: // Primitive types
1960                         return super.readClassDescriptor();
1961                     case 1: // Non-primitive types
1962                         String className = readUTF();
1963                         Class<?> clazz = Class.forName(className, true,
1964                                 classLoader);
1965                         return ObjectStreamClass.lookup(clazz);
1966                     default:
1967                         throw new StreamCorruptedException(
1968                                 "Unexpected class descriptor type: " + type);
1969                     }
1970                 }
1971 
1972                 @Override
1973                 protected Class<?> resolveClass(ObjectStreamClass desc)
1974                         throws IOException, ClassNotFoundException {
1975                     String name = desc.getName();
1976                     try {
1977                         return Class.forName(name, false, classLoader);
1978                     } catch (ClassNotFoundException ex) {
1979                         return super.resolveClass(desc);
1980                     }
1981                 }
1982             };
1983             return in.readObject();
1984         } catch (IOException e) {
1985             throw new BufferDataException(e);
1986         } finally {
1987             limit(oldLimit);
1988         }
1989     }
1990 
1991     /**
1992      * {@inheritDoc}
1993      */
1994     @Override
1995     public IoBuffer putObject(Object o) {
1996         int oldPos = position();
1997         skip(4); // Make a room for the length field.
1998         try {
1999             ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
2000                 @Override
2001                 protected void writeClassDescriptor(ObjectStreamClass desc)
2002                         throws IOException {
2003                     if (desc.forClass().isPrimitive()) {
2004                         write(0);
2005                         super.writeClassDescriptor(desc);
2006                     } else {
2007                         write(1);
2008                         writeUTF(desc.getName());
2009                     }
2010                 }
2011             };
2012             out.writeObject(o);
2013             out.flush();
2014         } catch (IOException e) {
2015             throw new BufferDataException(e);
2016         }
2017 
2018         // Fill the length field
2019         int newPos = position();
2020         position(oldPos);
2021         putInt(newPos - oldPos - 4);
2022         position(newPos);
2023         return this;
2024     }
2025 
2026     /**
2027      * {@inheritDoc}
2028      */
2029     @Override
2030     public boolean prefixedDataAvailable(int prefixLength) {
2031         return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
2032     }
2033 
2034     /**
2035      * {@inheritDoc}
2036      */
2037     @Override
2038     public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
2039         if (remaining() < prefixLength) {
2040             return false;
2041         }
2042 
2043         int dataLength;
2044         switch (prefixLength) {
2045         case 1:
2046             dataLength = getUnsigned(position());
2047             break;
2048         case 2:
2049             dataLength = getUnsignedShort(position());
2050             break;
2051         case 4:
2052             dataLength = getInt(position());
2053             break;
2054         default:
2055             throw new IllegalArgumentException("prefixLength: " + prefixLength);
2056         }
2057 
2058         if (dataLength < 0 || dataLength > maxDataLength) {
2059             throw new BufferDataException("dataLength: " + dataLength);
2060         }
2061 
2062         return remaining() - prefixLength >= dataLength;
2063     }
2064 
2065     /**
2066      * {@inheritDoc}
2067      */
2068     @Override
2069     public int indexOf(byte b) {
2070         if (hasArray()) {
2071             int arrayOffset = arrayOffset();
2072             int beginPos = arrayOffset + position();
2073             int limit = arrayOffset + limit();
2074             byte[] array = array();
2075 
2076             for (int i = beginPos; i < limit; i++) {
2077                 if (array[i] == b) {
2078                     return i - arrayOffset;
2079                 }
2080             }
2081         } else {
2082             int beginPos = position();
2083             int limit = limit();
2084 
2085             for (int i = beginPos; i < limit; i++) {
2086                 if (get(i) == b) {
2087                     return i;
2088                 }
2089             }
2090         }
2091 
2092         return -1;
2093     }
2094 
2095     /**
2096      * {@inheritDoc}
2097      */
2098     @Override
2099     public IoBuffer skip(int size) {
2100         autoExpand(size);
2101         return position(position() + size);
2102     }
2103 
2104     /**
2105      * {@inheritDoc}
2106      */
2107     @Override
2108     public IoBuffer fill(byte value, int size) {
2109         autoExpand(size);
2110         int q = size >>> 3;
2111         int r = size & 7;
2112 
2113         if (q > 0) {
2114             int intValue = value | value << 8 | value << 16 | value << 24;
2115             long longValue = intValue;
2116             longValue <<= 32;
2117             longValue |= intValue;
2118 
2119             for (int i = q; i > 0; i--) {
2120                 putLong(longValue);
2121             }
2122         }
2123 
2124         q = r >>> 2;
2125         r = r & 3;
2126 
2127         if (q > 0) {
2128             int intValue = value | value << 8 | value << 16 | value << 24;
2129             putInt(intValue);
2130         }
2131 
2132         q = r >> 1;
2133         r = r & 1;
2134 
2135         if (q > 0) {
2136             short shortValue = (short) (value | value << 8);
2137             putShort(shortValue);
2138         }
2139 
2140         if (r > 0) {
2141             put(value);
2142         }
2143 
2144         return this;
2145     }
2146 
2147     /**
2148      * {@inheritDoc}
2149      */
2150     @Override
2151     public IoBuffer fillAndReset(byte value, int size) {
2152         autoExpand(size);
2153         int pos = position();
2154         try {
2155             fill(value, size);
2156         } finally {
2157             position(pos);
2158         }
2159         return this;
2160     }
2161 
2162     /**
2163      * {@inheritDoc}
2164      */
2165     @Override
2166     public IoBuffer fill(int size) {
2167         autoExpand(size);
2168         int q = size >>> 3;
2169         int r = size & 7;
2170 
2171         for (int i = q; i > 0; i--) {
2172             putLong(0L);
2173         }
2174 
2175         q = r >>> 2;
2176         r = r & 3;
2177 
2178         if (q > 0) {
2179             putInt(0);
2180         }
2181 
2182         q = r >> 1;
2183         r = r & 1;
2184 
2185         if (q > 0) {
2186             putShort((short) 0);
2187         }
2188 
2189         if (r > 0) {
2190             put((byte) 0);
2191         }
2192 
2193         return this;
2194     }
2195 
2196     /**
2197      * {@inheritDoc}
2198      */
2199     @Override
2200     public IoBuffer fillAndReset(int size) {
2201         autoExpand(size);
2202         int pos = position();
2203         try {
2204             fill(size);
2205         } finally {
2206             position(pos);
2207         }
2208 
2209         return this;
2210     }
2211 
2212     /**
2213      * {@inheritDoc}
2214      */
2215     @Override
2216     public <E extends Enum<E>> E getEnum(Class<E> enumClass) {
2217         return toEnum(enumClass, getUnsigned());
2218     }
2219 
2220     /**
2221      * {@inheritDoc}
2222      */
2223     @Override
2224     public <E extends Enum<E>> E getEnum(int index, Class<E> enumClass) {
2225         return toEnum(enumClass, getUnsigned(index));
2226     }
2227 
2228     /**
2229      * {@inheritDoc}
2230      */
2231     @Override
2232     public <E extends Enum<E>> E getEnumShort(Class<E> enumClass) {
2233         return toEnum(enumClass, getUnsignedShort());
2234     }
2235 
2236     /**
2237      * {@inheritDoc}
2238      */
2239     @Override
2240     public <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass) {
2241         return toEnum(enumClass, getUnsignedShort(index));
2242     }
2243 
2244     /**
2245      * {@inheritDoc}
2246      */
2247     @Override
2248     public <E extends Enum<E>> E getEnumInt(Class<E> enumClass) {
2249         return toEnum(enumClass, getInt());
2250     }
2251 
2252     /**
2253      * {@inheritDoc}
2254      */
2255     public <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass) {
2256         return toEnum(enumClass, getInt(index));
2257     }
2258 
2259     /**
2260      * {@inheritDoc}
2261      */
2262     @Override
2263     public IoBuffer putEnum(Enum<?> e) {
2264         if (e.ordinal() > BYTE_MASK) {
2265             throw new IllegalArgumentException(enumConversionErrorMessage(e,
2266                     "byte"));
2267         }
2268         return put((byte) e.ordinal());
2269     }
2270 
2271     /**
2272      * {@inheritDoc}
2273      */
2274     @Override
2275     public IoBuffer putEnum(int index, Enum<?> e) {
2276         if (e.ordinal() > BYTE_MASK) {
2277             throw new IllegalArgumentException(enumConversionErrorMessage(e,
2278                     "byte"));
2279         }
2280         return put(index, (byte) e.ordinal());
2281     }
2282 
2283     /**
2284      * {@inheritDoc}
2285      */
2286     @Override
2287     public IoBuffer putEnumShort(Enum<?> e) {
2288         if (e.ordinal() > SHORT_MASK) {
2289             throw new IllegalArgumentException(enumConversionErrorMessage(e,
2290                     "short"));
2291         }
2292         return putShort((short) e.ordinal());
2293     }
2294 
2295     /**
2296      * {@inheritDoc}
2297      */
2298     @Override
2299     public IoBuffer putEnumShort(int index, Enum<?> e) {
2300         if (e.ordinal() > SHORT_MASK) {
2301             throw new IllegalArgumentException(enumConversionErrorMessage(e,
2302                     "short"));
2303         }
2304         return putShort(index, (short) e.ordinal());
2305     }
2306 
2307     /**
2308      * {@inheritDoc}
2309      */
2310     @Override
2311     public IoBuffer putEnumInt(Enum<?> e) {
2312         return putInt(e.ordinal());
2313     }
2314 
2315     /**
2316      * {@inheritDoc}
2317      */
2318     @Override
2319     public IoBuffer putEnumInt(int index, Enum<?> e) {
2320         return putInt(index, e.ordinal());
2321     }
2322 
2323     private <E> E toEnum(Class<E> enumClass, int i) {
2324         E[] enumConstants = enumClass.getEnumConstants();
2325         if (i > enumConstants.length) {
2326             throw new IndexOutOfBoundsException(String.format(
2327                     "%d is too large of an ordinal to convert to the enum %s",
2328                     i, enumClass.getName()));
2329         }
2330         return enumConstants[i];
2331     }
2332 
2333     private String enumConversionErrorMessage(Enum<?> e, String type) {
2334         return String.format("%s.%s has an ordinal value too large for a %s", e
2335                 .getClass().getName(), e.name(), type);
2336     }
2337 
2338     /**
2339      * {@inheritDoc}
2340      */
2341     @Override
2342     public <E extends Enum<E>> EnumSet<E> getEnumSet(Class<E> enumClass) {
2343         return toEnumSet(enumClass, get() & BYTE_MASK);
2344     }
2345 
2346     /**
2347      * {@inheritDoc}
2348      */
2349     @Override
2350     public <E extends Enum<E>> EnumSet<E> getEnumSet(int index,
2351             Class<E> enumClass) {
2352         return toEnumSet(enumClass, get(index) & BYTE_MASK);
2353     }
2354 
2355     /**
2356      * {@inheritDoc}
2357      */
2358     @Override
2359     public <E extends Enum<E>> EnumSet<E> getEnumSetShort(Class<E> enumClass) {
2360         return toEnumSet(enumClass, getShort() & SHORT_MASK);
2361     }
2362 
2363     /**
2364      * {@inheritDoc}
2365      */
2366     @Override
2367     public <E extends Enum<E>> EnumSet<E> getEnumSetShort(int index,
2368             Class<E> enumClass) {
2369         return toEnumSet(enumClass, getShort(index) & SHORT_MASK);
2370     }
2371 
2372     /**
2373      * {@inheritDoc}
2374      */
2375     @Override
2376     public <E extends Enum<E>> EnumSet<E> getEnumSetInt(Class<E> enumClass) {
2377         return toEnumSet(enumClass, getInt() & INT_MASK);
2378     }
2379 
2380     /**
2381      * {@inheritDoc}
2382      */
2383     @Override
2384     public <E extends Enum<E>> EnumSet<E> getEnumSetInt(int index,
2385             Class<E> enumClass) {
2386         return toEnumSet(enumClass, getInt(index) & INT_MASK);
2387     }
2388 
2389     /**
2390      * {@inheritDoc}
2391      */
2392     @Override
2393     public <E extends Enum<E>> EnumSet<E> getEnumSetLong(Class<E> enumClass) {
2394         return toEnumSet(enumClass, getLong());
2395     }
2396 
2397     /**
2398      * {@inheritDoc}
2399      */
2400     @Override
2401     public <E extends Enum<E>> EnumSet<E> getEnumSetLong(int index,
2402             Class<E> enumClass) {
2403         return toEnumSet(enumClass, getLong(index));
2404     }
2405 
2406     private <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> clazz, long vector) {
2407         EnumSet<E> set = EnumSet.noneOf(clazz);
2408         long mask = 1;
2409         for (E e : clazz.getEnumConstants()) {
2410             if ((mask & vector) == mask) {
2411                 set.add(e);
2412             }
2413             mask <<= 1;
2414         }
2415         return set;
2416     }
2417 
2418     /**
2419      * {@inheritDoc}
2420      */
2421     @Override
2422     public <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set) {
2423         long vector = toLong(set);
2424         if ((vector & ~BYTE_MASK) != 0) {
2425             throw new IllegalArgumentException(
2426                     "The enum set is too large to fit in a byte: " + set);
2427         }
2428         return put((byte) vector);
2429     }
2430 
2431     /**
2432      * {@inheritDoc}
2433      */
2434     @Override
2435     public <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set) {
2436         long vector = toLong(set);
2437         if ((vector & ~BYTE_MASK) != 0) {
2438             throw new IllegalArgumentException(
2439                     "The enum set is too large to fit in a byte: " + set);
2440         }
2441         return put(index, (byte) vector);
2442     }
2443 
2444     /**
2445      * {@inheritDoc}
2446      */
2447     @Override
2448     public <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set) {
2449         long vector = toLong(set);
2450         if ((vector & ~SHORT_MASK) != 0) {
2451             throw new IllegalArgumentException(
2452                     "The enum set is too large to fit in a short: " + set);
2453         }
2454         return putShort((short) vector);
2455     }
2456 
2457     /**
2458      * {@inheritDoc}
2459      */
2460     @Override
2461     public <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set) {
2462         long vector = toLong(set);
2463         if ((vector & ~SHORT_MASK) != 0) {
2464             throw new IllegalArgumentException(
2465                     "The enum set is too large to fit in a short: " + set);
2466         }
2467         return putShort(index, (short) vector);
2468     }
2469 
2470     /**
2471      * {@inheritDoc}
2472      */
2473     @Override
2474     public <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set) {
2475         long vector = toLong(set);
2476         if ((vector & ~INT_MASK) != 0) {
2477             throw new IllegalArgumentException(
2478                     "The enum set is too large to fit in an int: " + set);
2479         }
2480         return putInt((int) vector);
2481     }
2482 
2483     /**
2484      * {@inheritDoc}
2485      */
2486     @Override
2487     public <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set) {
2488         long vector = toLong(set);
2489         if ((vector & ~INT_MASK) != 0) {
2490             throw new IllegalArgumentException(
2491                     "The enum set is too large to fit in an int: " + set);
2492         }
2493         return putInt(index, (int) vector);
2494     }
2495 
2496     /**
2497      * {@inheritDoc}
2498      */
2499     @Override
2500     public <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set) {
2501         return putLong(toLong(set));
2502     }
2503 
2504     /**
2505      * {@inheritDoc}
2506      */
2507     @Override
2508     public <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set) {
2509         return putLong(index, toLong(set));
2510     }
2511 
2512     private <E extends Enum<E>> long toLong(Set<E> set) {
2513         long vector = 0;
2514         for (E e : set) {
2515             if (e.ordinal() >= Long.SIZE) {
2516                 throw new IllegalArgumentException(
2517                         "The enum set is too large to fit in a bit vector: "
2518                                 + set);
2519             }
2520             vector |= 1L << e.ordinal();
2521         }
2522         return vector;
2523     }
2524 
2525     /**
2526      * This method forwards the call to {@link #expand(int)} only when
2527      * <tt>autoExpand</tt> property is <tt>true</tt>.
2528      */
2529     private IoBuffer autoExpand(int expectedRemaining) {
2530         if (isAutoExpand()) {
2531             expand(expectedRemaining, true);
2532         }
2533         return this;
2534     }
2535 
2536     /**
2537      * This method forwards the call to {@link #expand(int)} only when
2538      * <tt>autoExpand</tt> property is <tt>true</tt>.
2539      */
2540     private IoBuffer autoExpand(int pos, int expectedRemaining) {
2541         if (isAutoExpand()) {
2542             expand(pos, expectedRemaining, true);
2543         }
2544         return this;
2545     }
2546 
2547     private static void checkFieldSize(int fieldSize) {
2548         if (fieldSize < 0) {
2549             throw new IllegalArgumentException("fieldSize cannot be negative: "
2550                     + fieldSize);
2551         }
2552     }
2553 }