Skip to content

Commit d6ecb02

Browse files
gab1onectrueden
authored andcommitted
Add BufferedStreamHandle
1 parent 908424c commit d6ecb02

File tree

2 files changed

+279
-0
lines changed

2 files changed

+279
-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,234 @@
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 byte readByte() throws IOException {
72+
73+
// reached end of the buffer
74+
if (offset() == handle.length()) {
75+
return -1;
76+
}
77+
78+
// check if we need to refill the buffer
79+
if (offset() > maxBuf() || maxBuf() == -1) {
80+
// buffer more bytes
81+
final int filled = fill();
82+
if (filled <= 0) {
83+
// no more bytes in input handle
84+
return -1;
85+
}
86+
}
87+
88+
byte b = getBufferIfOpen().getByte(offset());
89+
advance(1);
90+
return b;
91+
}
92+
93+
@Override
94+
public void seek(final long pos) throws IOException {
95+
final long off = offset();
96+
if (off == pos) return;
97+
if (pos > off) {
98+
// ensure target is buffered
99+
while (pos > maxBuf()) {
100+
fill();
101+
}
102+
}
103+
// values in the range (pos < off) are already buffered
104+
setOffset(pos);
105+
}
106+
107+
private long maxBuf() throws IOException {
108+
return getBufferIfOpen().getMaxPos();
109+
}
110+
111+
@Override
112+
public long skip(final long n) throws IOException {
113+
seek(offset() + n);
114+
return handle().skip(n);
115+
}
116+
117+
@Override
118+
public int read(final byte[] b, final int off, final int len)
119+
throws IOException
120+
{
121+
122+
while (maxBuf() < offset() + len) {
123+
final int filled = fill();
124+
if (filled <= 0) {
125+
// no more bytes available
126+
break;
127+
}
128+
}
129+
130+
// read all available bytes
131+
int available = (int) available(len);
132+
getBufferIfOpen().getBytes(offset(), b, off, available);
133+
setOffset(offset() + available);
134+
return available;
135+
}
136+
137+
/**
138+
* Fills the buffer with XX more bytes
139+
*
140+
* @throws IOException
141+
*/
142+
private int fill() throws IOException {
143+
final byte[] buf = new byte[CHUNK_SIZE];
144+
final int read = handle().read(buf);
145+
if (read <= 0) {
146+
return -1;
147+
}
148+
getBufferIfOpen().appendBytes(buf, read);
149+
return read;
150+
}
151+
152+
@Override
153+
public InputStream in() {
154+
if (inStreamProxy == null) {
155+
inStreamProxy = new DataHandleInputStream<>(this);
156+
}
157+
return inStreamProxy;
158+
}
159+
160+
@Override
161+
public OutputStream out() {
162+
if (outStreamProxy == null) {
163+
outStreamProxy = new DataHandleOutputStream<>(this);
164+
}
165+
return outStreamProxy;
166+
}
167+
168+
@Override
169+
public long length() throws IOException {
170+
return handle().length();
171+
}
172+
173+
private StreamHandle<L> handle() throws IOException {
174+
if (closed) {
175+
throw new IOException("Handle is closed!");
176+
}
177+
return handle;
178+
}
179+
180+
@Override
181+
public void setLength(final long length) throws IOException {
182+
handle().setLength(length);
183+
}
184+
185+
@Override
186+
public boolean isReadable() {
187+
return !closed && handle.isReadable();
188+
}
189+
190+
@Override
191+
public boolean isWritable() {
192+
return !closed && handle.isWritable();
193+
}
194+
195+
@Override
196+
public Class<L> getType() {
197+
return handle.getType();
198+
}
199+
200+
@Override
201+
public void resetStream() throws IOException {
202+
getBufferIfOpen();
203+
if (handle() instanceof ResettableStreamHandle) {
204+
((ResettableStreamHandle<L>) handle()).resetStream();
205+
}
206+
else {
207+
throw new IOException("Handle can not be reset!");
208+
}
209+
}
210+
211+
@Override
212+
public void close() throws IOException {
213+
if (!closed) {
214+
closed = true;
215+
handle().close();
216+
getBufferIfOpen().clear();
217+
buffer = null;
218+
}
219+
}
220+
221+
/**
222+
* @return the buffer used in this handle
223+
* @throws IOException if this handle has been closed
224+
*/
225+
private ByteBank getBufferIfOpen() throws IOException {
226+
if (closed) {
227+
throw new IOException("Handle is closed");
228+
}
229+
if (buffer == null) {
230+
buffer = new ByteArrayByteBank();
231+
}
232+
return buffer;
233+
}
234+
}

0 commit comments

Comments
 (0)