/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.util;
import java.io.InputStream;
import java.io.IOException;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Extent;
/**
* Access raw memory region as an input stream.
*/
public final class AddressInputStream extends InputStream {
/** Start address of memory region to be read */
private final Address startAddress;
/** Length of the memory region */
private final Extent length;
/** Offset to be read. Uses an Extent because the offset is always non-negative. */
private Extent offset;
/** Mark offset. Uses an Extent because the offset is always non-negative. */
private Extent markOffset;
/**
*
* @param startAddress start address of the memory region
* @param length length of the region in bytes
*/
public AddressInputStream(Address startAddress, Extent length) {
this.startAddress = startAddress;
this.length = length;
offset = Extent.zero();
markOffset = Extent.zero();
}
/** @return number of bytes that can be read */
@Override
public int available() {
int available = length.minus(offset).toInt();
available = (available > 0) ? available : 0;
return available;
}
/**
* Closing an AddressInputStream has no effect.
*/
@Override
public void close() throws IOException {
}
/** Marks location. Read limit has no effect. */
@Override
public void mark(int readLimit) {
markOffset = offset;
}
/** Is mark/reset supported */
@Override
public boolean markSupported() {
return true;
}
/** Reads a byte */
@Override
public int read() {
if (offset.GE(length)) {
return -1;
}
Address readLocation = startAddress.plus(offset);
byte result = readLocation.loadByte();
offset = offset.plus(1);
return result & 0xFF;
}
/** Resets to mark */
@Override
public void reset() {
offset = markOffset;
}
/** Skips bytes (at most @code{Integer.MAX_VALUE} bytes) */
@Override
public long skip(long n) {
if (n < 0) {
return 0;
}
long maxInt = Integer.MAX_VALUE;
int skipAmount = (n > maxInt) ? Integer.MAX_VALUE : (int) n;
int available = available();
skipAmount = (skipAmount > available) ? available : skipAmount;
offset = offset.plus(skipAmount);
return skipAmount;
}
}