Skip to content

Commit fe95394

Browse files
authored
fix(core): Fix MediaUtils parse path extension (#981)
## AgentScope-Java Version 1.0.11 ## Description * Closes: #977 * Fix MediaUtils parse path extension ## Checklist Please check the following items before code is ready to be reviewed. - [x] Code has been formatted with `mvn spotless:apply` - [x] All tests are passing (`mvn test`) - [x] Javadoc comments are complete and follow project conventions - [x] Related documentation has been updated (e.g. links, examples, etc.) - [x] Code is ready for review
1 parent fe28104 commit fe95394

2 files changed

Lines changed: 101 additions & 7 deletions

File tree

agentscope-core/src/main/java/io/agentscope/core/formatter/MediaUtils.java

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.nio.file.Files;
2828
import java.nio.file.InvalidPathException;
2929
import java.nio.file.Path;
30+
import java.nio.file.Paths;
3031
import java.util.Base64;
3132
import java.util.List;
3233
import javax.imageio.ImageIO;
@@ -58,7 +59,7 @@ private MediaUtils() {
5859

5960
/**
6061
* Check if a URL is a local file path (not a URL with protocol scheme).
61-
* Returns true for paths without http://, https://, ftp://, or file:// prefixes.
62+
* Returns true for paths without http://, https://, ftp://, file:// or oss:// prefixes.
6263
* Used to distinguish local files from remote URLs for different processing paths.
6364
*
6465
* @param url The URL or file path to check
@@ -349,14 +350,34 @@ public static String inferAudioFormatFromMediaType(String mediaType) {
349350
* Extract file extension from path or URL.
350351
*/
351352
public static String getExtension(String path) {
352-
if (path == null) {
353+
if (path == null || path.isBlank()) {
353354
return "";
354355
}
355-
int dotIndex = path.lastIndexOf('.');
356-
int slashIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
357-
// Ensure the dot is after the last slash (not part of directory name)
358-
if (dotIndex > slashIndex && dotIndex < path.length() - 1) {
359-
return path.substring(dotIndex + 1);
356+
357+
Path fileNamePath;
358+
try {
359+
if (isLocalFile(path)) {
360+
// treat as file
361+
fileNamePath = Paths.get(path).normalize().getFileName();
362+
} else {
363+
// treat as url
364+
URI uri = URI.create(path).normalize();
365+
fileNamePath = Paths.get(uri.getPath()).getFileName();
366+
}
367+
} catch (Exception e) {
368+
log.warn("Invalid path: {}", path, e);
369+
return "";
370+
}
371+
372+
if (fileNamePath == null) {
373+
return "";
374+
}
375+
376+
String fileName = fileNamePath.toString();
377+
int dotIndex = fileName.lastIndexOf('.');
378+
// Ensure the dot exists and is not the last character
379+
if (dotIndex != -1 && dotIndex < fileName.length() - 1) {
380+
return fileName.substring(dotIndex + 1);
360381
}
361382
return "";
362383
}

agentscope-core/src/test/java/io/agentscope/core/formatter/MediaUtilsTest.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,4 +329,77 @@ void testUrlToRgbaImageInputStreamWithFile() throws IOException {
329329
assertNotNull(is);
330330
is.close();
331331
}
332+
333+
@Test
334+
@DisplayName("Should return empty string when path is invalid")
335+
void testGetExtensionWithInvalidPath() {
336+
assertEquals("", MediaUtils.getExtension(null));
337+
assertEquals("", MediaUtils.getExtension(""));
338+
assertEquals("", MediaUtils.getExtension(" "));
339+
assertEquals("", MediaUtils.getExtension("/"));
340+
assertEquals("", MediaUtils.getExtension("\\"));
341+
assertEquals("", MediaUtils.getExtension("/home/user"));
342+
assertEquals("", MediaUtils.getExtension("C:\\Users\\Administrator"));
343+
assertEquals("", MediaUtils.getExtension("https://abc"));
344+
assertEquals("", MediaUtils.getExtension("https://abc[@]123"));
345+
assertEquals("", MediaUtils.getExtension("https://example.com/abc"));
346+
assertEquals("", MediaUtils.getExtension("https://example.com/abc/"));
347+
assertEquals("", MediaUtils.getExtension("https://example.com/img.png."));
348+
}
349+
350+
@Test
351+
@DisplayName("Should get extension with all types")
352+
void testGetExtensionWithAllTypes() {
353+
assertEquals("png", MediaUtils.getExtension("https://example.com/img.png"));
354+
assertEquals("wav", MediaUtils.getExtension("https://example.com/audio.wav"));
355+
assertEquals("mp3", MediaUtils.getExtension("https://example.com/audio.mp3"));
356+
assertEquals("mp4", MediaUtils.getExtension("https://example.com/video.mp4"));
357+
assertEquals("xxx", MediaUtils.getExtension("https://example.com/xxx.xxx"));
358+
}
359+
360+
@Test
361+
@DisplayName("Should get last extension when have nested types")
362+
void testGetExtensionWithNestedTypes() {
363+
assertEquals("gz", MediaUtils.getExtension("https://example.com/img.png.tar.gz"));
364+
assertEquals("zip", MediaUtils.getExtension("https://example.com/img.png.zip"));
365+
}
366+
367+
@Test
368+
@DisplayName("Should get extension with masks")
369+
void testGetExtensionWithMasks() {
370+
assertEquals("png", MediaUtils.getExtension("https://example.com/img.png?id=1&type=png"));
371+
assertEquals("png", MediaUtils.getExtension("https://example.com/img.png#section1.1"));
372+
assertEquals(
373+
"png",
374+
MediaUtils.getExtension("https://example.com/img.png?id=1&type=png#section1.1"));
375+
assertEquals("png", MediaUtils.getExtension("https://example.com/img.png?v=2.0.0"));
376+
assertEquals(
377+
"png", MediaUtils.getExtension("https://example.com/img-123&type=png&v=2.0.0.png"));
378+
379+
// verify the file name include special masks
380+
assertEquals("png", MediaUtils.getExtension("/home/user/img-123&type=png&v=2.0.0.png"));
381+
assertEquals(
382+
"png",
383+
MediaUtils.getExtension("C:\\Users\\Administrator\\img_123&type=png&v=2.0.0.png"));
384+
}
385+
386+
@Test
387+
@DisplayName("Should get extension with all supported protocol")
388+
void testGetExtensionWithSupportedProtocol() {
389+
assertEquals(
390+
"png",
391+
MediaUtils.getExtension("http://example.com/img.png?id=1&type=png#section1.1"));
392+
assertEquals(
393+
"png",
394+
MediaUtils.getExtension("https://example.com/img.png?id=1&type=png#section1.1"));
395+
assertEquals(
396+
"png",
397+
MediaUtils.getExtension("oss://example.com/img.png?id=1&type=png#section1.1"));
398+
assertEquals(
399+
"png",
400+
MediaUtils.getExtension("file://example.com/img.png?id=1&type=png#section1.1"));
401+
assertEquals(
402+
"png",
403+
MediaUtils.getExtension("ftp://example.com/img.png?id=1&type=png#section1.1"));
404+
}
332405
}

0 commit comments

Comments
 (0)