8178401: Various audio files writers do not close file streams properly
authorserb
Sun, 10 Dec 2017 00:08:42 -0800
changeset 48282 4483880d8811
parent 48281 1a6c071312a3
child 48283 da1b57b17101
8178401: Various audio files writers do not close file streams properly Reviewed-by: prr
src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java
src/java.desktop/share/classes/com/sun/media/sound/AuFileWriter.java
src/java.desktop/share/classes/com/sun/media/sound/WaveFileWriter.java
src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileWriter.java
test/jdk/ProblemList.txt
test/jdk/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java
--- a/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java	Sat Dec 09 20:40:45 2017 -0800
+++ b/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java	Sun Dec 10 00:08:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -113,10 +113,11 @@
         AiffFileFormat aiffFileFormat = (AiffFileFormat)getAudioFileFormat(fileType, stream);
 
         // first write the file without worrying about length fields
-        FileOutputStream fos = new FileOutputStream( out );     // throws IOException
-        BufferedOutputStream bos = new BufferedOutputStream( fos, bisBufferSize );
-        int bytesWritten = writeAiffFile(stream, aiffFileFormat, bos );
-        bos.close();
+        final int bytesWritten;
+        try (final FileOutputStream fos = new FileOutputStream(out);
+             final BufferedOutputStream bos = new BufferedOutputStream(fos)) {
+            bytesWritten = writeAiffFile(stream, aiffFileFormat, bos);
+        }
 
         // now, if length fields were not specified, calculate them,
         // open as a random access file, write the appropriate fields,
@@ -134,20 +135,19 @@
             long dataSize=ssndChunkSize-16;
             //TODO possibly incorrect round
             int numFrames = (int) (dataSize / ssndBlockSize);
-
-            RandomAccessFile raf=new RandomAccessFile(out, "rw");
-            // skip FORM magic
-            raf.skipBytes(4);
-            raf.writeInt(aiffLength-8);
-            // skip aiff2 magic, fver chunk, comm magic, comm size, channel count,
-            raf.skipBytes(4+aiffFileFormat.getFverChunkSize()+4+4+2);
-            // write frame count
-            raf.writeInt(numFrames);
-            // skip sample size, samplerate, SSND magic
-            raf.skipBytes(2+10+4);
-            raf.writeInt(ssndChunkSize-8);
-            // that's all
-            raf.close();
+            try (final RandomAccessFile raf = new RandomAccessFile(out, "rw")) {
+                // skip FORM magic
+                raf.skipBytes(4);
+                raf.writeInt(aiffLength - 8);
+                // skip aiff2 magic, fver chunk, comm magic, comm size, channel count,
+                raf.skipBytes(4 + aiffFileFormat.getFverChunkSize() + 4 + 4 + 2);
+                // write frame count
+                raf.writeInt(numFrames);
+                // skip sample size, samplerate, SSND magic
+                raf.skipBytes(2 + 10 + 4);
+                raf.writeInt(ssndChunkSize - 8);
+                // that's all
+            }
         }
 
         return bytesWritten;
@@ -289,10 +289,6 @@
         int compCode = AiffFileFormat.AIFC_PCM;
 
         byte header[] = null;
-        ByteArrayInputStream headerStream = null;
-        ByteArrayOutputStream baos = null;
-        DataOutputStream dos = null;
-        SequenceInputStream aiffStream = null;
         InputStream codedAudioStream = audioStream;
 
         // if we need to do any format conversion, do it here....
@@ -343,52 +339,39 @@
 
 
         // Now create an AIFF stream header...
