1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.nio; 19 20import java.nio.channels.FileChannel.MapMode; 21 22import libcore.io.Memory; 23import libcore.io.SizeOf; 24 25class DirectByteBuffer extends MappedByteBuffer { 26 // This is the offset into {@code Buffer.block} at which this buffer logically starts. 27 // TODO: rewrite this so we set 'block' to an OffsetMemoryBlock? 28 protected final int offset; 29 30 private final boolean isReadOnly; 31 32 protected DirectByteBuffer(MemoryBlock block, int capacity, int offset, boolean isReadOnly, MapMode mapMode) { 33 super(block, capacity, mapMode, block.toLong() + offset); 34 35 long baseSize = block.getSize(); 36 // We're throwing this exception after we passed a bogus value 37 // to the superclass constructor, but it doesn't make any 38 // difference in this case. 39 if (baseSize >= 0 && (capacity + offset) > baseSize) { 40 throw new IllegalArgumentException("capacity + offset > baseSize"); 41 } 42 43 this.offset = offset; 44 this.isReadOnly = isReadOnly; 45 } 46 47 // Used by the JNI NewDirectByteBuffer function. 48 DirectByteBuffer(long address, int capacity) { 49 this(MemoryBlock.wrapFromJni(address, capacity), capacity, 0, false, null); 50 } 51 52 private static DirectByteBuffer copy(DirectByteBuffer other, int markOfOther, boolean isReadOnly) { 53 other.checkNotFreed(); 54 DirectByteBuffer buf = new DirectByteBuffer(other.block, other.capacity(), other.offset, isReadOnly, other.mapMode); 55 buf.limit = other.limit; 56 buf.position = other.position(); 57 buf.mark = markOfOther; 58 return buf; 59 } 60 61 @Override public ByteBuffer asReadOnlyBuffer() { 62 return copy(this, mark, true); 63 } 64 65 @Override public ByteBuffer compact() { 66 checkIsAccessible(); 67 if (isReadOnly) { 68 throw new ReadOnlyBufferException(); 69 } 70 Memory.memmove(this, 0, this, position, remaining()); 71 position = limit - position; 72 limit = capacity; 73 mark = UNSET_MARK; 74 return this; 75 } 76 77 @Override public ByteBuffer duplicate() { 78 return copy(this, mark, isReadOnly); 79 } 80 81 @Override public ByteBuffer slice() { 82 checkNotFreed(); 83 return new DirectByteBuffer(block, remaining(), offset + position, isReadOnly, mapMode); 84 } 85 86 @Override public boolean isReadOnly() { 87 return isReadOnly; 88 } 89 90 @Override byte[] protectedArray() { 91 checkIsAccessible(); 92 if (isReadOnly) { 93 throw new ReadOnlyBufferException(); 94 } 95 byte[] array = this.block.array(); 96 if (array == null) { 97 throw new UnsupportedOperationException(); 98 } 99 return array; 100 } 101 102 @Override int protectedArrayOffset() { 103 protectedArray(); // Throw if we don't have an array or are read-only. 104 return offset; 105 } 106 107 @Override boolean protectedHasArray() { 108 return !isReadOnly && (block.array() != null); 109 } 110 111 @Override public final ByteBuffer get(byte[] dst, int dstOffset, int byteCount) { 112 checkIsAccessible(); 113 checkGetBounds(1, dst.length, dstOffset, byteCount); 114 this.block.peekByteArray(offset + position, dst, dstOffset, byteCount); 115 position += byteCount; 116 return this; 117 } 118 119 final void get(char[] dst, int dstOffset, int charCount) { 120 checkIsAccessible(); 121 int byteCount = checkGetBounds(SizeOf.CHAR, dst.length, dstOffset, charCount); 122 this.block.peekCharArray(offset + position, dst, dstOffset, charCount, order.needsSwap); 123 position += byteCount; 124 } 125 126 final void get(double[] dst, int dstOffset, int doubleCount) { 127 checkIsAccessible(); 128 int byteCount = checkGetBounds(SizeOf.DOUBLE, dst.length, dstOffset, doubleCount); 129 this.block.peekDoubleArray(offset + position, dst, dstOffset, doubleCount, order.needsSwap); 130 position += byteCount; 131 } 132 133 final void get(float[] dst, int dstOffset, int floatCount) { 134 checkIsAccessible(); 135 int byteCount = checkGetBounds(SizeOf.FLOAT, dst.length, dstOffset, floatCount); 136 this.block.peekFloatArray(offset + position, dst, dstOffset, floatCount, order.needsSwap); 137 position += byteCount; 138 } 139 140 final void get(int[] dst, int dstOffset, int intCount) { 141 checkIsAccessible(); 142 int byteCount = checkGetBounds(SizeOf.INT, dst.length, dstOffset, intCount); 143 this.block.peekIntArray(offset + position, dst, dstOffset, intCount, order.needsSwap); 144 position += byteCount; 145 } 146 147 final void get(long[] dst, int dstOffset, int longCount) { 148 checkIsAccessible(); 149 int byteCount = checkGetBounds(SizeOf.LONG, dst.length, dstOffset, longCount); 150 this.block.peekLongArray(offset + position, dst, dstOffset, longCount, order.needsSwap); 151 position += byteCount; 152 } 153 154 final void get(short[] dst, int dstOffset, int shortCount) { 155 checkIsAccessible(); 156 int byteCount = checkGetBounds(SizeOf.SHORT, dst.length, dstOffset, shortCount); 157 this.block.peekShortArray(offset + position, dst, dstOffset, shortCount, order.needsSwap); 158 position += byteCount; 159 } 160 161 @Override public final byte get() { 162 checkIsAccessible(); 163 if (position == limit) { 164 throw new BufferUnderflowException(); 165 } 166 return this.block.peekByte(offset + position++); 167 } 168 169 @Override public final byte get(int index) { 170 checkIsAccessible(); 171 checkIndex(index); 172 return this.block.peekByte(offset + index); 173 } 174 175 @Override public final char getChar() { 176 checkIsAccessible(); 177 int newPosition = position + SizeOf.CHAR; 178 if (newPosition > limit) { 179 throw new BufferUnderflowException(); 180 } 181 char result = (char) this.block.peekShort(offset + position, order); 182 position = newPosition; 183 return result; 184 } 185 186 @Override public final char getChar(int index) { 187 checkIsAccessible(); 188 checkIndex(index, SizeOf.CHAR); 189 return (char) this.block.peekShort(offset + index, order); 190 } 191 192 @Override public final double getDouble() { 193 checkIsAccessible(); 194 int newPosition = position + SizeOf.DOUBLE; 195 if (newPosition > limit) { 196 throw new BufferUnderflowException(); 197 } 198 double result = Double.longBitsToDouble(this.block.peekLong(offset + position, order)); 199 position = newPosition; 200 return result; 201 } 202 203 @Override public final double getDouble(int index) { 204 checkIsAccessible(); 205 checkIndex(index, SizeOf.DOUBLE); 206 return Double.longBitsToDouble(this.block.peekLong(offset + index, order)); 207 } 208 209 @Override public final float getFloat() { 210 checkIsAccessible(); 211 int newPosition = position + SizeOf.FLOAT; 212 if (newPosition > limit) { 213 throw new BufferUnderflowException(); 214 } 215 float result = Float.intBitsToFloat(this.block.peekInt(offset + position, order)); 216 position = newPosition; 217 return result; 218 } 219 220 @Override public final float getFloat(int index) { 221 checkIsAccessible(); 222 checkIndex(index, SizeOf.FLOAT); 223 return Float.intBitsToFloat(this.block.peekInt(offset + index, order)); 224 } 225 226 @Override public final int getInt() { 227 checkIsAccessible(); 228 int newPosition = position + SizeOf.INT; 229 if (newPosition > limit) { 230 throw new BufferUnderflowException(); 231 } 232 int result = this.block.peekInt(offset + position, order); 233 position = newPosition; 234 return result; 235 } 236 237 @Override public final int getInt(int index) { 238 checkIsAccessible(); 239 checkIndex(index, SizeOf.INT); 240 return this.block.peekInt(offset + index, order); 241 } 242 243 @Override public final long getLong() { 244 checkIsAccessible(); 245 int newPosition = position + SizeOf.LONG; 246 if (newPosition > limit) { 247 throw new BufferUnderflowException(); 248 } 249 long result = this.block.peekLong(offset + position, order); 250 position = newPosition; 251 return result; 252 } 253 254 @Override public final long getLong(int index) { 255 checkIsAccessible(); 256 checkIndex(index, SizeOf.LONG); 257 return this.block.peekLong(offset + index, order); 258 } 259 260 @Override public final short getShort() { 261 checkIsAccessible(); 262 int newPosition = position + SizeOf.SHORT; 263 if (newPosition > limit) { 264 throw new BufferUnderflowException(); 265 } 266 short result = this.block.peekShort(offset + position, order); 267 position = newPosition; 268 return result; 269 } 270 271 @Override public final short getShort(int index) { 272 checkIsAccessible(); 273 checkIndex(index, SizeOf.SHORT); 274 return this.block.peekShort(offset + index, order); 275 } 276 277 @Override public final boolean isDirect() { 278 return true; 279 } 280 281 /** @hide */ 282 @Override public final boolean isAccessible() { 283 return block.isAccessible(); 284 } 285 286 /** @hide */ 287 @Override public void setAccessible(boolean accessible) { 288 block.setAccessible(accessible); 289 } 290 291 /** 292 * Invalidates the buffer. Subsequent operations which touch the inner 293 * buffer will throw {@link IllegalStateException}. 294 */ 295 public final void free() { 296 block.free(); 297 } 298 299 @Override public final CharBuffer asCharBuffer() { 300 checkNotFreed(); 301 return ByteBufferAsCharBuffer.asCharBuffer(this); 302 } 303 304 @Override public final DoubleBuffer asDoubleBuffer() { 305 checkNotFreed(); 306 return ByteBufferAsDoubleBuffer.asDoubleBuffer(this); 307 } 308 309 @Override public final FloatBuffer asFloatBuffer() { 310 checkNotFreed(); 311 return ByteBufferAsFloatBuffer.asFloatBuffer(this); 312 } 313 314 @Override public final IntBuffer asIntBuffer() { 315 checkNotFreed(); 316 return ByteBufferAsIntBuffer.asIntBuffer(this); 317 } 318 319 @Override public final LongBuffer asLongBuffer() { 320 checkNotFreed(); 321 return ByteBufferAsLongBuffer.asLongBuffer(this); 322 } 323 324 @Override public final ShortBuffer asShortBuffer() { 325 checkNotFreed(); 326 return ByteBufferAsShortBuffer.asShortBuffer(this); 327 } 328 329 @Override public ByteBuffer put(byte value) { 330 checkIsAccessible(); 331 if (isReadOnly) { 332 throw new ReadOnlyBufferException(); 333 } 334 if (position == limit) { 335 throw new BufferOverflowException(); 336 } 337 this.block.pokeByte(offset + position++, value); 338 return this; 339 } 340 341 @Override public ByteBuffer put(int index, byte value) { 342 checkIsAccessible(); 343 if (isReadOnly) { 344 throw new ReadOnlyBufferException(); 345 } 346 checkIndex(index); 347 this.block.pokeByte(offset + index, value); 348 return this; 349 } 350 351 @Override public ByteBuffer put(byte[] src, int srcOffset, int byteCount) { 352 checkIsAccessible(); 353 if (isReadOnly) { 354 throw new ReadOnlyBufferException(); 355 } 356 checkPutBounds(1, src.length, srcOffset, byteCount); 357 this.block.pokeByteArray(offset + position, src, srcOffset, byteCount); 358 position += byteCount; 359 return this; 360 } 361 362 final void put(char[] src, int srcOffset, int charCount) { 363 checkIsAccessible(); 364 int byteCount = checkPutBounds(SizeOf.CHAR, src.length, srcOffset, charCount); 365 this.block.pokeCharArray(offset + position, src, srcOffset, charCount, order.needsSwap); 366 position += byteCount; 367 } 368 369 final void put(double[] src, int srcOffset, int doubleCount) { 370 checkIsAccessible(); 371 int byteCount = checkPutBounds(SizeOf.DOUBLE, src.length, srcOffset, doubleCount); 372 this.block.pokeDoubleArray(offset + position, src, srcOffset, doubleCount, order.needsSwap); 373 position += byteCount; 374 } 375 376 final void put(float[] src, int srcOffset, int floatCount) { 377 checkIsAccessible(); 378 int byteCount = checkPutBounds(SizeOf.FLOAT, src.length, srcOffset, floatCount); 379 this.block.pokeFloatArray(offset + position, src, srcOffset, floatCount, order.needsSwap); 380 position += byteCount; 381 } 382 383 final void put(int[] src, int srcOffset, int intCount) { 384 checkIsAccessible(); 385 int byteCount = checkPutBounds(SizeOf.INT, src.length, srcOffset, intCount); 386 this.block.pokeIntArray(offset + position, src, srcOffset, intCount, order.needsSwap); 387 position += byteCount; 388 } 389 390 final void put(long[] src, int srcOffset, int longCount) { 391 checkIsAccessible(); 392 int byteCount = checkPutBounds(SizeOf.LONG, src.length, srcOffset, longCount); 393 this.block.pokeLongArray(offset + position, src, srcOffset, longCount, order.needsSwap); 394 position += byteCount; 395 } 396 397 final void put(short[] src, int srcOffset, int shortCount) { 398 checkIsAccessible(); 399 int byteCount = checkPutBounds(SizeOf.SHORT, src.length, srcOffset, shortCount); 400 this.block.pokeShortArray(offset + position, src, srcOffset, shortCount, order.needsSwap); 401 position += byteCount; 402 } 403 404 @Override public ByteBuffer putChar(char value) { 405 checkIsAccessible(); 406 if (isReadOnly) { 407 throw new ReadOnlyBufferException(); 408 } 409 int newPosition = position + SizeOf.CHAR; 410 if (newPosition > limit) { 411 throw new BufferOverflowException(); 412 } 413 this.block.pokeShort(offset + position, (short) value, order); 414 position = newPosition; 415 return this; 416 } 417 418 @Override public ByteBuffer putChar(int index, char value) { 419 checkIsAccessible(); 420 if (isReadOnly) { 421 throw new ReadOnlyBufferException(); 422 } 423 checkIndex(index, SizeOf.CHAR); 424 this.block.pokeShort(offset + index, (short) value, order); 425 return this; 426 } 427 428 @Override public ByteBuffer putDouble(double value) { 429 checkIsAccessible(); 430 if (isReadOnly) { 431 throw new ReadOnlyBufferException(); 432 } 433 int newPosition = position + SizeOf.DOUBLE; 434 if (newPosition > limit) { 435 throw new BufferOverflowException(); 436 } 437 this.block.pokeLong(offset + position, Double.doubleToRawLongBits(value), order); 438 position = newPosition; 439 return this; 440 } 441 442 @Override public ByteBuffer putDouble(int index, double value) { 443 checkIsAccessible(); 444 if (isReadOnly) { 445 throw new ReadOnlyBufferException(); 446 } 447 checkIndex(index, SizeOf.DOUBLE); 448 this.block.pokeLong(offset + index, Double.doubleToRawLongBits(value), order); 449 return this; 450 } 451 452 @Override public ByteBuffer putFloat(float value) { 453 checkIsAccessible(); 454 if (isReadOnly) { 455 throw new ReadOnlyBufferException(); 456 } 457 int newPosition = position + SizeOf.FLOAT; 458 if (newPosition > limit) { 459 throw new BufferOverflowException(); 460 } 461 this.block.pokeInt(offset + position, Float.floatToRawIntBits(value), order); 462 position = newPosition; 463 return this; 464 } 465 466 @Override public ByteBuffer putFloat(int index, float value) { 467 checkIsAccessible(); 468 if (isReadOnly) { 469 throw new ReadOnlyBufferException(); 470 } 471 checkIndex(index, SizeOf.FLOAT); 472 this.block.pokeInt(offset + index, Float.floatToRawIntBits(value), order); 473 return this; 474 } 475 476 @Override public ByteBuffer putInt(int value) { 477 checkIsAccessible(); 478 if (isReadOnly) { 479 throw new ReadOnlyBufferException(); 480 } 481 int newPosition = position + SizeOf.INT; 482 if (newPosition > limit) { 483 throw new BufferOverflowException(); 484 } 485 this.block.pokeInt(offset + position, value, order); 486 position = newPosition; 487 return this; 488 } 489 490 @Override public ByteBuffer putInt(int index, int value) { 491 checkIsAccessible(); 492 if (isReadOnly) { 493 throw new ReadOnlyBufferException(); 494 } 495 checkIndex(index, SizeOf.INT); 496 this.block.pokeInt(offset + index, value, order); 497 return this; 498 } 499 500 @Override public ByteBuffer putLong(long value) { 501 checkIsAccessible(); 502 if (isReadOnly) { 503 throw new ReadOnlyBufferException(); 504 } 505 int newPosition = position + SizeOf.LONG; 506 if (newPosition > limit) { 507 throw new BufferOverflowException(); 508 } 509 this.block.pokeLong(offset + position, value, order); 510 position = newPosition; 511 return this; 512 } 513 514 @Override public ByteBuffer putLong(int index, long value) { 515 checkIsAccessible(); 516 if (isReadOnly) { 517 throw new ReadOnlyBufferException(); 518 } 519 checkIndex(index, SizeOf.LONG); 520 this.block.pokeLong(offset + index, value, order); 521 return this; 522 } 523 524 @Override public ByteBuffer putShort(short value) { 525 checkIsAccessible(); 526 if (isReadOnly) { 527 throw new ReadOnlyBufferException(); 528 } 529 int newPosition = position + SizeOf.SHORT; 530 if (newPosition > limit) { 531 throw new BufferOverflowException(); 532 } 533 this.block.pokeShort(offset + position, value, order); 534 position = newPosition; 535 return this; 536 } 537 538 @Override public ByteBuffer putShort(int index, short value) { 539 checkIsAccessible(); 540 if (isReadOnly) { 541 throw new ReadOnlyBufferException(); 542 } 543 checkIndex(index, SizeOf.SHORT); 544 this.block.pokeShort(offset + index, value, order); 545 return this; 546 } 547 548 private void checkIsAccessible() { 549 checkNotFreed(); 550 if (!block.isAccessible()) { 551 throw new IllegalStateException("buffer is inaccessible"); 552 } 553 } 554 555 private void checkNotFreed() { 556 if (block.isFreed()) { 557 throw new IllegalStateException("buffer was freed"); 558 } 559 } 560 561} 562