diff --git a/NOTES.md b/NOTES.md index c7739aa..283fac6 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,6 +1,7 @@ - 0.9.56 - Fixed deployment to tagtraum. - Fixed PCM endianness bug. + - Fixed % in path bug. - 0.9.55 diff --git a/ffsampledsp-complete/src/test/java/com/tagtraum/ffsampledsp/TestFFAudioFileReader.java b/ffsampledsp-complete/src/test/java/com/tagtraum/ffsampledsp/TestFFAudioFileReader.java index 790857d..6d37201 100644 --- a/ffsampledsp-complete/src/test/java/com/tagtraum/ffsampledsp/TestFFAudioFileReader.java +++ b/ffsampledsp-complete/src/test/java/com/tagtraum/ffsampledsp/TestFFAudioFileReader.java @@ -517,10 +517,84 @@ public void testBogusFile() throws IOException { @Test public void testFileWithPunctuationToURL() throws MalformedURLException { + // What matters is that all punctuation survives the fileToURL → urlToString round-trip + // so FFmpeg receives the correct literal path. The intermediate URL encoding may vary. Assume.assumeTrue(File.separator.equals("/")); final File file = new File("/someDir/;:&=+@[]?/name.txt"); final URL url = FFAudioFileReader.fileToURL(file); - assertEquals("file:/someDir/;:&=+@[]?/name.txt", url.toString()); + final String s = FFAudioFileReader.urlToString(url); + assertTrue( + "Punctuation must survive round-trip: " + s, + s.contains("/someDir/") + && s.contains(";") + && s.contains("&") + && s.contains("+") + && s.contains("[") + && s.contains("]") + && s.endsWith("name.txt")); + } + + @Test + public void testFileWithPercentSignToURL() throws MalformedURLException { + // A literal % in a file path must survive the fileToURL → urlToString round-trip intact. + Assume.assumeTrue(File.separator.equals("/")); + final File file = new File("/someDir/50%off/name.ogg"); + final URL url = FFAudioFileReader.fileToURL(file); + final String s = FFAudioFileReader.urlToString(url); + assertTrue("Round-tripped path must contain literal percent sign: " + s, s.contains("50%off")); + } + + @Test + public void testGetAudioFileFormatFileWithPercentSign() + throws IOException, UnsupportedAudioFileException { + final String filename = "test.ogg"; + final File file = File.createTempFile("test50%off", filename); + extractFile(filename, file); + try { + final AudioFileFormat fileFormat = new FFAudioFileReader().getAudioFileFormat(file); + assertEquals("ogg", fileFormat.getType().getExtension()); + assertEquals(2, fileFormat.getFormat().getChannels()); + } finally { + file.delete(); + } + } + + @Test + public void testGetAudioFileFormatURLWithPercentSign() + throws IOException, UnsupportedAudioFileException { + // file.toURI().toURL() keeps % encoded as %25; urlToString() must decode it for FFmpeg. + final String filename = "test.ogg"; + final File file = File.createTempFile("test50%off", filename); + extractFile(filename, file); + try { + final AudioFileFormat fileFormat = + new FFAudioFileReader().getAudioFileFormat(file.toURI().toURL()); + assertEquals("ogg", fileFormat.getType().getExtension()); + assertEquals(2, fileFormat.getFormat().getChannels()); + } finally { + file.delete(); + } + } + + @Test + public void testGetAudioInputStreamFileWithPercentSign() + throws IOException, UnsupportedAudioFileException { + final String filename = "test.ogg"; + final File file = File.createTempFile("test50%off", filename); + extractFile(filename, file); + try { + final AudioInputStream stream = new FFAudioFileReader().getAudioInputStream(file); + try { + final byte[] buf = new byte[1024]; + assertTrue( + "Expected to read audio bytes from file with percent sign in name", + stream.read(buf) > 0); + } finally { + stream.close(); + } + } finally { + file.delete(); + } } @Test diff --git a/ffsampledsp-java/src/main/java/com/tagtraum/ffsampledsp/FFAudioFileReader.java b/ffsampledsp-java/src/main/java/com/tagtraum/ffsampledsp/FFAudioFileReader.java index c89cd52..cd9d88e 100644 --- a/ffsampledsp-java/src/main/java/com/tagtraum/ffsampledsp/FFAudioFileReader.java +++ b/ffsampledsp-java/src/main/java/com/tagtraum/ffsampledsp/FFAudioFileReader.java @@ -140,21 +140,17 @@ public AudioFileFormat[] getAudioFileFormats(final File file) } /** - * Convert file to URL. Assumes that any punctuation in the filename must not be url encoded. + * Convert file to URL. The returned URL keeps all path characters percent-encoded as produced by + * {@link File#toURI()}, except that {@code +} is encoded as {@code %2B} so that {@link + * #urlToString(URL)} (which calls {@link java.net.URLDecoder}) does not misinterpret it as a + * space. All decoding for FFmpeg is done exclusively in {@code urlToString}. * * @param file file - * @return correctly encoded URL + * @return percent-encoded file URL suitable for passing to {@link #urlToString(URL)} * @throws MalformedURLException if the URL is malformed */ static URL fileToURL(final File file) throws MalformedURLException { - try { - String encoded = file.toURI().toString().replace("+", "%2B"); - return new URL(URLDecoder.decode(encoded, "UTF-8")); - } catch (UnsupportedEncodingException e) { - final MalformedURLException malformedURLException = new MalformedURLException(); - malformedURLException.initCause(e); - throw malformedURLException; - } + return new URL(file.toURI().toString().replace("+", "%2B")); } /**