Boundry stream is working more like a iterator now

This commit is contained in:
Ziver Koc 2016-07-11 23:55:47 +02:00
parent e4a5af69db
commit 739b923e1e
4 changed files with 166 additions and 91 deletions

View file

@ -39,7 +39,7 @@ import java.io.InputStream;
*/ */
public class BufferedBoundaryInputStream extends FilterInputStream{ public class BufferedBoundaryInputStream extends FilterInputStream{
/** The size of the buffer in bytes */ /** The size of the buffer in bytes */
private static final int DEFAULT_BUF_SIZE = 8192; protected static final int DEFAULT_BUF_SIZE = 8192;
/** The raw buffer */ /** The raw buffer */
private byte buffer[]; private byte buffer[];
@ -76,43 +76,16 @@ public class BufferedBoundaryInputStream extends FilterInputStream{
buffer = new byte[buf_size]; buffer = new byte[buf_size];
} }
/**
* Moves the remaining data to the beginning of the
* buffer and then fills the buffer with data from
* the source stream to the buffer
*
* @return the size of the buffer
*/
protected int fillBuffer() throws IOException {
int leftover = buf_end - buf_pos;
// is there any data available
if(leftover < 0 && super.available() <= 0)
return -1; // EOF
// Move the end of the buffer to the start to not miss any split boundary
System.arraycopy(buffer, buf_pos, buffer, 0, buf_end);
// Copy in new data from the stream
int n = super.read(buffer, leftover, buffer.length );
// Reset positions
if(n+leftover >= 0) {
buf_end = leftover + n;
buf_pos = 0;
}
searchNextBoundary();
return n+leftover;
}
/** /**
* @return the next byte in the buffer * @return the next byte in the buffer
*/ */
public final int read() throws IOException{ public final int read() throws IOException{
if(buf_pos >= buf_end-boundary.length) { if (fillBuffer() < 0)
if(fillBuffer() <= 0) return -1;
return -1; // EOF
}
if(buf_bound_pos == buf_pos) if(isOnBoundary())
return -1; // boundary return -1; // boundary
return buffer[buf_pos++]; return buffer[buf_pos++];
} }
@ -136,15 +109,13 @@ public class BufferedBoundaryInputStream extends FilterInputStream{
* @return the amount of bytes read or -1 if EOF * @return the amount of bytes read or -1 if EOF
*/ */
public int read(byte b[], int off, int len) throws IOException { public int read(byte b[], int off, int len) throws IOException {
if(buf_pos >= buf_end-boundary.length) { if (fillBuffer() < 0)
if(fillBuffer() <= 0)
return -1; // EOF return -1; // EOF
} if(isOnBoundary())
if(buf_bound_pos == buf_pos)
return -1; // boundary return -1; // boundary
// The request is larger then the buffer size // The request is larger then the buffer size
int leftover = buf_end - buf_pos; int leftover = available();
if(len > leftover){ if(len > leftover){
len = leftover; len = leftover;
} }
@ -160,40 +131,43 @@ public class BufferedBoundaryInputStream extends FilterInputStream{
/** /**
* @return if there is more data to read * @return if the current position in the buffer is a boundary
*/ */
public boolean isOnBoundary(){ private boolean isOnBoundary(){
return buf_bound_pos == buf_pos; return buf_bound_pos == buf_pos;
} }
/**
* Skips over the boundary at the current position in the buffer
*/
public boolean next(){
if(buf_bound_pos == buf_pos){
buf_pos += boundary.length;
searchNextBoundary();
return buf_end >= buf_pos;
}
return true;
}
/** /**
* Searches for the nearest boundary from the current position * Checks if there is more data available after the boundary.
* Note if the data between boundaries are longer than the buffer
* size then this method will return true until the next boundary
* is available in the buffer or the end of the stream.
*
* @return true if there is more data available after the closest boundary.
*/ */
protected void searchNextBoundary(){ public boolean hasNext() throws IOException {
for(int i=buf_pos; i<buf_end; i++){ if (buf_bound_pos < 0 && fillBuffer() >= 0)
for(int b=0; b < boundary.length; b++){ return true; // the boundary not in the buffer?
if(buffer[i+b] != boundary[b]) if (buf_bound_pos >= 0 && buf_bound_pos + boundary.length < buf_end)
break; return true; // there is more data beyond boundary in the buffer
else if(b == boundary.length-1){ return false;
buf_bound_pos = i; }
return; /**
* Skips over the closest boundary
*/
public void next() throws IOException {
if (buf_bound_pos >= 0){ // is boundary in buffer?
buf_pos += boundary.length;
searchNextBoundary();
}
else { // read data until we find the next boundary or get to the end of the stream
buf_pos = buf_end;
while (buf_bound_pos >= 0 || fillBuffer() < 0);
} }
} }
}
buf_bound_pos = -1;
}
/** /**
* Skips a specific amounts of bytes in the buffer. * Skips a specific amounts of bytes in the buffer.
@ -203,7 +177,7 @@ public class BufferedBoundaryInputStream extends FilterInputStream{
* @return the actual number of bytes skipped. * @return the actual number of bytes skipped.
*/ */
public long skip(long n) throws IOException { public long skip(long n) throws IOException {
int leftover = buf_end - buf_pos; int leftover = available();
if(n > leftover){ if(n > leftover){
buf_pos = buf_end; buf_pos = buf_end;
return leftover; return leftover;
@ -243,4 +217,55 @@ public class BufferedBoundaryInputStream extends FilterInputStream{
public boolean markSupported(){ public boolean markSupported(){
return false; return false;
} }
/**
* Checks if the buffer needs to be appended with data.
* If so it moves the remaining data to the beginning of the
* buffer and then fills the buffer with data from
* the source stream
*
* @return the number of new bytes read from the source stream
*/
private int fillBuffer() throws IOException {
int leftover = available();
// Do we need to fill the buffer
if(buf_pos < buf_end-boundary.length)
return 0;
// is there any data available
if(leftover <= 0 && super.available() <= 0)
return -1; // EOF
// Move the end of the buffer to the start to not miss any split boundary
if (leftover > 0)
System.arraycopy(buffer, buf_pos, buffer, 0, leftover);
// Copy in new data from the stream
int n = super.read(buffer, leftover, buffer.length-leftover );
// Reset positions
if(n+leftover >= 0) {
buf_end = leftover + n;
buf_pos = 0;
}
searchNextBoundary();
return n;
}
/**
* Searches for the nearest boundary from the current buffer position
*/
private void searchNextBoundary(){
for(int i=buf_pos; i<buf_end; i++){
for(int b=0; b < boundary.length; b++){
if(buffer[i+b] != boundary[b])
break;
else if(b == boundary.length-1){
buf_bound_pos = i;
return;
}
}
}
buf_bound_pos = -1;
}
} }

13
src/zutil/io/StringInputStream.java Normal file → Executable file
View file

@ -63,13 +63,13 @@ public class StringInputStream extends InputStream{
* Reads the next byte of data from the input stream. * Reads the next byte of data from the input stream.
*/ */
public int read(){ public int read(){
if(buffer.length() > 0){ if(buffer.length() == 0)
return -1;
int ret = Character.getNumericValue( buffer.charAt( 0 )); int ret = Character.getNumericValue( buffer.charAt( 0 ));
buffer.deleteCharAt( 0 ); buffer.deleteCharAt( 0 );
return ret; return ret;
} }
return -1;
}
/** /**
* Reads some number of bytes from the input stream * Reads some number of bytes from the input stream
@ -84,12 +84,13 @@ public class StringInputStream extends InputStream{
* into an array of bytes. * into an array of bytes.
*/ */
public int read(byte[] b, int off, int len){ public int read(byte[] b, int off, int len){
if(buffer.length() == 0)
return -1;
if( buffer.length() < len ){ if( buffer.length() < len ){
len = buffer.length(); len = buffer.length();
} }
char[] ctmp = new char[len]; byte[] btmp = buffer.substring(0, len).getBytes();
buffer.getChars(0, len, ctmp, 0);
byte[] btmp = new String( ctmp ).getBytes();
System.arraycopy(btmp, 0, b, off, len); System.arraycopy(btmp, 0, b, off, len);
buffer.delete(0, len); buffer.delete(0, len);
return len; return len;

View file

@ -119,9 +119,8 @@ public class MultipartParser implements Iterable<MultipartField>{
@Override @Override
public boolean hasNext() { public boolean hasNext() {
try { try {
IOUtil.copyStream(buffIn, new NullWriter()); return boundaryIn.hasNext();
return boundaryIn.isOnBoundary(); } catch (IOException e) {
} catch (IOException e){
logger.log(Level.SEVERE, null, e); logger.log(Level.SEVERE, null, e);
} }
return false; return false;

View file

@ -42,21 +42,22 @@ public class BufferedBoundaryInputStreamTest {
BufferedBoundaryInputStream in = new BufferedBoundaryInputStream(inin); BufferedBoundaryInputStream in = new BufferedBoundaryInputStream(inin);
in.setBoundary("#"); in.setBoundary("#");
assertTrue(in.hasNext());
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertTrue(in.isOnBoundary());
assertTrue(in.hasNext());
in.next(); in.next();
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertTrue(in.isOnBoundary());
assertTrue(in.hasNext());
in.next(); in.next();
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertTrue(in.isOnBoundary());
assertTrue(in.hasNext());
in.next(); in.next();
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals('a', in.read()); assertEquals('a', in.read());
@ -66,11 +67,11 @@ public class BufferedBoundaryInputStreamTest {
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertTrue(in.isOnBoundary());
assertFalse(in.hasNext());
in.next(); in.next();
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertFalse(in.isOnBoundary()); assertFalse(in.hasNext());
} }
@Test @Test
public void readArr_normal() throws IOException { public void readArr_normal() throws IOException {
@ -82,14 +83,17 @@ public class BufferedBoundaryInputStreamTest {
int n = in.read(buff); int n = in.read(buff);
assertEquals(3, n); assertEquals(3, n);
assertTrue(in.hasNext());
in.next(); in.next();
n = in.read(buff); n = in.read(buff);
assertEquals(16, n); assertEquals(16, n);
assertTrue(in.hasNext());
in.next(); in.next();
n = in.read(buff); n = in.read(buff);
assertEquals(15, n); assertEquals(15, n);
assertFalse(in.hasNext());
in.next(); in.next();
n = in.read(buff); n = in.read(buff);
assertEquals(-1, n); assertEquals(-1, n);
@ -104,11 +108,11 @@ public class BufferedBoundaryInputStreamTest {
byte[] buff = new byte[100]; byte[] buff = new byte[100];
assertEquals(3, in.read(buff)); assertEquals(3, in.read(buff));
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertTrue(in.isOnBoundary());
assertFalse(in.hasNext());
in.next(); in.next();
assertEquals(-1, in.read(buff)); assertEquals(-1, in.read(buff));
assertFalse(in.isOnBoundary()); assertFalse(in.hasNext());
} }
@Test @Test
public void readArr_multiCharBoundary() throws IOException { public void readArr_multiCharBoundary() throws IOException {
@ -120,11 +124,11 @@ public class BufferedBoundaryInputStreamTest {
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals('a', in.read()); assertEquals('a', in.read());
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertTrue(in.isOnBoundary());
assertFalse(in.hasNext());
in.next(); in.next();
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertFalse(in.isOnBoundary()); assertFalse(in.hasNext());
} }
@Test @Test
@ -151,12 +155,10 @@ public class BufferedBoundaryInputStreamTest {
in.setBoundary("a"); in.setBoundary("a");
int n; int n;
for(n=1; true; n++){ for(n=1; in.hasNext(); n++){
assertEquals(-1, in.read()); assertEquals(-1, in.read());
assertEquals(-1, in.read()); assertEquals(-1, in.read());
in.next(); in.next();
if(!in.isOnBoundary())
break;
} }
assertEquals(35, n); assertEquals(35, n);
} }
@ -168,12 +170,10 @@ public class BufferedBoundaryInputStreamTest {
byte[] buff = new byte[100]; byte[] buff = new byte[100];
int n; int n;
for(n=1; true; n++){ for(n=1; in.hasNext(); n++){
assertEquals(-1, in.read(buff)); assertEquals(-1, in.read(buff));
assertEquals(-1, in.read(buff)); assertEquals(-1, in.read(buff));
in.next(); in.next();
if(!in.isOnBoundary())
break;
} }
assertEquals(35, n); assertEquals(35, n);
} }
@ -203,4 +203,54 @@ public class BufferedBoundaryInputStreamTest {
assertEquals(data.length(), in.read(buff)); assertEquals(data.length(), in.read(buff));
assertEquals(data, new String(buff, 0, data.length())); assertEquals(data, new String(buff, 0, data.length()));
} }
@Test
public void read_largeData() throws IOException {
String data = "aaaaaaaaaaaa#aa#aaaaaaaaaaaaaaa#";
StringInputStream inin = new StringInputStream(data);
BufferedBoundaryInputStream in = new BufferedBoundaryInputStream(inin, 10);
in.setBoundary("#");
assertTrue(in.hasNext());
for (int i=0; i<12; ++i)
assertEquals('a', in.read());
assertEquals(-1, in.read());
assertTrue(in.hasNext());
in.next();
assertEquals('a', in.read());
assertEquals('a', in.read());
assertTrue(in.hasNext());
in.next();
for (int i=0; i<15; ++i)
assertEquals('a', in.read());
assertEquals(-1, in.read());
assertFalse(in.hasNext());
}
@Test
public void readArr_largeData() throws IOException {
String data = "aaaaaaaaaaaa#aa#aaaaaaaaaaaaaaa#";
StringInputStream inin = new StringInputStream(data);
BufferedBoundaryInputStream in = new BufferedBoundaryInputStream(inin, 10);
in.setBoundary("#");
byte[] buff = new byte[100];
assertTrue(in.hasNext());
assertEquals(10, in.read(buff));
assertEquals(2, in.read(buff));
assertEquals(-1, in.read());
assertTrue(in.hasNext());
in.next();
assertEquals(2, in.read(buff));
assertTrue(in.hasNext());
in.next();
assertEquals(10, in.read(buff));
assertEquals(5, in.read(buff));
assertEquals(-1, in.read());
assertFalse(in.hasNext());
}
} }