-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New crux-util ByteBufferInputStream, ByteInput, Unclosable input/outp…
…ut stream utility classes
- Loading branch information
Showing
6 changed files
with
434 additions
and
0 deletions.
There are no files selected for viewing
70 changes: 70 additions & 0 deletions
70
crux-util/src/main/java/com/fizzed/crux/util/ByteBufferInputStream.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package com.fizzed.crux.util; | ||
|
||
import java.io.InputStream; | ||
import java.nio.ByteBuffer; | ||
|
||
public class ByteBufferInputStream extends InputStream { | ||
|
||
private final ByteBuffer buf; | ||
|
||
public ByteBufferInputStream(ByteBuffer buffer) { | ||
if (buffer == null) throw new NullPointerException(); | ||
buf = buffer; | ||
} | ||
|
||
@Override | ||
public synchronized int read() { | ||
if (buf.hasRemaining()) return buf.get() & 0xff; | ||
return -1; | ||
} | ||
|
||
@Override | ||
public synchronized int read(byte b[]) { | ||
return read(0, b.length, b); | ||
} | ||
|
||
@Override | ||
public synchronized int read(byte b[], int off, int len) { | ||
if ((off | len | off + len | b.length - (off + len)) < 0) { | ||
throw new IndexOutOfBoundsException(); | ||
} | ||
return read(off, len, b); | ||
} | ||
|
||
private int read(int off, int len, byte[] b) { | ||
if (len == 0) return 0; | ||
|
||
int rem = buf.remaining(); | ||
if (rem <= 0) return -1; | ||
|
||
if (rem > len) rem = len; | ||
buf.get(b, off, rem); | ||
return rem; | ||
} | ||
|
||
@Override | ||
public synchronized long skip(long n) { | ||
if (n <= 0) return 0; | ||
|
||
int rem = buf.remaining(); | ||
if (n > rem) n = rem; | ||
|
||
buf.position((int)(buf.position() + n)); | ||
return n; | ||
} | ||
|
||
@Override | ||
public synchronized int available() { return buf.remaining(); } | ||
|
||
@Override | ||
public synchronized void mark(int readAheadLimit) { buf.mark(); } | ||
|
||
@Override | ||
public synchronized void reset() { buf.reset(); } | ||
|
||
@Override | ||
public boolean markSupported() { return true; } | ||
|
||
@Override | ||
public void close() {} | ||
} |
119 changes: 119 additions & 0 deletions
119
crux-util/src/main/java/com/fizzed/crux/util/ByteInput.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package com.fizzed.crux.util; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.ByteBuffer; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.Objects; | ||
|
||
/** | ||
* Generic way of providing "byte inputs" as files, byte arrays, etc. to methods. | ||
*/ | ||
public class ByteInput { | ||
|
||
protected final Path file; | ||
protected final byte[] bytes; | ||
protected final ByteBuffer buffer; | ||
protected final InputStream in; | ||
protected final boolean closeable; | ||
|
||
static public ByteInput byteInput(Path file) { | ||
Objects.requireNonNull(file, "file cannot be null"); | ||
return new ByteInput(file, null, null, null, true); | ||
} | ||
|
||
static public ByteInput byteInput(File file) { | ||
Objects.requireNonNull(file, "file cannot be null"); | ||
return new ByteInput(file.toPath(), null, null, null, true); | ||
} | ||
|
||
static public ByteInput byteInput(byte[] bytes) { | ||
Objects.requireNonNull(bytes, "bytes cannot be null"); | ||
return new ByteInput(null, bytes, null, null, true); | ||
} | ||
|
||
static public ByteInput byteInput(ByteBuffer buffer) { | ||
Objects.requireNonNull(buffer, "buffer cannot be null"); | ||
return new ByteInput(null, null, buffer, null, true); | ||
} | ||
|
||
static public ByteInput byteInput(InputStream in) { | ||
Objects.requireNonNull(in, "input cannot be null"); | ||
return new ByteInput(null, null, null, in, true); | ||
} | ||
|
||
static public ByteInput byteInput(InputStream in, boolean closeable) { | ||
Objects.requireNonNull(in, "input cannot be null"); | ||
return new ByteInput(null, null, null, in, closeable); | ||
} | ||
|
||
protected Long size; | ||
|
||
protected ByteInput(Path file, byte[] bytes, ByteBuffer buffer, InputStream in, boolean closeable) { | ||
this.file = file; | ||
this.bytes = bytes; | ||
this.buffer = buffer; | ||
this.in = in; | ||
this.closeable = closeable; | ||
} | ||
|
||
/** | ||
* If the size is definitively known ahead of time, this is the number of bytes. Will work on files, byte arrays, | ||
* and byte buffers, but others will return -1 since the size is not known definitively. | ||
* @return The number of bytes this input represents or -1 if that size is not definitively known | ||
* @throws IOException | ||
*/ | ||
public long available() throws IOException { | ||
if (this.file != null || this.bytes != null || this.buffer != null) { | ||
return this.size(); | ||
} else if (this.in != null) { | ||
return this.in.available(); | ||
} | ||
return -1L; | ||
} | ||
|
||
/** | ||
* If the size is definitively known ahead of time, this is the number of bytes. Will work on files, byte arrays, | ||
* and byte buffers, but others will return -1 since the size is not known definitively. | ||
* @return The number of bytes this input represents or -1 if that size is not definitively known | ||
* @throws IOException | ||
*/ | ||
public long size() throws IOException { | ||
if (size == null) { | ||
if (this.file != null) { | ||
this.size = Files.size(this.file); | ||
} else if (this.bytes != null) { | ||
this.size = (long)this.bytes.length; | ||
} else if (this.buffer != null) { | ||
this.size = (long)this.buffer.remaining(); | ||
} else { | ||
// otherwise we just don't know what size this is | ||
this.size = -1l; | ||
} | ||
} | ||
return this.size; | ||
} | ||
|
||
public InputStream open() throws IOException { | ||
if (this.file != null) { | ||
return Files.newInputStream(this.file); | ||
} else if (this.bytes != null) { | ||
return new ByteArrayInputStream(this.bytes); | ||
} else if (this.buffer != null) { | ||
return new ByteBufferInputStream(this.buffer); | ||
} else if (this.in != null) { | ||
if (this.closeable) { | ||
return this.in; | ||
} else { | ||
// wrap input stream in an un-closeable version | ||
return new UnclosableInputStream(this.in); | ||
} | ||
} else { | ||
throw new IllegalStateException("All available inputs were null (file, bytes, input)"); | ||
} | ||
} | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
crux-util/src/main/java/com/fizzed/crux/util/UnclosableInputStream.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.fizzed.crux.util; | ||
|
||
import java.io.FilterInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
public class UnclosableInputStream extends FilterInputStream { | ||
|
||
protected boolean closed; | ||
|
||
public UnclosableInputStream(InputStream in) { | ||
super(in); | ||
} | ||
|
||
public boolean isClosed() { | ||
return this.closed; | ||
} | ||
|
||
@Override | ||
public int read() throws IOException { | ||
if (this.closed) return -1; | ||
return super.read(); | ||
} | ||
|
||
@Override | ||
public int read(byte[] b) throws IOException { | ||
if (this.closed) return -1; | ||
return super.read(b); | ||
} | ||
|
||
@Override | ||
public int read(byte[] b, int off, int len) throws IOException { | ||
if (this.closed) return -1; | ||
return super.read(b, off, len); | ||
} | ||
|
||
@Override | ||
public int available() throws IOException { | ||
if (this.closed) throw new IOException("Stream closed"); | ||
return super.available(); | ||
} | ||
|
||
@Override | ||
public void close() throws IOException { | ||
this.closed = true; | ||
} | ||
|
||
} |
50 changes: 50 additions & 0 deletions
50
crux-util/src/main/java/com/fizzed/crux/util/UnclosableOutputStream.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.fizzed.crux.util; | ||
|
||
import java.io.FilterOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
|
||
public class UnclosableOutputStream extends FilterOutputStream { | ||
|
||
private boolean closed; | ||
|
||
public UnclosableOutputStream(OutputStream output) { | ||
super(output); | ||
this.closed = false; | ||
} | ||
|
||
public boolean isClosed() { | ||
return this.closed; | ||
} | ||
|
||
@Override | ||
public void write(int b) throws IOException { | ||
if (closed) throw new IOException("Stream closed"); | ||
super.write(b); | ||
} | ||
|
||
@Override | ||
public void write(byte[] b) throws IOException { | ||
if (closed) throw new IOException("Stream closed"); | ||
super.write(b); | ||
} | ||
|
||
@Override | ||
public void write(byte[] b, int off, int len) throws IOException { | ||
if (closed) throw new IOException("Stream closed"); | ||
super.write(b, off, len); | ||
} | ||
|
||
@Override | ||
public void flush() throws IOException { | ||
if (closed) throw new IOException("Stream closed"); | ||
super.flush(); | ||
} | ||
|
||
@Override | ||
public void close() throws IOException { | ||
this.closed = true; | ||
} | ||
|
||
} |
43 changes: 43 additions & 0 deletions
43
crux-util/src/test/java/com/fizzed/crux/util/ByteBufferInputStreamTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.fizzed.crux.util; | ||
|
||
import org.junit.Test; | ||
|
||
import java.nio.ByteBuffer; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.junit.Assert.*; | ||
|
||
public class ByteBufferInputStreamTest { | ||
|
||
@Test | ||
public void read() { | ||
final ByteBuffer buf = ByteBuffer.wrap("abcdef".getBytes()); | ||
|
||
final ByteBufferInputStream in = new ByteBufferInputStream(buf); | ||
int read; | ||
|
||
assertThat(in.available(), is(6)); | ||
assertThat(in.read(), is((int)'a')); | ||
|
||
final byte[] bytes = new byte[2]; | ||
read = in.read(bytes); | ||
assertThat(read, is(2)); | ||
assertThat(bytes[0], is((byte)'b')); | ||
assertThat(bytes[1], is((byte)'c')); | ||
|
||
read = in.read(bytes, 1, 1); | ||
assertThat(read, is(1)); | ||
assertThat(bytes[1], is((byte)'d')); | ||
|
||
assertThat(in.available(), is(2)); | ||
read = in.read(bytes); | ||
assertThat(read, is(2)); | ||
assertThat(bytes[0], is((byte)'e')); | ||
assertThat(bytes[1], is((byte)'f')); | ||
|
||
// this should be EOF now | ||
read = in.read(bytes); | ||
assertThat(read, is(-1)); | ||
} | ||
|
||
} |
Oops, something went wrong.