-        baos = new ByteArrayOutputStream();
-        dos = new DataOutputStream(baos);
-
-        // Write the outer FORM chunk
-        dos.writeInt(AiffFileFormat.AIFF_MAGIC);
-        dos.writeInt( (aiffLength-8) );
-        dos.writeInt(AiffFileFormat.AIFF_MAGIC2);
-
-        // Write a FVER chunk - only for AIFC
-        //dos.writeInt(FVER_MAGIC);
-        //dos.writeInt( (fverChunkSize-8) );
-        //dos.writeInt(FVER_TIMESTAMP);
-
-        // Write a COMM chunk
-        dos.writeInt(AiffFileFormat.COMM_MAGIC);
-        dos.writeInt( (commChunkSize-8) );
-        dos.writeShort(channels);
-        dos.writeInt(numFrames);
-        dos.writeShort(sampleSize);
-        write_ieee_extended(dos, sampleFramesPerSecond);   // 10 bytes
-
-        //Only for AIFC
-        //dos.writeInt(compCode);
-        //dos.writeInt(compCode);
-        //dos.writeShort(0);
-
-        // Write the SSND chunk header
-        dos.writeInt(AiffFileFormat.SSND_MAGIC);
-        dos.writeInt( (ssndChunkSize-8) );
-        // ssndOffset and ssndBlockSize set to 0 upon
-        // recommendation in "Sound Manager" chapter in
-        // "Inside Macintosh Sound", pp 2-87  (from Babu)
-        dos.writeInt(0);        // ssndOffset
-        dos.writeInt(0);        // ssndBlockSize
-
-        // Concat this with the audioStream and return it
-
-        dos.close();
-        header = baos.toByteArray();
-        headerStream = new ByteArrayInputStream( header );
-
-        aiffStream = new SequenceInputStream(headerStream,
-                            new NoCloseInputStream(codedAudioStream));
-
-        return aiffStream;
-
+        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             final DataOutputStream dos = new DataOutputStream(baos)) {
+            // Write the outer FORM chunk
+            dos.writeInt(AiffFileFormat.AIFF_MAGIC);
+            dos.writeInt((aiffLength - 8));
+            dos.writeInt(AiffFileFormat.AIFF_MAGIC2);
+            // Write a FVER chunk - only for AIFC
+            //dos.writeInt(FVER_MAGIC);
+            //dos.writeInt( (fverChunkSize-8) );
+            //dos.writeInt(FVER_TIMESTAMP);
+            // Write a COMM chunk
+            dos.writeInt(AiffFileFormat.COMM_MAGIC);
+            dos.writeInt((commChunkSize - 8));
+            dos.writeShort(channels);
+            dos.writeInt(numFrames);
+            dos.writeShort(sampleSize);
+            write_ieee_extended(dos, sampleFramesPerSecond);   // 10 bytes
+            //Only for AIFC
+            //dos.writeInt(compCode);
+            //dos.writeInt(compCode);
+            //dos.writeShort(0);
+            // Write the SSND chunk header
+            dos.writeInt(AiffFileFormat.SSND_MAGIC);
+            dos.writeInt((ssndChunkSize - 8));
+            // ssndOffset and ssndBlockSize set to 0 upon
+            // recommendation in "Sound Manager" chapter in
+            // "Inside Macintosh Sound", pp 2-87  (from Babu)
+            dos.writeInt(0);        // ssndOffset
+            dos.writeInt(0);        // ssndBlockSize
+            header = baos.toByteArray();
+        }
+        return new SequenceInputStream(new ByteArrayInputStream(header),
+                                       new NoCloseInputStream(codedAudioStream));
     }
 
     // HELPER METHODS
--- a/src/java.desktop/share/classes/com/sun/media/sound/AuFileWriter.java	Sat Dec 09 20:40:45 2017 -0800
+++ b/src/java.desktop/share/classes/com/sun/media/sound/AuFileWriter.java	Sun Dec 10 00:08:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -111,10 +111,11 @@
         AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream);
 
         // first write the file without worrying about length fields
-        FileOutputStream fos = new FileOutputStream( out );     // throws IOException
-        BufferedOutputStream bos = new BufferedOutputStream( fos, bisBufferSize );
-        int bytesWritten = writeAuFile(stream, auFileFormat, bos );
-        bos.close();
+        final int bytesWritten;
+        try (final FileOutputStream fos = new FileOutputStream(out);
+             final BufferedOutputStream bos = new BufferedOutputStream(fos)) {
+            bytesWritten = writeAuFile(stream, auFileFormat, bos);
+        }
 
         // now, if length fields were not specified, calculate them,
         // open as a random access file, write the appropriate fields,
@@ -123,14 +124,14 @@
 
             // $$kk: 10.22.99: jan: please either implement this or throw an exception!
             // $$fb: 2001-07-13: done. Fixes Bug 4479981
