diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/GhidraSourceBundle.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/GhidraSourceBundle.java index 241135958a..68f8c51ac7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/GhidraSourceBundle.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/GhidraSourceBundle.java @@ -47,6 +47,7 @@ import generic.io.NullPrintWriter; import generic.jar.ResourceFile; import ghidra.app.script.*; import ghidra.util.Msg; +import utilities.util.FileUtilities; /** * {@link GhidraSourceBundle} represents a Java source directory that is compiled on build to an OSGi bundle. @@ -173,20 +174,18 @@ public class GhidraSourceBundle extends GhidraBundle { * * @param sourceFile a source file from this bundle * @return the class name + * @throws ClassNotFoundException if {@code sourceFile} isn't contained in this bundle */ - public String classNameForScript(ResourceFile sourceFile) { - try { - String path = sourceFile.getCanonicalPath(); - - // get the relative path and chop ".java" from the end - path = path.substring(1 + getSourceDirectory().getCanonicalPath().length(), - path.length() - 5); - return path.replace(File.separatorChar, '.'); - } - catch (IOException e) { - Msg.error(this, "getting class name for script", e); - return null; + public String classNameForScript(ResourceFile sourceFile) throws ClassNotFoundException { + String relativePath = FileUtilities.relativizePath(getSourceDirectory(), sourceFile); + if (relativePath == null) { + throw new ClassNotFoundException( + String.format("Failed to find script file '%s' in source directory '%s'", + sourceFile, getSourceDirectory())); } + // chop ".java" from the end + relativePath = relativePath.substring(0, relativePath.length() - 5); + return relativePath.replace(File.separatorChar, '.'); } void clearBuildErrors(ResourceFile sourceFile) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScriptUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScriptUtil.java index e386c800d9..6099eceeef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScriptUtil.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/script/GhidraScriptUtil.java @@ -32,6 +32,7 @@ import ghidra.app.util.headless.HeadlessAnalyzer; import ghidra.framework.Application; import ghidra.util.Msg; import ghidra.util.classfinder.ClassSearcher; +import utilities.util.FileUtilities; /** * A utility class for managing script directories and ScriptInfo objects. @@ -129,19 +130,13 @@ public class GhidraScriptUtil { * @return the source directory if found, or null if not */ public static ResourceFile findSourceDirectoryContaining(ResourceFile sourceFile) { - String sourcePath; - try { - sourcePath = sourceFile.getCanonicalPath(); - for (ResourceFile sourceDir : getScriptSourceDirectories()) { - if (sourcePath.startsWith(sourceDir.getCanonicalPath() + File.separatorChar)) { - return sourceDir; - } + for (ResourceFile sourceDir : getScriptSourceDirectories()) { + if (FileUtilities.relativizePath(sourceDir, sourceFile) != null) { + return sourceDir; } } - catch (IOException e) { - Msg.error(GhidraScriptUtil.class, - "Failed to find script in any script directory: " + sourceFile.toString(), e); - } + Msg.error(GhidraScriptUtil.class, + "Failed to find script in any script directory: " + sourceFile.toString()); return null; } diff --git a/Ghidra/Framework/Generic/src/test/java/utilities/util/FileUtilitiesTest.java b/Ghidra/Framework/Generic/src/test/java/utilities/util/FileUtilitiesTest.java index 1b428d42c3..142c6b4ca6 100644 --- a/Ghidra/Framework/Generic/src/test/java/utilities/util/FileUtilitiesTest.java +++ b/Ghidra/Framework/Generic/src/test/java/utilities/util/FileUtilitiesTest.java @@ -140,6 +140,38 @@ public class FileUtilitiesTest { assertNull(relative); } + @Test + public void testRelativizePath_ResourceFiles() { + ResourceFile f1 = new ResourceFile(new File("/a/b")); + ResourceFile f2 = new ResourceFile(new File("/a/b/c")); + String relative = FileUtilities.relativizePath(f1, f2); + assertEquals("c", relative); + } + + @Test + public void testRelativizePath_ResourceFiles2() { + ResourceFile f1 = new ResourceFile(new File("/a/b")); + ResourceFile f2 = new ResourceFile(new File("/a/b/c/d")); + String relative = FileUtilities.relativizePath(f1, f2); + assertEquals("c/d", relative); + } + + @Test + public void testRelativizePath_ResourceFiles_NotRelated() { + ResourceFile f1 = new ResourceFile(new File("/a/b")); + ResourceFile f2 = new ResourceFile(new File("/c/d")); + String relative = FileUtilities.relativizePath(f1, f2); + assertNull(relative); + } + + @Test + public void testRelativizePath_ResourceFiles_Same() { + ResourceFile f1 = new ResourceFile(new File("/a/b")); + ResourceFile f2 = new ResourceFile(new File("/a/b")); + String relative = FileUtilities.relativizePath(f1, f2); + assertNull(relative); + } + private ResourceFile createNestedTempFile(String path) throws Exception { String tmpdir = AbstractGenericTest.getTestDirectoryPath(); diff --git a/Ghidra/Framework/Utility/src/main/java/utilities/util/FileUtilities.java b/Ghidra/Framework/Utility/src/main/java/utilities/util/FileUtilities.java index 02ad63ab1a..2d3ada122d 100644 --- a/Ghidra/Framework/Utility/src/main/java/utilities/util/FileUtilities.java +++ b/Ghidra/Framework/Utility/src/main/java/utilities/util/FileUtilities.java @@ -902,6 +902,32 @@ public final class FileUtilities { return childPath; } + /** + * Return the relative path string of one resource file in another. If + * no path can be constructed or the files are the same, then null is returned. + * + * Note: unlike {@link #relativizePath(File, File)}, this function does not resolve symbolic links. + * + *

For example, given, in this order, two files with these paths + * /a/b and /a/b/c, this method will return 'c'. + * + * @param f1 the parent resource file + * @param f2 the child resource file + * @return the relative path of {@code f2} in {@code f1} + */ + public static String relativizePath(ResourceFile f1, ResourceFile f2) { + StringBuilder sb = new StringBuilder(f2.getName()); + f2 = f2.getParentFile(); + while (f2 != null) { + if (f1.equals(f2)) { + return sb.toString(); + } + sb.insert(0, f2.getName() + File.separator); + f2 = f2.getParentFile(); + } + return null; + } + public static boolean exists(URI uri) { String scheme = uri.getScheme();