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