--- old/src/java.base/share/classes/java/io/InputStream.java 2018-10-16 13:42:08.000000000 -0700 +++ new/src/java.base/share/classes/java/io/InputStream.java 2018-10-16 13:42:07.000000000 -0700 @@ -64,8 +64,8 @@ *

While the stream is open, the {@code available()}, {@code read()}, * {@code read(byte[])}, {@code read(byte[], int, int)}, * {@code readAllBytes()}, {@code readNBytes(byte[], int, int)}, - * {@code readNBytes(int)}, {@code skip(long)}, and - * {@code transferTo()} methods all behave as if end of stream has been + * {@code readNBytes(int)}, {@code skip(long)}, {@code skipNBytes(long)}, + * 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}. * @@ -139,6 +139,14 @@ } @Override + public void skipNBytes(long n) throws IOException { + ensureOpen(); + if (n > 0) { + throw new EOFException(); + } + } + + @Override public long transferTo(OutputStream out) throws IOException { Objects.requireNonNull(out); ensureOpen(); @@ -513,11 +521,10 @@ * For instance, the implementation may depend on the ability to seek. * * @param n the number of bytes to be skipped. - * @return the actual number of bytes skipped. + * @return the actual number of bytes skipped which might be zero. * @throws IOException if an I/O error occurs. */ public long skip(long n) throws IOException { - long remaining = n; int nr; @@ -539,6 +546,26 @@ } /** + * Skips over and discards exactly {@code n} bytes of data from this input + * stream. If {@code n <= 0}, no bytes are skipped. If {@code n > 0}, + * then {@code n} bytes of data are skipped unless end of stream is + * encountered first, in which case an {@code EOFException} is thrown. + * + *

This method blocks until data is available to skip, end of file is + * detected, or an exception is thrown. + * + * @param n the number of bytes to be skipped. + * @throws EOFException if end of stream is encountered before {@code n} + * bytes are skipped. + * @throws IOException if an I/O error occurs. + */ + public void skipNBytes(long n) throws IOException { + if (n > 0 && skip(n) != n) { + throw new EOFException("End of stream before enough bytes skipped"); + } + } + + /** * Returns an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking, which may be 0, or 0 when * end of stream is detected. The read might be on the same thread or --- old/test/jdk/java/io/InputStream/NullInputStream.java 2018-10-16 13:42:08.000000000 -0700 +++ new/test/jdk/java/io/InputStream/NullInputStream.java 2018-10-16 13:42:08.000000000 -0700 @@ -22,6 +22,7 @@ */ import java.io.ByteArrayOutputStream; +import java.io.EOFException; import java.io.InputStream; import java.io.IOException; import org.testng.annotations.AfterGroups; @@ -31,7 +32,7 @@ /* * @test - * @bug 4358774 8139206 + * @bug 4358774 6516099 8139206 * @run testng NullInputStream * @summary Check for expected behavior of InputStream.nullInputStream(). */ @@ -146,6 +147,21 @@ } @Test(groups = "open") + public static void testSkipNBytes() { + try { + openStream.skipNBytes(-1); + openStream.skipNBytes(0); + } catch (IOException ioe) { + fail("Unexpected IOException"); + } + } + + @Test(groups = "open", expectedExceptions = EOFException.class) + public static void testSkipNBytesEOF() throws IOException { + openStream.skipNBytes(1); + } + + @Test(groups = "open") public static void testTransferTo() { try { assertEquals(0, openStream.transferTo(new ByteArrayOutputStream(7)), @@ -219,6 +235,15 @@ } @Test(groups = "closed") + public static void testSkipNBytesClosed() { + try { + closedStream.skipNBytes(1); + fail("Expected IOException not thrown"); + } catch (IOException e) { + } + } + + @Test(groups = "closed") public static void testTransferToClosed() { try { closedStream.transferTo(new ByteArrayOutputStream(7)); --- old/test/jdk/java/io/InputStream/Skip.java 2018-10-16 13:42:09.000000000 -0700 +++ new/test/jdk/java/io/InputStream/Skip.java 2018-10-16 13:42:09.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -21,24 +21,22 @@ * questions. */ +/** + * @test + * @bug 4016710 6516099 + * @summary check for correct implementation of InputStream.skip{NBytes} + */ -/* @test - @bug 4016710 - @summary check for correct implementation of InputStream.skip - */ - -import java.io.*; - - -public class Skip{ +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; - private static void dotest(InputStream in , int curpos , - long total , long toskip , long expected) - throws Exception - { +public class Skip { + private static final int EOF = -1; + private static void dotest(InputStream in, int curpos, long total, + long toskip, long expected) throws Exception { try { - System.err.println("\n\nCurrently at pos = " + curpos + "\nTotal bytes in the Stream = " + total + "\nNumber of bytes to skip = " + toskip + @@ -50,19 +48,48 @@ System.err.println("actual number skipped: "+ skipped); if ((skipped < 0) || (skipped > expected)) { - throw new RuntimeException("Unexpected number of bytes skipped"); + throw new RuntimeException("Unexpected byte count skipped"); } - } catch (IOException e) { - System.err.println("IOException is thrown - possible result"); + System.err.println("IOException is thrown: " + e); } catch (Throwable e) { - throw new RuntimeException("Unexpected "+e+" is thrown!"); + throw new RuntimeException("Unexpected " + e + " is thrown!"); } + } + private static void dotestExact(MyInputStream in, int curpos, long total, + long toskip) throws Exception { + try { + System.err.println("\n\nCurrently at pos = " + curpos + + "\nTotal bytes in the Stream = " + total + + "\nNumber of bytes to skip = " + toskip); + + try { + long pos = in.position(); + assert pos == curpos : pos + " != " + curpos; + in.skipNBytes(toskip); + if (in.position() != pos + (toskip < 0 ? 0 : toskip)) { + throw new RuntimeException((in.position() - pos) + + " bytes skipped; expected " + toskip); + } + } catch (EOFException eofe) { + if (!(toskip > 0 && + (curpos == EOF || (curpos + toskip > total)))) { + throw new RuntimeException("Unexpected EOFException", eofe); + } + + System.err.println("Caught expected EOFException"); + + return; + } + } catch (IOException e) { + System.err.println("IOException is thrown: " + e); + } catch (Throwable e) { + throw new RuntimeException("Unexpected " + e + " is thrown!"); + } } public static void main( String argv[] ) throws Exception { - MyInputStream in = new MyInputStream(11); /* test for negative skip */ @@ -72,13 +99,14 @@ dotest(in, 0, 11, 20, 11); /* check for skip after EOF */ - dotest(in, -1, 11, 20, 0); + dotest(in, EOF, 11, 20, 0); in = new MyInputStream(9000); + /* check for skip equal to the read chunk size in InputStream.java */ dotest(in, 0, 9000, 2048, 2048); - /* check for skip greater than the read chunk size in InputStream.java */ + /* check for skip larger than the read chunk size in InputStream.java */ dotest(in, 2048, 9000, 5000, 5000); /* check for skip beyond EOF starting from before EOF */ @@ -98,13 +126,31 @@ * dotest(in, 0, total, toskip, toskip); */ - } + /* tests for skipping an exact number of bytes */ + + in = new MyInputStream(11); + + /* test for negative skip */ + dotestExact(in, 0, 11, -23); + /* test for zero skip */ + dotestExact(in, 0, 11, 0); + + /* test for skip before EOF */ + dotestExact(in, 0, 11, 5); + + /* check for skip beyond EOF starting from before EOF */ + dotestExact(in, 5, 11, 7); + + /* check for skip from / after EOF */ + dotestExact(in, EOF, 11, 1); + } } class MyInputStream extends InputStream { + private static final int EOF = -1; - private int readctr = 0; + private long readctr = 0; private long endoffile; public MyInputStream(long endoffile) { @@ -112,9 +158,8 @@ } public int read() { - if (readctr == endoffile) { - return -1; + return EOF; } else { readctr++; @@ -123,4 +168,6 @@ } public int available() { return 0; } + + public long position() { return readctr == endoffile ? EOF : readctr; } }