/*
Copyright 2011, Lightbox Technologies, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.lightboxtechnologies.spectrum;
import java.io.EOFException;
import java.io.InputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.fs.FSDataInputStream;
/**
* An {@link InputStream} which reads sequentially from a list of extents.
*
* @author Joel Uckelman
*/
public class ExtentsInputStream extends InputStream {
protected final FSDataInputStream in;
protected final Iterator<Map<String,Object>> ext_iter;
protected Map<String,?> cur_extent = null;
protected long cur_pos;
protected long cur_end;
public ExtentsInputStream(FSDataInputStream in,
List<Map<String,Object>> extents) {
this.in = in;
this.ext_iter = extents.iterator();
}
protected boolean prepareExtent() {
// prepare next extent
if (cur_extent == null || cur_pos == cur_end) {
if (ext_iter.hasNext()) {
cur_extent = ext_iter.next();
final long length = ((Number) cur_extent.get("len")).longValue();
cur_pos = ((Number) cur_extent.get("addr")).longValue();
cur_end = cur_pos + length;
}
else {
return false;
}
}
return true;
}
@Override
public int read() throws IOException {
final byte[] b = new byte[1];
// keep trying until we read one byte or hit EOF
int rlen;
do {
rlen = read(b, 0, 1);
} while (rlen == 0);
return rlen == -1 ? -1 : b[0];
}
@Override
public int read(byte[] buf, int off, int len) throws IOException {
if (!prepareExtent()) {
return -1;
}
// NB: cur_end - cur_pos might be larger than 2^31-1, so we must
// check that it doesn't overflow an int.
int rlen = Math.min(len,
(int) Math.min(cur_end - cur_pos, Integer.MAX_VALUE));
rlen = in.read(cur_pos, buf, off, rlen);
cur_pos += rlen;
return rlen;
}
}