6864911: ASN.1/DER input stream parser needs more work
Reviewed-by: mullan, xuelei
This commit is contained in:
parent
04185fd4b8
commit
94bafe8b8f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,12 +32,8 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.naming.CommunicationException;
|
||||
import javax.naming.AuthenticationException;
|
||||
import javax.naming.AuthenticationNotSupportedException;
|
||||
import javax.naming.ServiceUnavailableException;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.InterruptedNamingException;
|
||||
@ -47,6 +43,8 @@ import javax.naming.ldap.Control;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import sun.misc.IOUtils;
|
||||
//import javax.net.SocketFactory;
|
||||
|
||||
/**
|
||||
@ -799,7 +797,6 @@ public final class Connection implements Runnable {
|
||||
byte inbuf[]; // Buffer for reading incoming bytes
|
||||
int inMsgId; // Message id of incoming response
|
||||
int bytesread; // Number of bytes in inbuf
|
||||
int bytesleft; // Number of bytes that need to read for completing resp
|
||||
int br; // Temp; number of bytes read from stream
|
||||
int offset; // Offset of where to store bytes in inbuf
|
||||
int seqlen; // Length of ASN sequence
|
||||
@ -811,7 +808,7 @@ public final class Connection implements Runnable {
|
||||
try {
|
||||
while (true) {
|
||||
try {
|
||||
inbuf = new byte[2048];
|
||||
inbuf = new byte[10];
|
||||
|
||||
offset = 0;
|
||||
seqlen = 0;
|
||||
@ -871,19 +868,10 @@ public final class Connection implements Runnable {
|
||||
}
|
||||
|
||||
// read in seqlen bytes
|
||||
bytesleft = seqlen;
|
||||
if ((offset + bytesleft) > inbuf.length) {
|
||||
byte nbuf[] = new byte[offset + bytesleft];
|
||||
System.arraycopy(inbuf, 0, nbuf, 0, offset);
|
||||
inbuf = nbuf;
|
||||
}
|
||||
while (bytesleft > 0) {
|
||||
bytesread = in.read(inbuf, offset, bytesleft);
|
||||
if (bytesread < 0)
|
||||
break; // EOF
|
||||
offset += bytesread;
|
||||
bytesleft -= bytesread;
|
||||
}
|
||||
byte[] left = IOUtils.readFully(in, seqlen, false);
|
||||
inbuf = Arrays.copyOf(inbuf, offset + left.length);
|
||||
System.arraycopy(left, 0, inbuf, offset, left.length);
|
||||
offset += left.length;
|
||||
/*
|
||||
if (dump > 0) {
|
||||
System.err.println("seqlen: " + seqlen);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1995-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -51,6 +51,7 @@ import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import sun.awt.AppContext;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.misc.IOUtils;
|
||||
import sun.net.www.ParseUtil;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
@ -331,36 +332,7 @@ public class AppletClassLoader extends URLClassLoader {
|
||||
|
||||
byte[] b;
|
||||
try {
|
||||
if (len != -1) {
|
||||
// Read exactly len bytes from the input stream
|
||||
b = new byte[len];
|
||||
while (len > 0) {
|
||||
int n = in.read(b, b.length - len, len);
|
||||
if (n == -1) {
|
||||
throw new IOException("unexpected EOF");
|
||||
}
|
||||
len -= n;
|
||||
}
|
||||
} else {
|
||||
// Read until end of stream is reached - use 8K buffer
|
||||
// to speed up performance [stanleyh]
|
||||
b = new byte[8192];
|
||||
int total = 0;
|
||||
while ((len = in.read(b, total, b.length - total)) != -1) {
|
||||
total += len;
|
||||
if (total >= b.length) {
|
||||
byte[] tmp = new byte[total * 2];
|
||||
System.arraycopy(b, 0, tmp, 0, total);
|
||||
b = tmp;
|
||||
}
|
||||
}
|
||||
// Trim array to correct size, if necessary
|
||||
if (total != b.length) {
|
||||
byte[] tmp = new byte[total];
|
||||
System.arraycopy(b, 0, tmp, 0, total);
|
||||
b = tmp;
|
||||
}
|
||||
}
|
||||
b = IOUtils.readFully(in, len, true);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
|
@ -26,9 +26,9 @@
|
||||
package sun.dyn.anon;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import sun.misc.IOUtils;
|
||||
|
||||
/**
|
||||
* Anonymous class loader. Will load any valid classfile, producing
|
||||
@ -285,13 +285,6 @@ public class AnonymousClassLoader {
|
||||
if (contentLength < 0)
|
||||
throw new IOException("invalid content length "+contentLength);
|
||||
|
||||
byte[] classFile = new byte[contentLength];
|
||||
InputStream tcs = connection.getInputStream();
|
||||
for (int fill = 0, nr; fill < classFile.length; fill += nr) {
|
||||
nr = tcs.read(classFile, fill, classFile.length - fill);
|
||||
if (nr < 0)
|
||||
throw new IOException("premature end of file");
|
||||
}
|
||||
return classFile;
|
||||
return IOUtils.readFully(connection.getInputStream(), contentLength, true);
|
||||
}
|
||||
}
|
||||
|
80
jdk/src/share/classes/sun/misc/IOUtils.java
Normal file
80
jdk/src/share/classes/sun/misc/IOUtils.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IOUtils: A collection of IO-related public static methods.
|
||||
*/
|
||||
|
||||
package sun.misc;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class IOUtils {
|
||||
|
||||
/**
|
||||
* Read up to <code>length</code> of bytes from <code>in</code>
|
||||
* until EOF is detected.
|
||||
* @param in input stream, must not be null
|
||||
* @param length number of bytes to read, -1 or Integer.MAX_VALUE means
|
||||
* read as much as possible
|
||||
* @param readAll if true, an EOFException will be thrown if not enough
|
||||
* bytes are read. Ignored when length is -1 or Integer.MAX_VALUE
|
||||
* @return bytes read
|
||||
* @throws IOException Any IO error or a premature EOF is detected
|
||||
*/
|
||||
public static byte[] readFully(InputStream is, int length, boolean readAll)
|
||||
throws IOException {
|
||||
byte[] output = {};
|
||||
if (length == -1) length = Integer.MAX_VALUE;
|
||||
int pos = 0;
|
||||
while (pos < length) {
|
||||
int bytesToRead;
|
||||
if (pos >= output.length) { // Only expand when there's no room
|
||||
bytesToRead = Math.min(length - pos, output.length + 1024);
|
||||
if (output.length < pos + bytesToRead) {
|
||||
output = Arrays.copyOf(output, pos + bytesToRead);
|
||||
}
|
||||
} else {
|
||||
bytesToRead = output.length - pos;
|
||||
}
|
||||
int cc = is.read(output, pos, bytesToRead);
|
||||
if (cc < 0) {
|
||||
if (readAll && length != Integer.MAX_VALUE) {
|
||||
throw new EOFException("Detect premature EOF");
|
||||
} else {
|
||||
if (output.length != pos) {
|
||||
output = Arrays.copyOf(output, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
pos += cc;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,14 +25,15 @@
|
||||
|
||||
package sun.misc;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.net.URL;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.CodeSigner;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.jar.Attributes;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import sun.nio.ByteBuffered;
|
||||
|
||||
/**
|
||||
@ -105,49 +106,37 @@ public abstract class Resource {
|
||||
}
|
||||
|
||||
try {
|
||||
if (len != -1) {
|
||||
// Read exactly len bytes from the input stream
|
||||
b = new byte[len];
|
||||
while (len > 0) {
|
||||
int n = 0;
|
||||
try {
|
||||
n = in.read(b, b.length - len, len);
|
||||
} catch (InterruptedIOException iioe) {
|
||||
Thread.interrupted();
|
||||
isInterrupted = true;
|
||||
b = new byte[0];
|
||||
if (len == -1) len = Integer.MAX_VALUE;
|
||||
int pos = 0;
|
||||
while (pos < len) {
|
||||
int bytesToRead;
|
||||
if (pos >= b.length) { // Only expand when there's no room
|
||||
bytesToRead = Math.min(len - pos, b.length + 1024);
|
||||
if (b.length < pos + bytesToRead) {
|
||||
b = Arrays.copyOf(b, pos + bytesToRead);
|
||||
}
|
||||
if (n == -1) {
|
||||
throw new IOException("unexpected EOF");
|
||||
}
|
||||
len -= n;
|
||||
} else {
|
||||
bytesToRead = b.length - pos;
|
||||
}
|
||||
} else {
|
||||
// Read until end of stream is reached
|
||||
b = new byte[1024];
|
||||
int total = 0;
|
||||
for (;;) {
|
||||
len = 0;
|
||||
try {
|
||||
len = in.read(b, total, b.length - total);
|
||||
if (len == -1)
|
||||
break;
|
||||
} catch (InterruptedIOException iioe) {
|
||||
Thread.interrupted();
|
||||
isInterrupted = true;
|
||||
}
|
||||
total += len;
|
||||
if (total >= b.length) {
|
||||
byte[] tmp = new byte[total * 2];
|
||||
System.arraycopy(b, 0, tmp, 0, total);
|
||||
b = tmp;
|
||||
int cc = 0;
|
||||
try {
|
||||
cc = in.read(b, pos, bytesToRead);
|
||||
} catch (InterruptedIOException iioe) {
|
||||
Thread.interrupted();
|
||||
isInterrupted = true;
|
||||
}
|
||||
if (cc < 0) {
|
||||
if (len != Integer.MAX_VALUE) {
|
||||
throw new EOFException("Detect premature EOF");
|
||||
} else {
|
||||
if (b.length != pos) {
|
||||
b = Arrays.copyOf(b, pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Trim array to correct size, if necessary
|
||||
if (total != b.length) {
|
||||
byte[] tmp = new byte[total];
|
||||
System.arraycopy(b, 0, tmp, 0, total);
|
||||
b = tmp;
|
||||
}
|
||||
pos += cc;
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -44,6 +44,7 @@ import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import sun.misc.IOUtils;
|
||||
import sun.net.www.ParseUtil;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
@ -373,34 +374,7 @@ public final class MethodUtil extends SecureClassLoader {
|
||||
|
||||
byte[] b;
|
||||
try {
|
||||
if (len != -1) {
|
||||
// Read exactly len bytes from the input stream
|
||||
b = new byte[len];
|
||||
while (len > 0) {
|
||||
int n = in.read(b, b.length - len, len);
|
||||
if (n == -1) {
|
||||
throw new IOException("unexpected EOF");
|
||||
}
|
||||
len -= n;
|
||||
}
|
||||
} else {
|
||||
b = new byte[8192];
|
||||
int total = 0;
|
||||
while ((len = in.read(b, total, b.length - total)) != -1) {
|
||||
total += len;
|
||||
if (total >= b.length) {
|
||||
byte[] tmp = new byte[total * 2];
|
||||
System.arraycopy(b, 0, tmp, 0, total);
|
||||
b = tmp;
|
||||
}
|
||||
}
|
||||
// Trim array to correct size, if necessary
|
||||
if (total != b.length) {
|
||||
byte[] tmp = new byte[total];
|
||||
System.arraycopy(b, 0, tmp, 0, total);
|
||||
b = tmp;
|
||||
}
|
||||
}
|
||||
b = IOUtils.readFully(in, len, true);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import java.security.cert.CertPathValidatorException.BasicReason;
|
||||
import java.net.*;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import sun.misc.IOUtils;
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.*;
|
||||
|
||||
@ -351,27 +352,8 @@ class OCSPChecker extends PKIXCertPathChecker {
|
||||
}
|
||||
in = con.getInputStream();
|
||||
|
||||
byte[] response = null;
|
||||
int total = 0;
|
||||
int contentLength = con.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
response = new byte[contentLength];
|
||||
} else {
|
||||
response = new byte[2048];
|
||||
contentLength = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
while (total < contentLength) {
|
||||
int count = in.read(response, total, response.length - total);
|
||||
if (count < 0)
|
||||
break;
|
||||
|
||||
total += count;
|
||||
if (total >= response.length && total < contentLength) {
|
||||
response = Arrays.copyOf(response, total * 2);
|
||||
}
|
||||
}
|
||||
response = Arrays.copyOf(response, total);
|
||||
byte[] response = IOUtils.readFully(in, contentLength, false);
|
||||
|
||||
OCSPResponse ocspResponse = new OCSPResponse(response, pkixParams,
|
||||
responderCert);
|
||||
|
@ -34,6 +34,7 @@ import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.Arrays;
|
||||
|
||||
import sun.misc.IOUtils;
|
||||
import sun.security.pkcs.*;
|
||||
|
||||
/**
|
||||
@ -142,25 +143,7 @@ public class HttpTimestamper implements Timestamper {
|
||||
|
||||
int total = 0;
|
||||
int contentLength = connection.getContentLength();
|
||||
if (contentLength != -1) {
|
||||
replyBuffer = new byte[contentLength];
|
||||
} else {
|
||||
replyBuffer = new byte[2048];
|
||||
contentLength = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
while (total < contentLength) {
|
||||
int count = input.read(replyBuffer, total,
|
||||
replyBuffer.length - total);
|
||||
if (count < 0)
|
||||
break;
|
||||
|
||||
total += count;
|
||||
if (total >= replyBuffer.length && total < contentLength) {
|
||||
replyBuffer = Arrays.copyOf(replyBuffer, total * 2);
|
||||
}
|
||||
}
|
||||
replyBuffer = Arrays.copyOf(replyBuffer, total);
|
||||
replyBuffer = IOUtils.readFully(input, contentLength, false);
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println("received timestamp response (length=" +
|
||||
|
@ -28,6 +28,7 @@ package sun.security.util;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
import sun.misc.IOUtils;
|
||||
|
||||
/**
|
||||
* Represents a single DER-encoded value. DER encoding rules are a subset
|
||||
@ -382,12 +383,8 @@ public class DerValue {
|
||||
if (fullyBuffered && in.available() != length)
|
||||
throw new IOException("extra data given to DerValue constructor");
|
||||
|
||||
byte[] bytes = new byte[length];
|
||||
byte[] bytes = IOUtils.readFully(in, length, true);
|
||||
|
||||
// n.b. readFully not needed in normal fullyBuffered case
|
||||
DataInputStream dis = new DataInputStream(in);
|
||||
|
||||
dis.readFully(bytes);
|
||||
buffer = new DerInputBuffer(bytes);
|
||||
return new DerInputStream(buffer);
|
||||
}
|
||||
|
119
jdk/test/sun/security/util/DerValue/BadValue.java
Normal file
119
jdk/test/sun/security/util/DerValue/BadValue.java
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6864911
|
||||
* @summary ASN.1/DER input stream parser needs more work
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import sun.security.util.*;
|
||||
import sun.misc.IOUtils;
|
||||
|
||||
public class BadValue {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// Test IOUtils.readFully
|
||||
|
||||
// We have 4 bytes
|
||||
InputStream in = new ByteArrayInputStream(new byte[10]);
|
||||
byte[] bs = IOUtils.readFully(in, 4, true);
|
||||
if (bs.length != 4 || in.available() != 6) {
|
||||
throw new Exception("First read error");
|
||||
}
|
||||
// But only 6 left
|
||||
bs = IOUtils.readFully(in, 10, false);
|
||||
if (bs.length != 6 || in.available() != 0) {
|
||||
throw new Exception("Second read error");
|
||||
}
|
||||
// MAX read as much as it can
|
||||
in = new ByteArrayInputStream(new byte[10]);
|
||||
bs = IOUtils.readFully(in, Integer.MAX_VALUE, true);
|
||||
if (bs.length != 10 || in.available() != 0) {
|
||||
throw new Exception("Second read error");
|
||||
}
|
||||
// MAX ignore readAll
|
||||
in = new ByteArrayInputStream(new byte[10]);
|
||||
bs = IOUtils.readFully(in, Integer.MAX_VALUE, false);
|
||||
if (bs.length != 10 || in.available() != 0) {
|
||||
throw new Exception("Second read error");
|
||||
}
|
||||
// 20>10, readAll means failure
|
||||
in = new ByteArrayInputStream(new byte[10]);
|
||||
try {
|
||||
bs = IOUtils.readFully(in, 20, true);
|
||||
throw new Exception("Third read error");
|
||||
} catch (EOFException e) {
|
||||
// OK
|
||||
}
|
||||
int bignum = 10 * 1024 * 1024;
|
||||
bs = IOUtils.readFully(new SuperSlowStream(bignum), -1, true);
|
||||
if (bs.length != bignum) {
|
||||
throw new Exception("Fourth read error");
|
||||
}
|
||||
|
||||
// Test DerValue
|
||||
byte[] input = {0x04, (byte)0x84, 0x40, 0x00, 0x42, 0x46, 0x4b};
|
||||
try {
|
||||
new DerValue(new ByteArrayInputStream(input));
|
||||
} catch (IOException ioe) {
|
||||
// This is OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An InputStream contains a given number of bytes, but only returns one byte
|
||||
* per read.
|
||||
*/
|
||||
class SuperSlowStream extends InputStream {
|
||||
private int p;
|
||||
/**
|
||||
* @param Initial capacity
|
||||
*/
|
||||
public SuperSlowStream(int capacity) {
|
||||
p = capacity;
|
||||
}
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (p > 0) {
|
||||
p--;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if (len == 0) return 0;
|
||||
if (p > 0) {
|
||||
p--;
|
||||
b[off] = 0;
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user