-            RandomAccessFile raf=new RandomAccessFile(out, "rw");
-            if (raf.length()<=0x7FFFFFFFl) {
-                // skip AU magic and data offset field
-                raf.skipBytes(8);
-                raf.writeInt(bytesWritten-AuFileFormat.AU_HEADERSIZE);
-                // that's all
+            try (final RandomAccessFile raf = new RandomAccessFile(out, "rw")) {
+                if (raf.length() <= 0x7FFFFFFFl) {
+                    // skip AU magic and data offset field
+                    raf.skipBytes(8);
+                    raf.writeInt(bytesWritten - AuFileFormat.AU_HEADERSIZE);
+                    // that's all
+                }
             }
-            raf.close();
         }
 
         return bytesWritten;
@@ -191,39 +192,29 @@
         int sampleRate     = (int)format.getSampleRate();
         int channels       = format.getChannels();
 
-        byte header[] = null;
-        ByteArrayInputStream headerStream = null;
-        ByteArrayOutputStream baos = null;
-        DataOutputStream dos = null;
-        SequenceInputStream auStream = null;
-
         // if we need to do any format conversion, we do it here.
         //$$ fb 2001-07-13: Bug 4391108
         audioStream = AudioSystem.getAudioInputStream(format, audioStream);
 
-        baos = new ByteArrayOutputStream();
-        dos = new DataOutputStream(baos);
-
-        dos.writeInt(AuFileFormat.AU_SUN_MAGIC);
-        dos.writeInt(headerSize);
-        dos.writeInt((int)dataSizeInBytes);
-        dos.writeInt(auType);
-        dos.writeInt(sampleRate);
-        dos.writeInt(channels);
-
+        final byte[] header;
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             DataOutputStream dos = new DataOutputStream(baos)) {
+            dos.writeInt(AuFileFormat.AU_SUN_MAGIC);
+            dos.writeInt(headerSize);
+            dos.writeInt((int) dataSizeInBytes);
+            dos.writeInt(auType);
+            dos.writeInt(sampleRate);
+            dos.writeInt(channels);
+            header = baos.toByteArray();
+        }
         // Now create a new InputStream from headerStream and the InputStream
         // in audioStream
-
-        dos.close();
-        header = baos.toByteArray();
-        headerStream = new ByteArrayInputStream( header );
-        auStream = new SequenceInputStream(headerStream,
-                        new NoCloseInputStream(audioStream));
-
-        return auStream;
+        return new SequenceInputStream(new ByteArrayInputStream(header),
+                                       new NoCloseInputStream(audioStream));
     }
 
