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