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.util.byteaccess;
21  
22  import java.nio.ByteOrder;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  
27  import org.apache.mina.core.buffer.IoBuffer;
28  import org.apache.mina.util.byteaccess.ByteArrayList.Node;
29  
30  /**
31   * A ByteArray composed of other ByteArrays. Optimised for fast relative access
32   * via cursors. Absolute access methods are provided, but may perform poorly.
33   *
34   * TODO: Write about laziness of cursor implementation - how movement doesn't
35   * happen until actual get/put.
36   * 
37   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
38   */
39  public final class CompositeByteArray extends AbstractByteArray {
40  
41      /**
42       * Allows for efficient detection of component boundaries when using a cursor.
43       *
44       * TODO: Is this interface right?
45       */
46      public interface CursorListener {
47  
48          /**
49           * Called when the first component in the composite is entered by the cursor.
50           */
51          public void enteredFirstComponent(int componentIndex, ByteArray component);
52  
53          /**
54           * Called when the next component in the composite is entered by the cursor.
55           */
56          public void enteredNextComponent(int componentIndex, ByteArray component);
57  
58          /**
59           * Called when the previous component in the composite is entered by the cursor.
60           */
61          public void enteredPreviousComponent(int componentIndex, ByteArray component);
62  
63          /**
64           * Called when the last component in the composite is entered by the cursor.
65           */
66          public void enteredLastComponent(int componentIndex, ByteArray component);
67      }
68  
69      /**
70       * Stores the underlying <code>ByteArray</code>s.
71       */
72      private final ByteArrayList bas = new ByteArrayList();
73  
74      /**
75       * The byte order for data in the buffer
76       */
77      private ByteOrder order;
78  
79      /**
80       * May be used in <code>getSingleIoBuffer</code>. Optional.
81       */
82      private final ByteArrayFactory byteArrayFactory;
83  
84      /**
85       * Creates a new instance of CompositeByteArray.
86       */
87      public CompositeByteArray() {
88          this(null);
89      }
90  
91      /**
92       * 
93       * Creates a new instance of CompositeByteArray.
94       *
95       * @param byteArrayFactory
96       *  The factory used to create the ByteArray objects
97       */
98      public CompositeByteArray(ByteArrayFactory byteArrayFactory) {
99          this.byteArrayFactory = byteArrayFactory;
100     }
101 
102     /**
103      * Returns the first {@link ByteArray} in the list
104      *
105      * @return
106      *  The first ByteArray in the list
107      */
108     public ByteArray getFirst() {
109         if (bas.isEmpty()) {
110             return null;
111         }
112 
113         return bas.getFirst().getByteArray();
114     }
115 
116     /**
117      * Adds the specified {@link ByteArray} to the first
118      * position in the list
119      *
120      * @param ba
121      *  The ByteArray to add to the list
122      */
123     public void addFirst(ByteArray ba) {
124         addHook(ba);
125         bas.addFirst(ba);
126     }
127 
128     /**
129      * Remove the first {@link ByteArray} in the list
130      *
131      * @return
132      *  The first ByteArray in the list
133      */
134     public ByteArray removeFirst() {
135         Node node = bas.removeFirst();
136         return node == null ? null : node.getByteArray();
137     }
138 
139     /**
140      * Remove component <code>ByteArray</code>s to the given index (splitting
141      * them if necessary) and returning them in a single <code>ByteArray</code>.
142      * The caller is responsible for freeing the returned object.
143      *
144      * TODO: Document free behaviour more thoroughly.
145      */
146     public ByteArray removeTo(int index) {
147         if (index < first() || index > last()) {
148             throw new IndexOutOfBoundsException();
149         }
150         // Optimisation when removing exactly one component.
151         //        if (index == start() + getFirst().length()) {
152         //            ByteArray component = getFirst();
153         //            removeFirst();
154         //            return component;
155         //        }
156         // Removing
157         CompositeByteArray prefix = new CompositeByteArray(byteArrayFactory);
158         int remaining = index - first();
159 
160         while (remaining > 0) {
161             ByteArray component = removeFirst();
162 
163             if (component.last() <= remaining) {
164                 // Remove entire component.
165                 prefix.addLast(component);
166                 remaining -= component.last();
167             } else {
168                 // Remove part of component. Do this by removing entire
169                 // component then readding remaining bytes.
170                 // TODO: Consider using getIoBuffers(), as would avoid
171                 // performance problems for nested ComponentByteArrays.
172                 IoBuffer bb = component.getSingleIoBuffer();
173                 // get the limit of the buffer
174                 int originalLimit = bb.limit();
175                 // set the position to the beginning of the buffer
176                 bb.position(0);
177                 // set the limit of the buffer to what is remaining
178                 bb.limit(remaining);
179                 // create a new IoBuffer, sharing the data with 'bb'
180                 IoBuffer bb1 = bb.slice();
181                 // set the position at the end of the buffer
182                 bb.position(remaining);
183                 // gets the limit of the buffer
184                 bb.limit(originalLimit);
185                 // create a new IoBuffer, sharing teh data with 'bb'
186                 IoBuffer bb2 = bb.slice();
187                 // create a new ByteArray with 'bb1'
188                 ByteArray ba1 = new BufferByteArray(bb1) {
189                     @Override
190                     public void free() {
191                         // Do not free.  This will get freed 
192                     }
193                 };
194 
195                 // add the new ByteArray to the CompositeByteArray
196                 prefix.addLast(ba1);
197                 remaining -= ba1.last();
198 
199                 // final for anonymous inner class
200                 final ByteArray componentFinal = component;
201                 ByteArray ba2 = new BufferByteArray(bb2) {
202                     @Override
203                     public void free() {
204                         componentFinal.free();
205                     }
206                 };
207                 // add the new ByteArray to the CompositeByteArray
208                 addFirst(ba2);
209             }
210         }
211 
212         // return the CompositeByteArray
213         return prefix;
214     }
215 
216     /**
217      * Adds the specified {@link ByteArray} to the end of the list
218      *
219      * @param ba
220      *  The ByteArray to add to the end of the list
221      */
222     public void addLast(ByteArray ba) {
223         addHook(ba);
224         bas.addLast(ba);
225     }
226 
227     /**
228      * Removes the last {@link ByteArray} in the list
229      *
230      * @return
231      *  The ByteArray that was removed
232      */
233     public ByteArray removeLast() {
234         Node node = bas.removeLast();
235         return node == null ? null : node.getByteArray();
236     }
237 
238     /**
239      * @inheritDoc
240      */
241     public void free() {
242         while (!bas.isEmpty()) {
243             Node node = bas.getLast();
244             node.getByteArray().free();
245             bas.removeLast();
246         }
247     }
248 
249     private void checkBounds(int index, int accessSize) {
250         int lower = index;
251         int upper = index + accessSize;
252 
253         if (lower < first()) {
254             throw new IndexOutOfBoundsException("Index " + lower + " less than start " + first() + ".");
255         }
256 
257         if (upper > last()) {
258             throw new IndexOutOfBoundsException("Index " + upper + " greater than length " + last() + ".");
259         }
260     }
261 
262     /**
263      * @inheritDoc
264      */
265     public Iterable<IoBuffer> getIoBuffers() {
266         if (bas.isEmpty()) {
267             return Collections.emptyList();
268         }
269 
270         Collection<IoBuffer> result = new ArrayList<IoBuffer>();
271         Node node = bas.getFirst();
272 
273         for (IoBuffer bb : node.getByteArray().getIoBuffers()) {
274             result.add(bb);
275         }
276 
277         while (node.hasNextNode()) {
278             node = node.getNextNode();
279 
280             for (IoBuffer bb : node.getByteArray().getIoBuffers()) {
281                 result.add(bb);
282             }
283         }
284 
285         return result;
286     }
287 
288     /**
289      * @inheritDoc
290      */
291     public IoBuffer getSingleIoBuffer() {
292         if (byteArrayFactory == null) {
293             throw new IllegalStateException(
294                     "Can't get single buffer from CompositeByteArray unless it has a ByteArrayFactory.");
295         }
296 
297         if (bas.isEmpty()) {
298             ByteArray ba = byteArrayFactory.create(1);
299             return ba.getSingleIoBuffer();
300         }
301 
302         int actualLength = last() - first();
303 
304         {
305             Node node = bas.getFirst();
306             ByteArray ba = node.getByteArray();
307 
308             if (ba.last() == actualLength) {
309                 return ba.getSingleIoBuffer();
310             }
311         }
312 
313         // Replace all nodes with a single node.
314         ByteArray target = byteArrayFactory.create(actualLength);
315         IoBuffer bb = target.getSingleIoBuffer();
316         Cursor cursor = cursor();
317         cursor.put(bb); // Copy all existing data into target IoBuffer.
318 
319         while (!bas.isEmpty()) {
320             Node node = bas.getLast();
321             ByteArray component = node.getByteArray();
322             bas.removeLast();
323             component.free();
324         }
325 
326         bas.addLast(target);
327         return bb;
328     }
329 
330     /**
331      * @inheritDoc
332      */
333     public Cursor cursor() {
334         return new CursorImpl();
335     }
336 
337     /**
338      * @inheritDoc
339      */
340     public Cursor cursor(int index) {
341         return new CursorImpl(index);
342     }
343 
344     /**
345      * Get a cursor starting at index 0 (which may not be the start of the
346      * array) and with the given listener.
347      * 
348      * @param listener
349      *  Returns a new {@link Cursor} instance
350      */
351     public Cursor cursor(CursorListener listener) {
352         return new CursorImpl(listener);
353     }
354 
355     /**
356      * Get a cursor starting at the given index and with the given listener.
357      * 
358      * @param index
359      *  The position of the array to start the Cursor at
360      * @param listener
361      *  The listener for the Cursor that is returned
362      */
363     public Cursor cursor(int index, CursorListener listener) {
364         return new CursorImpl(index, listener);
365     }
366 
367     /**
368      * @inheritDoc
369      */
370     public ByteArray slice(int index, int length) {
371         return cursor(index).slice(length);
372     }
373 
374     /**
375      * @inheritDoc
376      */
377     public byte get(int index) {
378         return cursor(index).get();
379     }
380 
381     /**
382      * @inheritDoc
383      */
384     public void put(int index, byte b) {
385         cursor(index).put(b);
386     }
387 
388     /**
389      * @inheritDoc
390      */
391     public void get(int index, IoBuffer bb) {
392         cursor(index).get(bb);
393     }
394 
395     /**
396      * @inheritDoc
397      */
398     public void put(int index, IoBuffer bb) {
399         cursor(index).put(bb);
400     }
401 
402     /**
403      * @inheritDoc
404      */
405     public int first() {
406         return bas.firstByte();
407     }
408 
409     /**
410      * @inheritDoc
411      */
412     public int last() {
413         return bas.lastByte();
414     }
415 
416     /**
417      * This method should be called prior to adding any component
418      * <code>ByteArray</code> to a composite.
419      *
420      * @param ba
421      *  The component to add.
422      */
423     private void addHook(ByteArray ba) {
424         // Check first() is zero, otherwise cursor might not work.
425         // TODO: Remove this restriction?
426         if (ba.first() != 0) {
427             throw new IllegalArgumentException("Cannot add byte array that doesn't start from 0: " + ba.first());
428         }
429         // Check order.
430         if (order == null) {
431             order = ba.order();
432         } else if (!order.equals(ba.order())) {
433             throw new IllegalArgumentException("Cannot add byte array with different byte order: " + ba.order());
434         }
435     }
436 
437     /**
438      * @inheritDoc
439      */
440     public ByteOrder order() {
441         if (order == null) {
442             throw new IllegalStateException("Byte order not yet set.");
443         }
444         return order;
445     }
446 
447     /**
448      * @inheritDoc
449      */
450     public void order(ByteOrder order) {
451         if (order == null || !order.equals(this.order)) {
452             this.order = order;
453 
454             if (!bas.isEmpty()) {
455                 for (Node node = bas.getFirst(); node.hasNextNode(); node = node.getNextNode()) {
456                     node.getByteArray().order(order);
457                 }
458             }
459         }
460     }
461 
462     /**
463      * @inheritDoc
464      */
465     public short getShort(int index) {
466         return cursor(index).getShort();
467     }
468 
469     /**
470      * @inheritDoc
471      */
472     public void putShort(int index, short s) {
473         cursor(index).putShort(s);
474     }
475 
476     /**
477      * @inheritDoc
478      */
479     public int getInt(int index) {
480         return cursor(index).getInt();
481     }
482 
483     /**
484      * @inheritDoc
485      */
486     public void putInt(int index, int i) {
487         cursor(index).putInt(i);
488     }
489 
490     /**
491      * @inheritDoc
492      */
493     public long getLong(int index) {
494         return cursor(index).getLong();
495     }
496 
497     /**
498      * @inheritDoc
499      */
500     public void putLong(int index, long l) {
501         cursor(index).putLong(l);
502     }
503 
504     /**
505      * @inheritDoc
506      */
507     public float getFloat(int index) {
508         return cursor(index).getFloat();
509     }
510 
511     /**
512      * @inheritDoc
513      */
514     public void putFloat(int index, float f) {
515         cursor(index).putFloat(f);
516     }
517 
518     /**
519      * @inheritDoc
520      */
521     public double getDouble(int index) {
522         return cursor(index).getDouble();
523     }
524 
525     /**
526      * @inheritDoc
527      */
528     public void putDouble(int index, double d) {
529         cursor(index).putDouble(d);
530     }
531 
532     /**
533      * @inheritDoc
534      */
535     public char getChar(int index) {
536         return cursor(index).getChar();
537     }
538 
539     /**
540      * @inheritDoc
541      */
542     public void putChar(int index, char c) {
543         cursor(index).putChar(c);
544     }
545 
546     private class CursorImpl implements Cursor {
547 
548         private int index;
549 
550         private final CursorListener listener;
551 
552         private Node componentNode;
553 
554         // Index of start of current component.
555         private int componentIndex;
556 
557         // Cursor within current component.
558         private ByteArray.Cursor componentCursor;
559 
560         public CursorImpl() {
561             this(0, null);
562         }
563 
564         public CursorImpl(int index) {
565             this(index, null);
566         }
567 
568         public CursorImpl(CursorListener listener) {
569             this(0, listener);
570         }
571 
572         public CursorImpl(int index, CursorListener listener) {
573             this.index = index;
574             this.listener = listener;
575         }
576 
577         /**
578          * @inheritDoc
579          */
580         public int getIndex() {
581             return index;
582         }
583 
584         /**
585          * @inheritDoc
586          */
587         public void setIndex(int index) {
588             checkBounds(index, 0);
589             this.index = index;
590         }
591 
592         /**
593          * @inheritDoc
594          */
595         public void skip(int length) {
596             setIndex(index + length);
597         }
598 
599         /**
600          * @inheritDoc
601          */
602         public ByteArray slice(int length) {
603             CompositeByteArray slice = new CompositeByteArray(byteArrayFactory);
604             int remaining = length;
605             while (remaining > 0) {
606                 prepareForAccess(remaining);
607                 int componentSliceSize = Math.min(remaining, componentCursor.getRemaining());
608                 ByteArray componentSlice = componentCursor.slice(componentSliceSize);
609                 slice.addLast(componentSlice);
610                 index += componentSliceSize;
611                 remaining -= componentSliceSize;
612             }
613             return slice;
614         }
615 
616         /**
617          * @inheritDoc
618          */
619         public ByteOrder order() {
620             return CompositeByteArray.this.order();
621         }
622 
623         private void prepareForAccess(int accessSize) {
624             // Handle removed node. Do this first so we can remove the reference
625             // even if bounds checking fails.
626             if (componentNode != null && componentNode.isRemoved()) {
627                 componentNode = null;
628                 componentCursor = null;
629             }
630 
631             // Bounds checks
632             checkBounds(index, accessSize);
633 
634             // Remember the current node so we can later tell whether or not we
635             // need to create a new cursor.
636             Node oldComponentNode = componentNode;
637 
638             // Handle missing node.
639             if (componentNode == null) {
640                 int basMidpoint = (last() - first()) / 2 + first();
641                 if (index <= basMidpoint) {
642                     // Search from the start.
643                     componentNode = bas.getFirst();
644                     componentIndex = first();
645                     if (listener != null) {
646                         listener.enteredFirstComponent(componentIndex, componentNode.getByteArray());
647                     }
648                 } else {
649                     // Search from the end.
650                     componentNode = bas.getLast();
651                     componentIndex = last() - componentNode.getByteArray().last();
652                     if (listener != null) {
653                         listener.enteredLastComponent(componentIndex, componentNode.getByteArray());
654                     }
655                 }
656             }
657 
658             // Go back, if necessary.
659             while (index < componentIndex) {
660                 componentNode = componentNode.getPreviousNode();
661                 componentIndex -= componentNode.getByteArray().last();
662                 if (listener != null) {
663                     listener.enteredPreviousComponent(componentIndex, componentNode.getByteArray());
664                 }
665             }
666 
667             // Go forward, if necessary.
668             while (index >= componentIndex + componentNode.getByteArray().length()) {
669                 componentIndex += componentNode.getByteArray().last();
670                 componentNode = componentNode.getNextNode();
671                 if (listener != null) {
672                     listener.enteredNextComponent(componentIndex, componentNode.getByteArray());
673                 }
674             }
675 
676             // Update the cursor.
677             int internalComponentIndex = index - componentIndex;
678             if (componentNode == oldComponentNode) {
679                 // Move existing cursor.
680                 componentCursor.setIndex(internalComponentIndex);
681             } else {
682                 // Create new cursor.
683                 componentCursor = componentNode.getByteArray().cursor(internalComponentIndex);
684             }
685         }
686 
687         /**
688          * @inheritDoc
689          */
690         public int getRemaining() {
691             return last() - index + 1;
692         }
693 
694         /**
695          * @inheritDoc
696          */
697         public boolean hasRemaining() {
698             return getRemaining() > 0;
699         }
700 
701         /**
702          * @inheritDoc
703          */
704         public byte get() {
705             prepareForAccess(1);
706             byte b = componentCursor.get();
707             index += 1;
708             return b;
709         }
710 
711         /**
712          * @inheritDoc
713          */
714         public void put(byte b) {
715             prepareForAccess(1);
716             componentCursor.put(b);
717             index += 1;
718         }
719 
720         /**
721          * @inheritDoc
722          */
723         public void get(IoBuffer bb) {
724             while (bb.hasRemaining()) {
725                 int remainingBefore = bb.remaining();
726                 prepareForAccess(remainingBefore);
727                 componentCursor.get(bb);
728                 int remainingAfter = bb.remaining();
729                 // Advance index by actual amount got.
730                 int chunkSize = remainingBefore - remainingAfter;
731                 index += chunkSize;
732             }
733         }
734 
735         /**
736          * @inheritDoc
737          */
738         public void put(IoBuffer bb) {
739             while (bb.hasRemaining()) {
740                 int remainingBefore = bb.remaining();
741                 prepareForAccess(remainingBefore);
742                 componentCursor.put(bb);
743                 int remainingAfter = bb.remaining();
744                 // Advance index by actual amount put.
745                 int chunkSize = remainingBefore - remainingAfter;
746                 index += chunkSize;
747             }
748         }
749 
750         /**
751          * @inheritDoc
752          */
753         public short getShort() {
754             prepareForAccess(2);
755             if (componentCursor.getRemaining() >= 4) {
756                 short s = componentCursor.getShort();
757                 index += 2;
758                 return s;
759             } else {
760                 byte b0 = get();
761                 byte b1 = get();
762                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
763                     return (short) ((b0 << 8) | (b1 << 0));
764                 } else {
765                     return (short) ((b1 << 8) | (b0 << 0));
766                 }
767             }
768         }
769 
770         /**
771          * @inheritDoc
772          */
773         public void putShort(short s) {
774             prepareForAccess(2);
775             if (componentCursor.getRemaining() >= 4) {
776                 componentCursor.putShort(s);
777                 index += 2;
778             } else {
779                 byte b0;
780                 byte b1;
781                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
782                     b0 = (byte) ((s >> 8) & 0xff);
783                     b1 = (byte) ((s >> 0) & 0xff);
784                 } else {
785                     b0 = (byte) ((s >> 0) & 0xff);
786                     b1 = (byte) ((s >> 8) & 0xff);
787                 }
788                 put(b0);
789                 put(b1);
790             }
791         }
792 
793         /**
794          * @inheritDoc
795          */
796         public int getInt() {
797             prepareForAccess(4);
798             if (componentCursor.getRemaining() >= 4) {
799                 int i = componentCursor.getInt();
800                 index += 4;
801                 return i;
802             } else {
803                 byte b0 = get();
804                 byte b1 = get();
805                 byte b2 = get();
806                 byte b3 = get();
807                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
808                     return ((b0 << 24) | (b1 << 16) | (b2 << 8) | (b3 << 0));
809                 } else {
810                     return ((b3 << 24) | (b2 << 16) | (b1 << 8) | (b0 << 0));
811                 }
812             }
813         }
814 
815         /**
816          * @inheritDoc
817          */
818         public void putInt(int i) {
819             prepareForAccess(4);
820             if (componentCursor.getRemaining() >= 4) {
821                 componentCursor.putInt(i);
822                 index += 4;
823             } else {
824                 byte b0;
825                 byte b1;
826                 byte b2;
827                 byte b3;
828                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
829                     b0 = (byte) ((i >> 24) & 0xff);
830                     b1 = (byte) ((i >> 16) & 0xff);
831                     b2 = (byte) ((i >> 8) & 0xff);
832                     b3 = (byte) ((i >> 0) & 0xff);
833                 } else {
834                     b0 = (byte) ((i >> 0) & 0xff);
835                     b1 = (byte) ((i >> 8) & 0xff);
836                     b2 = (byte) ((i >> 16) & 0xff);
837                     b3 = (byte) ((i >> 24) & 0xff);
838                 }
839                 put(b0);
840                 put(b1);
841                 put(b2);
842                 put(b3);
843             }
844         }
845 
846         /**
847          * @inheritDoc
848          */
849         public long getLong() {
850             prepareForAccess(8);
851             if (componentCursor.getRemaining() >= 4) {
852                 long l = componentCursor.getLong();
853                 index += 8;
854                 return l;
855             } else {
856                 byte b0 = get();
857                 byte b1 = get();
858                 byte b2 = get();
859                 byte b3 = get();
860                 byte b4 = get();
861                 byte b5 = get();
862                 byte b6 = get();
863                 byte b7 = get();
864                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
865                     return ((b0 & 0xffL) << 56) | ((b1 & 0xffL) << 48) | ((b2 & 0xffL) << 40) | ((b3 & 0xffL) << 32)
866                             | ((b4 & 0xffL) << 24) | ((b5 & 0xffL) << 16) | ((b6 & 0xffL) << 8) | ((b7 & 0xffL) << 0);
867                 } else {
868                     return ((b7 & 0xffL) << 56) | ((b6 & 0xffL) << 48) | ((b5 & 0xffL) << 40) | ((b4 & 0xffL) << 32)
869                             | ((b3 & 0xffL) << 24) | ((b2 & 0xffL) << 16) | ((b1 & 0xffL) << 8) | ((b0 & 0xffL) << 0);
870                 }
871             }
872         }
873 
874         /**
875          * @inheritDoc
876          */
877         public void putLong(long l) {
878             //TODO: see if there is some optimizing that can be done here
879             prepareForAccess(8);
880             if (componentCursor.getRemaining() >= 4) {
881                 componentCursor.putLong(l);
882                 index += 8;
883             } else {
884                 byte b0;
885                 byte b1;
886                 byte b2;
887                 byte b3;
888                 byte b4;
889                 byte b5;
890                 byte b6;
891                 byte b7;
892                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
893                     b0 = (byte) ((l >> 56) & 0xff);
894                     b1 = (byte) ((l >> 48) & 0xff);
895                     b2 = (byte) ((l >> 40) & 0xff);
896                     b3 = (byte) ((l >> 32) & 0xff);
897                     b4 = (byte) ((l >> 24) & 0xff);
898                     b5 = (byte) ((l >> 16) & 0xff);
899                     b6 = (byte) ((l >> 8) & 0xff);
900                     b7 = (byte) ((l >> 0) & 0xff);
901                 } else {
902                     b0 = (byte) ((l >> 0) & 0xff);
903                     b1 = (byte) ((l >> 8) & 0xff);
904                     b2 = (byte) ((l >> 16) & 0xff);
905                     b3 = (byte) ((l >> 24) & 0xff);
906                     b4 = (byte) ((l >> 32) & 0xff);
907                     b5 = (byte) ((l >> 40) & 0xff);
908                     b6 = (byte) ((l >> 48) & 0xff);
909                     b7 = (byte) ((l >> 56) & 0xff);
910                 }
911                 put(b0);
912                 put(b1);
913                 put(b2);
914                 put(b3);
915                 put(b4);
916                 put(b5);
917                 put(b6);
918                 put(b7);
919             }
920         }
921 
922         /**
923          * @inheritDoc
924          */
925         public float getFloat() {
926             prepareForAccess(4);
927             if (componentCursor.getRemaining() >= 4) {
928                 float f = componentCursor.getFloat();
929                 index += 4;
930                 return f;
931             } else {
932                 int i = getInt();
933                 return Float.intBitsToFloat(i);
934             }
935         }
936 
937         /**
938          * @inheritDoc
939          */
940         public void putFloat(float f) {
941             prepareForAccess(4);
942             if (componentCursor.getRemaining() >= 4) {
943                 componentCursor.putFloat(f);
944                 index += 4;
945             } else {
946                 int i = Float.floatToIntBits(f);
947                 putInt(i);
948             }
949         }
950 
951         /**
952          * @inheritDoc
953          */
954         public double getDouble() {
955             prepareForAccess(8);
956             if (componentCursor.getRemaining() >= 4) {
957                 double d = componentCursor.getDouble();
958                 index += 8;
959                 return d;
960             } else {
961                 long l = getLong();
962                 return Double.longBitsToDouble(l);
963             }
964         }
965 
966         /**
967          * @inheritDoc
968          */
969         public void putDouble(double d) {
970             prepareForAccess(8);
971             if (componentCursor.getRemaining() >= 4) {
972                 componentCursor.putDouble(d);
973                 index += 8;
974             } else {
975                 long l = Double.doubleToLongBits(d);
976                 putLong(l);
977             }
978         }
979 
980         /**
981          * @inheritDoc
982          */
983         public char getChar() {
984             prepareForAccess(2);
985             if (componentCursor.getRemaining() >= 4) {
986                 char c = componentCursor.getChar();
987                 index += 2;
988                 return c;
989             } else {
990                 byte b0 = get();
991                 byte b1 = get();
992                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
993                     return (char) ((b0 << 8) | (b1 << 0));
994                 } else {
995                     return (char) ((b1 << 8) | (b0 << 0));
996                 }
997             }
998         }
999 
1000         /**
1001          * @inheritDoc
1002          */
1003         public void putChar(char c) {
1004             prepareForAccess(2);
1005             if (componentCursor.getRemaining() >= 4) {
1006                 componentCursor.putChar(c);
1007                 index += 2;
1008             } else {
1009                 byte b0;
1010                 byte b1;
1011                 if (order.equals(ByteOrder.BIG_ENDIAN)) {
1012                     b0 = (byte) ((c >> 8) & 0xff);
1013                     b1 = (byte) ((c >> 0) & 0xff);
1014                 } else {
1015                     b0 = (byte) ((c >> 0) & 0xff);
1016                     b1 = (byte) ((c >> 8) & 0xff);
1017                 }
1018                 put(b0);
1019                 put(b1);
1020             }
1021         }
1022 
1023     }
1024 }