-    private int writeAuFile(AudioInputStream in, AuFileFormat auFileFormat, OutputStream out) throws IOException {
+    private int writeAuFile(AudioInputStream in, AuFileFormat auFileFormat,
+                            OutputStream out) throws IOException {
 
         int bytesRead = 0;
         int bytesWritten = 0;
--- a/src/java.desktop/share/classes/com/sun/media/sound/WaveFileWriter.java	Sat Dec 09 20:40:45 2017 -0800
+++ b/src/java.desktop/share/classes/com/sun/media/sound/WaveFileWriter.java	Sun Dec 10 00:08:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -113,10 +113,11 @@
         WaveFileFormat waveFileFormat = (WaveFileFormat)getAudioFileFormat(fileType, stream);
 
         // first write the file without worrying about length fields
-        FileOutputStream fos = new FileOutputStream( out );     // throws IOException
-        BufferedOutputStream bos = new BufferedOutputStream( fos, bisBufferSize );
-        int bytesWritten = writeWaveFile(stream, waveFileFormat, bos );
-        bos.close();
+        final int bytesWritten;
+        try (final FileOutputStream fos = new FileOutputStream(out);
+             final BufferedOutputStream bos = new BufferedOutputStream(fos)) {
+            bytesWritten = writeWaveFile(stream, waveFileFormat, bos);
+        }
 
         // now, if length fields were not specified, calculate them,
         // open as a random access file, write the appropriate fields,
@@ -125,16 +126,16 @@
 
             int dataLength=bytesWritten-waveFileFormat.getHeaderSize();
             int riffLength=dataLength + waveFileFormat.getHeaderSize() - 8;
-
-            RandomAccessFile raf=new RandomAccessFile(out, "rw");
-            // skip RIFF magic
-            raf.skipBytes(4);
-            raf.writeInt(big2little( riffLength ));
-            // skip WAVE magic, fmt_ magic, fmt_ length, fmt_ chunk, data magic
-            raf.skipBytes(4+4+4+WaveFileFormat.getFmtChunkSize(waveFileFormat.getWaveType())+4);
-            raf.writeInt(big2little( dataLength ));
-            // that's all
-            raf.close();
+            try (final RandomAccessFile raf = new RandomAccessFile(out, "rw")) {
+                // skip RIFF magic
+                raf.skipBytes(4);
+                raf.writeInt(big2little(riffLength));
+                // skip WAVE magic, fmt_ magic, fmt_ length, fmt_ chunk, data magic
+                raf.skipBytes(4 + 4 + 4 + WaveFileFormat.getFmtChunkSize(
+                        waveFileFormat.getWaveType()) + 4);
+                raf.writeInt(big2little(dataLength));
+                // that's all
+            }
         }
 
         return bytesWritten;
@@ -262,12 +263,6 @@
         int length                         = waveFileFormat.getByteLength();
         int riffLength = dataLength + headerLength - 8;
 
-        byte header[] = null;
-        ByteArrayInputStream headerStream = null;
-        ByteArrayOutputStream baos = null;
-        DataOutputStream dos = null;
-        SequenceInputStream waveStream = null;
-
         AudioFormat audioStreamFormat = null;
         AudioFormat.Encoding encoding = null;
         InputStream codedAudioStream = audioStream;
@@ -314,37 +309,31 @@
 
 
         // Now push the header into a stream, concat, and return the new SequenceInputStream
-
-        baos = new ByteArrayOutputStream();
-        dos = new DataOutputStream(baos);
-
-        // we write in littleendian...
-        dos.writeInt(riffMagic);
-        dos.writeInt(big2little( riffLength ));
-        dos.writeInt(waveMagic);
-        dos.writeInt(fmtMagic);
-        dos.writeInt(big2little(fmtLength));
-        dos.writeShort(big2littleShort(wav_type));
-        dos.writeShort(big2littleShort(channels));
-        dos.writeInt(big2little(sampleRate));
-        dos.writeInt(big2little(avgBytesPerSec));
-        dos.writeShort(big2littleShort(blockAlign));
-        dos.writeShort(big2littleShort(sampleSizeInBits));
-        //$$fb 2002-04-16: Fix for 4636355: RIFF audio headers could be _more_ spec compliant
-        if (wav_type != WaveFileFormat.WAVE_FORMAT_PCM) {
-            // add length 0 for "codec specific data length"
-            dos.writeShort(0);
+        final byte[] header;
+        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             final DataOutputStream dos = new DataOutputStream(baos)) {
+            // we write in littleendian...
+            dos.writeInt(riffMagic);
+            dos.writeInt(big2little(riffLength));
+            dos.writeInt(waveMagic);
+            dos.writeInt(fmtMagic);
+            dos.writeInt(big2little(fmtLength));
+            dos.writeShort(big2littleShort(wav_type));
+            dos.writeShort(big2littleShort(channels));
+            dos.writeInt(big2little(sampleRate));
+            dos.writeInt(big2little(avgBytesPerSec));
+            dos.writeShort(big2littleShort(blockAlign));
+            dos.writeShort(big2littleShort(sampleSizeInBits));
+            //$$fb 2002-04-16: Fix for 4636355: RIFF audio headers could be _more_ spec compliant
+            if (wav_type != WaveFileFormat.WAVE_FORMAT_PCM) {
+                // add length 0 for "codec specific data length"
+                dos.writeShort(0);
+            }
+            dos.writeInt(dataMagic);
+            dos.writeInt(big2little(dataLength));
+            header = baos.toByteArray();
         }
-
-        dos.writeInt(dataMagic);
-        dos.writeInt(big2little(dataLength));
-
-        dos.close();
-        header = baos.toByteArray();
-        headerStream = new ByteArrayInputStream( header );
-        waveStream = new SequenceInputStream(headerStream,
-                            new NoCloseInputStream(codedAudioStream));
-
-        return waveStream;
+        return new SequenceInputStream(new ByteArrayInputStream(header),
+                                       new NoCloseInputStream(codedAudioStream));
     }
 }
