Refactored some stream classes and added PositionalInputStream

This commit is contained in:
Ziver Koc 2021-08-26 22:45:24 +02:00
parent 946f5f5133
commit 5771133792
7 changed files with 290 additions and 68 deletions

View file

@ -25,38 +25,28 @@
package zutil.io;
import java.io.Closeable;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* A simple Class that mirrors a InputStream but
* also has an additional Closeable objects that
* will be closed when the this object is closed.
* A simple Class that mirrors a InputStream but also has additional Closeable objects that
* will be closed at the same time as the {@link #close()} method is called.
*
* @author Ziver
*/
public class InputStreamCloser extends InputStream{
private Closeable[] c;
private InputStream in;
public class InputStreamCloser extends FilterInputStream {
private Closeable[] additionalClosable;
public InputStreamCloser(InputStream in, Closeable... c) {
this.c = c;
this.in = in;
public InputStreamCloser(InputStream in, Closeable... additionalClosable) {
super(in);
this.additionalClosable = additionalClosable;
}
public void close() throws IOException {
in.close();
for (Closeable stream : c)
super.close();
for (Closeable stream : additionalClosable)
stream.close();
}
// Mirror functions
public int read() throws IOException { return in.read(); }
public int read(byte b[]) throws IOException { return in.read(b); }
public int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); }
public long skip(long n) throws IOException { return in.skip(n); }
public int available() throws IOException { return in.available(); }
public synchronized void mark(int readlimit) { in.mark(readlimit); }
public synchronized void reset() throws IOException { in.reset(); }
public boolean markSupported() { return in.markSupported(); }
}

View file

@ -0,0 +1,82 @@
package zutil.io;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* A InputStream wrapper that counts the current position in the data stream which equals the amount of data read.
*/
public class PositionalInputStream extends FilterInputStream {
private long pos = 0;
private long mark = 0;
/**
* @param in the underlying input stream.
*/
protected PositionalInputStream(InputStream in) {
super(in);
}
/**
* @return the current position in the data stream
*/
public synchronized long getPosition() {
return pos;
}
@Override
public int read() throws IOException {
int b = super.read();
synchronized(this) {
if (b >= 0) pos += 1;
}
return b;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int n = super.read(b, off, len);
synchronized(this) {
if (n > 0) pos += n;
}
return n;
}
@Override
public long skip(long skip) throws IOException {
long n = super.skip(skip);
synchronized(this) {
if (n > 0) pos += n;
}
return n;
}
@Override
public void mark(int readlimit) {
super.mark(readlimit);
synchronized(this) {
mark = pos;
}
}
@Override
public synchronized void reset() throws IOException {
super.reset();
synchronized(this) {
// Only update the position if mark is supported,
// as reset succeeds even if mark is not supported.
if (markSupported())
pos = mark;
}
}
}

View file

@ -25,30 +25,30 @@
package zutil.io;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* This class saves all the input data in to an StringBuffer
* This InputStream uses a string as the data source.
*
* @author Ziver
*
*/
public class StringInputStream extends InputStream{
// The buffer
protected StringBuilder buffer;
public class StringInputStream extends InputStream {
private StringBuilder buffer = new StringBuilder();
private int pos;
private int mark;
/**
* Creates an new instance of this class
* Creates a new instance of this class
*/
public StringInputStream() {
clear();
}
public StringInputStream() { }
public StringInputStream(String data) {
clear();
add(data);
}
/**
* Returns an estimate of the number of bytes
* that can be read (or skipped over) from this
@ -56,44 +56,37 @@ public class StringInputStream extends InputStream{
* invocation of a method for this input stream.
*/
public int available() {
return buffer.length();
return buffer.length() - pos;
}
/**
* Reads the next byte of data from the input stream.
*/
public int read() {
if (buffer.length() == 0)
public synchronized int read() {
if (available() <= 0)
return -1;
int ret = buffer.charAt(0);
buffer.deleteCharAt(0);
int ret = buffer.charAt(pos);
pos++;
return ret;
}
/**
* Reads some number of bytes from the input stream
* and stores them into the buffer array b.
* Reads up to len bytes of data from the input stream into an array of bytes.
*/
public int read(byte[] b) {
return read(b, 0, b.length);
}
/**
* Reads up to len bytes of data from the input stream
* into an array of bytes.
*/
public int read(byte[] b, int off, int len) {
if (buffer.length() == 0)
public synchronized int read(byte[] b, int off, int len) {
if (available() <= 0)
return -1;
if (buffer.length() < len) {
len = buffer.length();
if (available() < len)
len = available();
for (int i=0; i<len; i++) {
b[off + i] = (byte) buffer.charAt(pos);
pos++;
}
byte[] btmp = buffer.substring(0, len).getBytes(StandardCharsets.ISO_8859_1);
System.arraycopy(btmp, 0, b, off, len);
buffer.delete(0, len);
return len;
}
@ -104,16 +97,12 @@ public class StringInputStream extends InputStream{
*
* @param n is the amount characters to skip
*/
public long skip(long n) {
if (buffer.length() < n) {
int len = buffer.length();
buffer.delete(0, len);
return len;
}
else {
buffer.delete(0, (int) n);
return n;
}
public synchronized long skip(long n) {
if (available() < n)
n = available();
pos += n;
return n;
}
/**
@ -121,7 +110,23 @@ public class StringInputStream extends InputStream{
* reset methods.
*/
public boolean markSupported() {
return false;
return true;
}
/**
* Set the current position as a sae point that can be returned to with the {@link #reset()} method
*
* @param readLimit parameter not used.
*/
public synchronized void mark(int readLimit) {
mark = pos;
}
/**
* Reset the reading position back to the mark point.
*/
public synchronized void reset() {
pos = mark;
}
@ -133,8 +138,19 @@ public class StringInputStream extends InputStream{
clear();
}
public void clear() {
public synchronized void clear() {
buffer = new StringBuilder();
pos = 0;
mark = 0;
}
/**
* Clears the part of the String buffer that has already been read.
*/
public synchronized void clearOld() {
buffer.delete(0, pos);
pos = 0;
mark = 0;
}
public void add(String data) {

View file

@ -27,7 +27,7 @@ package zutil.io;
import java.io.OutputStream;
/**
* This class saves all the input data in to an StringBuffer
* This class saves all the input data into a String
*
* @author Ziver
*

View file

@ -45,12 +45,13 @@ public class FQDNStringSerializer implements BinaryFieldSerializer<String> {
str.append('.');
if ((c & 0b1100_0000) == 0b1100_0000) {
// This a pointer
// This a offset pointer to the String data
int offset = (c & 0b0011_1111) << 8;
offset |= in.read() & 0b1111_1111;
str.append(offset);
break; // PTR is always the last part of the FQDN
} else {
// Normal String
// Normal String data
for (int i = 0; i < c; ++i) {
str.append((char) in.read());
}

View file

@ -0,0 +1,75 @@
package zutil.io;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
public class PositionalInputStreamTest {
@Test
public void read() throws IOException {
PositionalInputStream in = new PositionalInputStream(new StringInputStream("hello"));
assertEquals(0, in.getPosition());
assertEquals('h', (char) in.read());
assertEquals(1, in.getPosition());
assertEquals('e', (char) in.read());
assertEquals(2, in.getPosition());
assertEquals('l', (char) in.read());
assertEquals(3, in.getPosition());
assertEquals('l', (char) in.read());
assertEquals(4, in.getPosition());
assertEquals('o', (char) in.read());
assertEquals(5, in.getPosition());
assertEquals(-1, in.read());
assertEquals(5, in.getPosition());
assertEquals(-1, in.read());
assertEquals(5, in.getPosition());
}
@Test
public void readArray() throws IOException {
PositionalInputStream in = new PositionalInputStream(new StringInputStream("hello world"));
byte[] buffer = new byte[20];
assertEquals(5, in.read(buffer, 0, 5));
assertEquals("hello", new String(buffer, 0, 5));
assertEquals(5, in.getPosition());
assertEquals(' ', (char) in.read());
assertEquals(6, in.getPosition());
assertEquals(5, in.read(buffer));
assertEquals("world", new String(buffer, 0, 5));
assertEquals(11, in.getPosition());
assertEquals(-1, in.read());
assertEquals(11, in.getPosition());
}
@Test
public void skip() throws IOException {
PositionalInputStream in = new PositionalInputStream(new StringInputStream("hello world"));
assertEquals(5, in.skip(5));
assertEquals(5, in.getPosition());
assertEquals(6, in.skip(20));
assertEquals(11, in.getPosition());
}
@Test
public void mark() throws IOException {
PositionalInputStream in = new PositionalInputStream(new StringInputStream("hello world"));
in.mark(20);
assertEquals(6, in.skip(6));
assertEquals(6, in.getPosition());
in.reset();
assertEquals(0, in.getPosition());
assertEquals('h', (char) in.read());
assertEquals(1, in.getPosition());
}
}

View file

@ -0,0 +1,58 @@
package zutil.io;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
public class StringInputStreamTest {
@Test
public void read() throws IOException {
StringInputStream in = new StringInputStream("hello");
assertEquals('h', (char) in.read());
assertEquals('e', (char) in.read());
assertEquals('l', (char) in.read());
assertEquals('l', (char) in.read());
assertEquals('o', (char) in.read());
assertEquals(-1, in.read());
assertEquals(-1, in.read());
}
@Test
public void readArray() throws IOException {
StringInputStream in = new StringInputStream("hello world");
byte[] buffer = new byte[20];
assertEquals(5, in.read(buffer, 0, 5));
assertEquals("hello", new String(buffer, 0, 5));
assertEquals(' ', (char) in.read());
assertEquals(5, in.read(buffer));
assertEquals("world", new String(buffer, 0, 5));
assertEquals(-1, in.read());
}
@Test
public void skip() {
StringInputStream in = new StringInputStream("hello world");
assertEquals(5, in.skip(5));
assertEquals(6, in.skip(20));
}
@Test
public void mark() throws IOException {
StringInputStream in = new StringInputStream("hello world");
in.mark(20);
assertEquals(6, in.skip(6));
in.reset();
assertEquals('h', (char) in.read());
}
}