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