--- a/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileWriter.java	Sat Dec 09 20:40:45 2017 -0800
+++ b/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileWriter.java	Sun Dec 10 00:08:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, 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
@@ -69,24 +69,23 @@
 
     public void write(AudioInputStream stream, RIFFWriter writer)
             throws IOException {
-
-        RIFFWriter fmt_chunk = writer.writeChunk("fmt ");
-
-        AudioFormat format = stream.getFormat();
-        fmt_chunk.writeUnsignedShort(3); // WAVE_FORMAT_IEEE_FLOAT
-        fmt_chunk.writeUnsignedShort(format.getChannels());
-        fmt_chunk.writeUnsignedInt((int) format.getSampleRate());
-        fmt_chunk.writeUnsignedInt(((int) format.getFrameRate())
-                * format.getFrameSize());
-        fmt_chunk.writeUnsignedShort(format.getFrameSize());
-        fmt_chunk.writeUnsignedShort(format.getSampleSizeInBits());
-        fmt_chunk.close();
-        RIFFWriter data_chunk = writer.writeChunk("data");
-        byte[] buff = new byte[1024];
-        int len;
-        while ((len = stream.read(buff, 0, buff.length)) != -1)
-            data_chunk.write(buff, 0, len);
-        data_chunk.close();
+        try (final RIFFWriter fmt_chunk = writer.writeChunk("fmt ")) {
+            AudioFormat format = stream.getFormat();
+            fmt_chunk.writeUnsignedShort(3); // WAVE_FORMAT_IEEE_FLOAT
+            fmt_chunk.writeUnsignedShort(format.getChannels());
+            fmt_chunk.writeUnsignedInt((int) format.getSampleRate());
+            fmt_chunk.writeUnsignedInt(((int) format.getFrameRate())
+                                               * format.getFrameSize());
+            fmt_chunk.writeUnsignedShort(format.getFrameSize());
+            fmt_chunk.writeUnsignedShort(format.getSampleSizeInBits());
+        }
+        try (RIFFWriter data_chunk = writer.writeChunk("data")) {
+            byte[] buff = new byte[1024];
+            int len;
+            while ((len = stream.read(buff, 0, buff.length)) != -1) {
+                data_chunk.write(buff, 0, len);
+            }
+        }
     }
 
     private static final class NoCloseOutputStream extends OutputStream {
@@ -136,11 +135,11 @@
         checkFormat(fileType, stream);
         if (stream.getFormat().isBigEndian())
             stream = toLittleEndian(stream);
-        RIFFWriter writer = new RIFFWriter(new NoCloseOutputStream(out), "WAVE");
-        write(stream, writer);
-        int fpointer = (int) writer.getFilePointer();
-        writer.close();
-        return fpointer;
+        try (final RIFFWriter writer = new RIFFWriter(
+                new NoCloseOutputStream(out), "WAVE")) {
+            write(stream, writer);
+            return (int) writer.getFilePointer();
+        }
     }
 
     @Override
@@ -153,10 +152,9 @@
         checkFormat(fileType, stream);
         if (stream.getFormat().isBigEndian())
             stream = toLittleEndian(stream);
-        RIFFWriter writer = new RIFFWriter(out, "WAVE");
-        write(stream, writer);
-        int fpointer = (int) writer.getFilePointer();
-        writer.close();
-        return fpointer;
+        try (final RIFFWriter writer = new RIFFWriter(out, "WAVE")) {
+            write(stream, writer);
+            return (int) writer.getFilePointer();
+        }
     }
 }
--- a/test/jdk/ProblemList.txt	Sat Dec 09 20:40:45 2017 -0800
+++ b/test/jdk/ProblemList.txt	Sun Dec 10 00:08:42 2017 -0800
@@ -273,8 +273,6 @@
 ############################################################################
 
 # jdk_sound
-javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java 8178401 windows-all
-
 javax/sound/sampled/DirectAudio/bug6372428.java                      8055097 generic-all
 javax/sound/sampled/Clip/bug5070081.java                             8055097 generic-all
 javax/sound/sampled/DataLine/LongFramePosition.java                  8055097 generic-all
--- a/test/jdk/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java	Sat Dec 09 20:40:45 2017 -0800
+++ b/test/jdk/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java	Sun Dec 10 00:08:42 2017 -0800
@@ -49,7 +49,7 @@
 
 /**
  * @test
- * @bug 8038139
+ * @bug 8038139 8178401
  */
 public final class FrameLengthAfterConversion {