Skip to content

Commit 15fc988

Browse files
committed
Add BufferedStreamHandle
1 parent 908424c commit 15fc988

File tree

2 files changed

+289
-0
lines changed

2 files changed

+289
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.io.handle;
33+
34+
import org.scijava.io.location.Location;
35+
36+
/**
37+
* A buffered {@link StreamHandle}.
38+
*
39+
* @author Gabriel Einsdorf
40+
*/
41+
public interface BufferedStreamHandle<L extends Location> extends
42+
SeekableStreamHandle<L>
43+
{
44+
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.io.handle;
33+
34+
import java.io.IOException;
35+
import java.io.InputStream;
36+
import java.io.OutputStream;
37+
38+
import org.scijava.io.ByteArrayByteBank;
39+
import org.scijava.io.ByteBank;
40+
import org.scijava.io.location.Location;
41+
42+
/**
43+
* A {@link BufferedStreamHandle} backed by a {@link ByteBank}.
44+
*
45+
* @author Gabriel Einsdorf
46+
*/
47+
public class DefaultBufferedStreamHandle<L extends Location> extends
48+
AbstractStreamHandle<L> implements BufferedStreamHandle<L>
49+
{
50+
51+
private static final int CHUNK_SIZE = 8192;
52+
53+
private final StreamHandle<L> handle;
54+
private ByteBank buffer;
55+
56+
private InputStream inStreamProxy;
57+
private OutputStream outStreamProxy;
58+
59+
private boolean closed;
60+
61+
/**
62+
* Wraps around StreamHandle in a buffer
63+
*
64+
* @param handle
65+
*/
66+
public DefaultBufferedStreamHandle(final StreamHandle<L> handle) {
67+
this.handle = handle;
68+
}
69+
70+
@Override
71+
public int read() throws IOException {
72+
return offset() < length() ? readByte() & 0xff : -1;
73+
}
74+
75+
@Override
76+
public byte readByte() throws IOException {
77+
78+
// reached end of the buffer
79+
if (offset() == handle.length()) {
80+
return -1;
81+
}
82+
83+
// check if we need to refill the buffer
84+
if (offset() > maxBuf() || maxBuf() == -1) {
85+
// buffer more bytes
86+
final int filled = fill();
87+
if (filled <= 0) {
88+
// no more bytes in input handle
89+
return -1;
90+
}
91+
}
92+
93+
final byte b = getBufferIfOpen().getByte(offset());
94+
advance(1);
95+
return b;
96+
}
97+
98+
@Override
99+
public void seek(final long pos) throws IOException {
100+
final long off = offset();
101+
if (off == pos) return;
102+
if (pos > off) {
103+
// ensure target is buffered
104+
while (pos > maxBuf()) {
105+
fill();
106+
}
107+
}
108+
// values in the range (pos < off) are already buffered
109+
setOffset(pos);
110+
}
111+
112+
private long maxBuf() throws IOException {
113+
return getBufferIfOpen().size() - 1;
114+
}
115+
116+
@Override
117+
public long skip(final long n) throws IOException {
118+
seek(offset() + n);
119+
return handle().skip(n);
120+
}
121+
122+
@Override
123+
public int read(final byte[] b, final int off, final int len)
124+
throws IOException
125+
{
126+
127+
while (maxBuf() < offset() + len) {
128+
final int filled = fill();
129+
if (filled <= 0) {
130+
// no more bytes available
131+
break;
132+
}
133+
}
134+
135+
// read all available bytes
136+
final int available = (int) available(len);
137+
getBufferIfOpen().getBytes(offset(), b, off, available);
138+
setOffset(offset() + available);
139+
return available;
140+
}
141+
142+
/**
143+
* Fills the buffer with XX more bytes
144+
*
145+
* @throws IOException
146+
*/
147+
private int fill() throws IOException {
148+
final byte[] buf = new byte[CHUNK_SIZE];
149+
final int read = handle().read(buf);
150+
if (read <= 0) {
151+
return -1;
152+
}
153+
getBufferIfOpen().appendBytes(buf, read);
154+
return read;
155+
}
156+
157+
@Override
158+
public InputStream in() {
159+
if (inStreamProxy == null) {
160+
inStreamProxy = new DataHandleInputStream<>(this);
161+
}
162+
return inStreamProxy;
163+
}
164+
165+
@Override
166+
public OutputStream out() {
167+
if (outStreamProxy == null) {
168+
outStreamProxy = new DataHandleOutputStream<>(this);
169+
}
170+
return outStreamProxy;
171+
}
172+
173+
@Override
174+
public long length() throws IOException {
175+
return handle().length();
176+
}
177+
178+
private StreamHandle<L> handle() throws IOException {
179+
if (closed) {
180+
throw new IOException("Handle is closed!");
181+
}
182+
return handle;
183+
}
184+
185+
@Override
186+
public void setLength(final long length) throws IOException {
187+
handle().setLength(length);
188+
}
189+
190+
@Override
191+
public boolean isReadable() {
192+
return !closed && handle.isReadable();
193+
}
194+
195+
@Override
196+
public boolean isWritable() {
197+
return !closed && handle.isWritable();
198+
}
199+
200+
@Override
201+
public boolean exists() throws IOException {
202+
return handle.exists();
203+
}
204+
205+
@Override
206+
public Class<L> getType() {
207+
return handle.getType();
208+
}
209+
210+
@Override
211+
public void resetStream() throws IOException {
212+
getBufferIfOpen();
213+
if (handle() instanceof ResettableStreamHandle) {
214+
((ResettableStreamHandle<L>) handle()).resetStream();
215+
}
216+
else {
217+
throw new IOException("Handle can not be reset!");
218+
}
219+
}
220+
221+
@Override
222+
public void close() throws IOException {
223+
if (!closed) {
224+
closed = true;
225+
handle().close();
226+
getBufferIfOpen().clear();
227+
buffer = null;
228+
}
229+
}
230+
231+
/**
232+
* @return the buffer used in this handle
233+
* @throws IOException if this handle has been closed
234+
*/
235+
private ByteBank getBufferIfOpen() throws IOException {
236+
if (closed) {
237+
throw new IOException("Handle is closed");
238+
}
239+
if (buffer == null) {
240+
buffer = new ByteArrayByteBank();
241+
}
242+
return buffer;
243+
}
244+
}

0 commit comments

Comments
 (0)