Boundry stream is working more like a iterator now
This commit is contained in:
parent
e4a5af69db
commit
739b923e1e
4 changed files with 166 additions and 91 deletions
|
|
@ -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
13
src/zutil/io/StringInputStream.java
Normal file → Executable 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;
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue