/**
* Copyright (c) 2012, Thilo Planz. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package v7db.files.spi;
import java.io.IOException;
import java.io.InputStream;
/**
* Support for "offset" and "length" parameters that can be used to create new
* Content by taking a segment of other Content, with optional repetition.
*
*/
public final class OffsetAndLength implements Content {
private final Content original;
private final long offset, length;
public OffsetAndLength(Content original, long offset, long length) {
this.original = original;
this.offset = offset;
this.length = length;
}
public InputStream getInputStream() throws IOException {
return getInputStream(0, length);
}
public InputStream getInputStream(long offset, long length)
throws IOException {
offset += this.offset;
long oLen = original.getLength();
if (length + offset <= oLen)
return original.getInputStream(offset, length);
return new RepeatedInputStream(offset, length);
}
class RepeatedInputStream extends InputStream {
private long remaining;
private InputStream chunk;
private final long oLength;
private long ooff;
RepeatedInputStream(long offset, long length) {
oLength = original.getLength();
remaining = length;
ooff = offset % oLength;
}
@Override
public int read() throws IOException {
if (remaining > 0) {
if (chunk == null) {
chunk = original.getInputStream(ooff, oLength - ooff);
ooff = 0;
}
int x = chunk.read();
if (x == -1) {
chunk.close();
chunk = null;
return read();
}
remaining--;
return x;
}
return -1;
}
}
public long getLength() {
return length;
}
}