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