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