Index: src/main/java/java/io/BufferedOutputStream.java =================================================================== --- src/main/java/java/io/BufferedOutputStream.java (revision 547334) +++ src/main/java/java/io/BufferedOutputStream.java (working copy) @@ -84,10 +84,7 @@ */ @Override public synchronized void flush() throws IOException { - if (count > 0) { - out.write(buf, 0, count); - } - count = 0; + flushInternal(); out.flush(); } @@ -122,7 +119,8 @@ throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$ } - if (count == 0 && length >= buf.length) { + if (length >= buf.length) { + flushInternal(); out.write(buffer, offset, length); return; } @@ -131,29 +129,15 @@ // K002f=Arguments out of bounds throw new ArrayIndexOutOfBoundsException(Msg.getString("K002f")); //$NON-NLS-1$ } - - int available = buf.length - count; - if (length < available) { - available = length; + + // flush the internal buffer first if we have not enough space left + if (length >= (buf.length - count)) { + flushInternal(); } - if (available > 0) { - System.arraycopy(buffer, offset, buf, count, available); - count += available; - } - if (count == buf.length) { - out.write(buf, 0, buf.length); - count = 0; - if (length > available) { - offset += available; - available = length - available; - if (available >= buf.length) { - out.write(buffer, offset, available); - } else { - System.arraycopy(buffer, offset, buf, count, available); - count += available; - } - } - } + + // the length is always less than (buf.length - count) here so arraycopy is safe + System.arraycopy(buffer, offset, buf, count, length); + count += length; } /** @@ -179,4 +163,14 @@ } buf[count++] = (byte) oneByte; } + + /** + * Flushes only internal buffer. + */ + private void flushInternal() throws IOException { + if (count > 0) { + out.write(buf, 0, count); + } + count = 0; + } } Index: src/test/java/tests/api/java/io/BufferedOutputStreamTest.java =================================================================== --- src/test/java/tests/api/java/io/BufferedOutputStreamTest.java (revision 546816) +++ src/test/java/tests/api/java/io/BufferedOutputStreamTest.java (working copy) @@ -82,6 +82,24 @@ } } + private static class MockOutputStream extends OutputStream { + byte[] written; + int count; + + public MockOutputStream(int size) { + written = new byte[size]; + count = 0; + } + + public void write(int b) { + written[count++] = (byte)b; + } + + public String getWritten() { + return new String(written, 0, count); + } + } + /** * @tests java.io.BufferedOutputStream#write(byte[], int, int) */ @@ -105,8 +123,20 @@ bais.read(wbytes, 0, 1013); assertTrue("Incorrect bytes written", fileString.substring(0, 1013) .equals(new String(wbytes, 0, wbytes.length))); + + // regression test for HARMONY-4177 + MockOutputStream mos = new MockOutputStream(5); + BufferedOutputStream bos = new BufferedOutputStream(mos, 3); + bos.write("a".getBytes()); + bos.write("bcde".getBytes()); + assertEquals("Large data should be written directly", "abcde", mos.getWritten()); + mos = new MockOutputStream(4); + bos = new BufferedOutputStream(mos, 3); + bos.write("ab".getBytes()); + bos.write("cd".getBytes()); + assertEquals("Should flush before write", "ab", mos.getWritten()); } catch (java.io.IOException e) { - fail("Flush test failed"); + fail("write$BII test failed: " + e); } }