--- old/src/java.base/share/classes/java/io/InputStream.java 2018-01-17 08:15:49.000000000 -0800 +++ new/src/java.base/share/classes/java/io/InputStream.java 2018-01-17 08:15:48.000000000 -0800 @@ -63,7 +63,8 @@ * *
While the stream is open, the {@code available()}, {@code read()},
* {@code read(byte[])}, {@code read(byte[], int, int)},
- * {@code readAllBytes()}, {@code readNBytes()}, {@code skip()}, and
+ * {@code readAllBytes()}, {@code readNBytes(byte[], int, int)},
+ * {@code readNBytes(int)}, {@code skip()}, and
* {@code transferTo()} methods all behave as if end of stream has been
* reached. After the stream has been closed, these methods all throw
* {@code IOException}.
@@ -123,6 +124,16 @@
}
@Override
+ public byte[] readNBytes(int len)
+ throws IOException {
+ if (len < 0) {
+ throw new IllegalArgumentException("len < 0");
+ }
+ ensureOpen();
+ return new byte[0];
+ }
+
+ @Override
public long skip(long n) throws IOException {
ensureOpen();
return 0L;
@@ -233,8 +244,8 @@
* b
and the number of bytes read before the exception
* occurred is returned. The default implementation of this method blocks
* until the requested amount of input data len
has been read,
- * end of file is detected, or an exception is thrown. Subclasses are encouraged
- * to provide a more efficient implementation of this method.
+ * end of file is detected, or an exception is thrown. Subclasses are
+ * encouraged to provide a more efficient implementation of this method.
*
* @param b the buffer into which the data is read.
* @param off the start offset in array b
@@ -287,16 +298,22 @@
private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
/**
- * Reads all remaining bytes from the input stream. This method blocks until
- * all remaining bytes have been read and end of stream is detected, or an
- * exception is thrown. This method does not close the input stream.
+ * Reads a number of bytes from the input stream. The number of bytes to
+ * read is specified by the {@code len} parameter which is interpreted as
+ * an inclusive upper bound on the number to read. This method blocks
+ * until the requested number of bytes have been read, end of stream is
+ * detected, or an exception is thrown. This method does not close the
+ * input stream.
+ *
+ *
If {@code len} is zero, then no bytes are read and an empty byte + * array is returned. * *
When this stream reaches end of stream, further invocations of this * method will return an empty byte array. * *
Note that this method is intended for simple cases where it is - * convenient to read all bytes into a byte array. It is not intended for - * reading input streams with large amounts of data. + * convenient to read the specified number of bytes into a byte array. It + * is not intended for reading large amounts of data. * *
The behavior for the case where the input stream is asynchronously
* closed, or the thread interrupted during the read, is highly input
@@ -308,26 +325,36 @@
* It is strongly recommended that the stream be promptly closed if an I/O
* error occurs.
*
+ * @param len the maximum number of bytes to read
* @return a byte array containing the bytes read from this input stream
+ * @throws IllegalArgumentException if {@code len} is negative
* @throws IOException if an I/O error occurs
* @throws OutOfMemoryError if an array of the required size cannot be
* allocated. For example, if an array larger than {@code 2GB} would
* be required to store the bytes.
*
- * @since 9
+ * @since 11
*/
- public byte[] readAllBytes() throws IOException {
+ private byte[] readAtMostNBytes(int len)
+ throws IOException {
+ if (len < 0) {
+ throw new IllegalArgumentException("len < 0");
+ }
+
List When this stream reaches end of stream, further invocations of this
+ * method will return an empty byte array.
+ *
+ * Note that this method is intended for simple cases where it is
+ * convenient to read all bytes into a byte array. It is not intended for
+ * reading input streams with large amounts of data.
+ *
+ * The behavior for the case where the input stream is asynchronously
+ * closed, or the thread interrupted during the read, is highly input
+ * stream specific, and therefore not specified.
+ *
+ * If an I/O error occurs reading from the input stream, then it may do
+ * so after some, but not all, bytes have been read. Consequently the input
+ * stream may not be at end of stream and may be in an inconsistent state.
+ * It is strongly recommended that the stream be promptly closed if an I/O
+ * error occurs.
+ *
+ * @return a byte array containing the bytes read from this input stream
+ * @throws IOException if an I/O error occurs
+ * @throws OutOfMemoryError if an array of the required size cannot be
+ * allocated. For example, if an array larger than {@code 2GB} would
+ * be required to store the bytes.
+ *
+ * @since 9
+ */
+ public byte[] readAllBytes() throws IOException {
+ return readAtMostNBytes(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Reads up to a specified number of bytes from the input stream. This
+ * method blocks until the requested number of bytes have been read, end
+ * of stream is detected, or an exception is thrown. This method does not
+ * close the input stream.
+ *
+ * The length of the returned array equals the number of bytes read
+ * from the stream. If {@code len} is zero, then no bytes are read and
+ * an empty byte array is returned. Otherwise, up to {@code len} bytes
+ * are read from the stream. Fewer than {@code len} bytes may be read if
+ * end of stream is encountered.
+ *
+ * When this stream reaches end of stream, further invocations of this
+ * method will return an empty byte array.
+ *
+ * Note that this method is intended for simple cases where it is
+ * convenient to read the specified number of bytes into a byte array. It
+ * is not intended for reading large amounts of data.
+ *
+ * The behavior for the case where the input stream is asynchronously
+ * closed, or the thread interrupted during the read, is highly input
+ * stream specific, and therefore not specified.
+ *
+ * If an I/O error occurs reading from the input stream, then it may do
+ * so after some, but not all, bytes have been read. Consequently the input
+ * stream may not be at end of stream and may be in an inconsistent state.
+ * It is strongly recommended that the stream be promptly closed if an I/O
+ * error occurs.
+ *
+ * @param len the maximum number of bytes to read
+ * @return a byte array containing the bytes read from this input stream
+ * @throws IllegalArgumentException if {@code length} is negative
+ * @throws IOException if an I/O error occurs
+ * @throws OutOfMemoryError if an array of the required size cannot be
+ * allocated. For example, if an array larger than {@code 2GB} would
+ * be required to store the bytes.
+ *
+ * @since 11
+ */
+ public byte[] readNBytes(int len) throws IOException {
+ return readAtMostNBytes(len);
+ }
+
+ /**
* Reads the requested number of bytes from the input stream into the given
* byte array. This method blocks until {@code len} bytes of input data have
* been read, end of stream is detected, or an exception is thrown. The
--- old/test/jdk/java/io/InputStream/NullInputStream.java 2018-01-17 08:15:49.000000000 -0800
+++ new/test/jdk/java/io/InputStream/NullInputStream.java 2018-01-17 08:15:49.000000000 -0800
@@ -31,7 +31,7 @@
/*
* @test
- * @bug 4358774
+ * @bug 4358774 8139206
* @run testng NullInputStream
* @summary Check for expected behavior of InputStream.nullInputStream().
*/
@@ -107,7 +107,7 @@
}
@Test(groups = "open")
- public static void testreadNBytes() {
+ public static void testReadNBytes() {
try {
assertEquals(0, openStream.readNBytes(new byte[1], 0, 1),
"readNBytes(byte[],int,int) != 0");
@@ -117,6 +117,26 @@
}
@Test(groups = "open")
+ public static void testReadNBytesWithLength() {
+ try {
+ assertEquals(0, openStream.readNBytes(-1).length,
+ "readNBytes(-1) != 0");
+ fail("Expected IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException iae) {
+ } catch (IOException ioe) {
+ fail("Unexpected IOException");
+ }
+ try {
+ assertEquals(0, openStream.readNBytes(0).length,
+ "readNBytes(0, false) != 0");
+ assertEquals(0, openStream.readNBytes(1).length,
+ "readNBytes(1, false) != 0");
+ } catch (IOException ioe) {
+ fail("Unexpected IOException");
+ }
+ }
+
+ @Test(groups = "open")
public static void testSkip() {
try {
assertEquals(0, openStream.skip(1), "skip() != 0");
@@ -181,6 +201,15 @@
}
@Test(groups = "closed")
+ public static void testReadNBytesWithLengthClosed() {
+ try {
+ closedStream.readNBytes(1);
+ fail("Expected IOException not thrown");
+ } catch (IOException e) {
+ }
+ }
+
+ @Test(groups = "closed")
public static void testSkipClosed() {
try {
closedStream.skip(1);
--- old/test/jdk/java/io/InputStream/ReadNBytes.java 2018-01-17 08:15:49.000000000 -0800
+++ new/test/jdk/java/io/InputStream/ReadNBytes.java 2018-01-17 08:15:49.000000000 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. 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
@@ -31,7 +31,7 @@
/*
* @test
- * @bug 8080835
+ * @bug 8080835 8139206
* @library /test/lib
* @build jdk.test.lib.RandomFactory
* @run main ReadNBytes
@@ -46,15 +46,19 @@
public static void main(String[] args) throws IOException {
test(new byte[]{1, 2, 3});
test(createRandomBytes(1024));
- test(createRandomBytes((1 << 13) - 1));
- test(createRandomBytes((1 << 13)));
- test(createRandomBytes((1 << 13) + 1));
- test(createRandomBytes((1 << 15) - 1));
- test(createRandomBytes((1 << 15)));
- test(createRandomBytes((1 << 15) + 1));
- test(createRandomBytes((1 << 17) - 1));
- test(createRandomBytes((1 << 17)));
- test(createRandomBytes((1 << 17) + 1));
+ for (int shift : new int[] {13, 15, 17}) {
+ for (int offset : new int[] {-1, 0, 1}) {
+ test(createRandomBytes((1 << shift) + offset));
+ }
+ }
+
+ test(-1);
+ test(0);
+ for (int shift : new int[] {13, 15, 17}) {
+ for (int offset : new int[] {-1, 0, 1}) {
+ test((1 << shift) + offset);
+ }
+ }
}
static void test(byte[] inputBytes) throws IOException {
@@ -91,6 +95,46 @@
check(!in.isClosed(), "Stream unexpectedly closed");
}
+ static void test(int max) throws IOException {
+ byte[] inputBytes = max <= 0 ? new byte[0] : createRandomBytes(max);
+ WrapperInputStream in =
+ new WrapperInputStream(new ByteArrayInputStream(inputBytes));
+
+ if (max < 0) {
+ try {
+ in.readNBytes(max);
+ check(false, "Expected IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException iae) {
+ return;
+ }
+ } else if (max == 0) {
+ int x;
+ check((x = in.readNBytes(max).length) == 0,
+ "Expected zero bytes, got " + x);
+ return;
+ }
+
+ int off = Math.toIntExact(in.skip(generator.nextInt(max/2)));
+ int len = generator.nextInt(max - 1 - off);
+ byte[] readBytes = in.readNBytes(len);
+ check(readBytes.length == len,
+ "Expected " + len + " bytes, got " + readBytes.length);
+ check(Arrays.equals(inputBytes, off, off + len, readBytes, 0, len),
+ "Expected[" + Arrays.copyOfRange(inputBytes, off, off + len) +
+ "], got:[" + readBytes + "]");
+
+ int remaining = max - (off + len);
+ readBytes = in.readNBytes(remaining);
+ check(readBytes.length == remaining,
+ "Expected " + remaining + "bytes, got " + readBytes.length);
+ check(Arrays.equals(inputBytes, off + len, max,
+ readBytes, 0, remaining),
+ "Expected[" + Arrays.copyOfRange(inputBytes, off + len, max) +
+ "], got:[" + readBytes + "]");
+
+ check(!in.isClosed(), "Stream unexpectedly closed");
+ }
+
static byte[] createRandomBytes(int size) {
byte[] bytes = new byte[size];
generator.nextBytes(bytes);