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 }