1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.io; 18 19 /** 20 * Iterates over big- or little-endian bytes on the native heap. 21 * See {@link MemoryMappedFile#bigEndianIterator} and {@link MemoryMappedFile#littleEndianIterator}. 22 * 23 * @hide 24 */ 25 public final class NioBufferIterator extends BufferIterator { 26 27 private final MemoryMappedFile file; 28 private final long address; 29 private final int length; 30 private final boolean swap; 31 32 private int position; 33 NioBufferIterator(MemoryMappedFile file, long address, int length, boolean swap)34 NioBufferIterator(MemoryMappedFile file, long address, int length, boolean swap) { 35 file.checkNotClosed(); 36 37 this.file = file; 38 this.address = address; 39 40 if (length < 0) { 41 throw new IllegalArgumentException("length < 0"); 42 } 43 final long MAX_VALID_ADDRESS = -1; 44 if (Long.compareUnsigned(address, MAX_VALID_ADDRESS - length) > 0) { 45 throw new IllegalArgumentException( 46 "length " + length + " would overflow 64-bit address space"); 47 } 48 this.length = length; 49 50 this.swap = swap; 51 } 52 53 @Override seek(int offset)54 public void seek(int offset) { 55 position = offset; 56 } 57 58 @Override skip(int byteCount)59 public void skip(int byteCount) { 60 position += byteCount; 61 } 62 63 @Override pos()64 public int pos() { 65 return position; 66 } 67 68 @Override readByteArray(byte[] bytes, int arrayOffset, int byteCount)69 public void readByteArray(byte[] bytes, int arrayOffset, int byteCount) { 70 checkArrayBounds(arrayOffset, bytes.length, byteCount); 71 file.checkNotClosed(); 72 checkReadBounds(position, length, byteCount); 73 Memory.peekByteArray(address + position, bytes, arrayOffset, byteCount); 74 position += byteCount; 75 } 76 77 @Override readByte()78 public byte readByte() { 79 file.checkNotClosed(); 80 checkReadBounds(position, length, 1); 81 byte result = Memory.peekByte(address + position); 82 ++position; 83 return result; 84 } 85 86 @Override readInt()87 public int readInt() { 88 file.checkNotClosed(); 89 checkReadBounds(position, length, Integer.BYTES); 90 int result = Memory.peekInt(address + position, swap); 91 position += Integer.BYTES; 92 return result; 93 } 94 95 @Override readIntArray(int[] ints, int arrayOffset, int intCount)96 public void readIntArray(int[] ints, int arrayOffset, int intCount) { 97 checkArrayBounds(arrayOffset, ints.length, intCount); 98 file.checkNotClosed(); 99 final int byteCount = Integer.BYTES * intCount; 100 checkReadBounds(position, length, byteCount); 101 Memory.peekIntArray(address + position, ints, arrayOffset, intCount, swap); 102 position += byteCount; 103 } 104 105 @Override readLongArray(long[] longs, int arrayOffset, int longCount)106 public void readLongArray(long[] longs, int arrayOffset, int longCount) { 107 checkArrayBounds(arrayOffset, longs.length, longCount); 108 file.checkNotClosed(); 109 final int byteCount = Long.BYTES * longCount; 110 checkReadBounds(position, length, byteCount); 111 Memory.peekLongArray(address + position, longs, arrayOffset, longCount, swap); 112 position += byteCount; 113 } 114 115 @Override readShort()116 public short readShort() { 117 file.checkNotClosed(); 118 checkReadBounds(position, length, Short.BYTES); 119 short result = Memory.peekShort(address + position, swap); 120 position += Short.BYTES; 121 return result; 122 } 123 checkReadBounds(int position, int length, int byteCount)124 private static void checkReadBounds(int position, int length, int byteCount) { 125 if (position < 0 || byteCount < 0) { 126 throw new IndexOutOfBoundsException( 127 "Invalid read args: position=" + position + ", byteCount=" + byteCount); 128 } 129 // Use of int here relies on length being an int <= Integer.MAX_VALUE. 130 final int finalReadPos = position + byteCount; 131 if (finalReadPos < 0 || finalReadPos > length) { 132 throw new IndexOutOfBoundsException( 133 "Read outside range: position=" + position + ", byteCount=" + byteCount 134 + ", length=" + length); 135 } 136 } 137 checkArrayBounds(int arrayOffset, int arrayLength, int count)138 private static void checkArrayBounds(int arrayOffset, int arrayLength, int count) { 139 if (arrayOffset < 0 || count < 0) { 140 throw new IndexOutOfBoundsException( 141 "Invalid args: arrayOffset=" + arrayOffset + ", count=" + count); 142 } 143 // Use of int here relies on arrayLength being an int <= Integer.MAX_VALUE, which it has to 144 // be because it's an array length. 145 final int targetPos = arrayOffset + count; 146 if (targetPos < 0 || targetPos > arrayLength) { 147 throw new IndexOutOfBoundsException( 148 "Write outside range: arrayLength=" + arrayLength + ", arrayOffset=" 149 + arrayOffset + ", count=" + count); 150 } 151 } 152 } 153