seppuku/src/main/java/me/rigamortis/seppuku/api/util/ResourceUtil.java

114 lines
4.7 KiB
Java

package me.rigamortis.seppuku.api.util;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public final class ResourceUtil {
// thanks to the guy who made this helper method. source:
// http://www.uofr.net/~greg/java/get-resource-listing.html
// modified to keep the trailing slash in directories so you can
// differentiate between directories and files, to support paths with a
// leading slash, to always return absolute paths, to optionally recurse and
// to return a set.
// note that this is kinda expensive for jar files since it lists ALL the
// resources and then filters them, so, if you need recursion, set recurse
// to true instead of doing it yourself or you will slow everything down
/**
* List directory contents for a resource folder.
* This is basically a brute-force implementation.
* Works for regular files and also JARs.
*
* @param clazz Any java class that lives in the same place as the resources you want.
* @param path Should end with "/".
* @return The full path of each member item. Directories have a trailing slash.
* @throws URISyntaxException
* @throws IOException
* @author Greg Briggs
*/
public static Set<String> getResourceListing(Class clazz, String path, boolean recurse) throws URISyntaxException, IOException {
String classPath = clazz.getName().replace(".", "/");
URL dirURL = clazz.getClassLoader().getResource(path);
if (dirURL != null && dirURL.getProtocol().equals("file")) {
/* A file path: ~~easy enough~~ not so easy for recursion */
int lastSlash = classPath.lastIndexOf('/');
if (lastSlash != -1) {
path = "/" + classPath.substring(0, lastSlash + 1) + path;
} else {
path = "/" + path;
}
return listFiles(new HashSet<String>(), new File(dirURL.toURI()), path, recurse);
}
if (dirURL == null) {
/*
* In case of a jar file, we can't actually find a directory.
* Have to assume the same jar as clazz.
*/
String me = classPath + ".class";
dirURL = clazz.getClassLoader().getResource(me);
// make absolute path from class' package if path doesnt have a leading slash, else, remove leading slash so patterns match
if (path.startsWith("/")) {
path = path.substring(1);
} else {
int lastSlash = classPath.lastIndexOf('/');
if (lastSlash != -1) {
path = classPath.substring(0, lastSlash + 1) + path;
}
}
}
if (dirURL.getProtocol().equals("jar")) {
/* A JAR path */
String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!")); //strip out only the JAR file
JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
Set<String> result = new HashSet<String>(); //avoid duplicates in case it is a subdirectory
while (entries.hasMoreElements()) {
String name = entries.nextElement().getName();
if (name.startsWith(path) && !name.equals(path)) { //filter according to the path and ignore entry if it's the input path
// ignore part after next slash so that only subdirectories are kept instead of children of subdirectories (if not recursing)
if (!recurse) {
int nextSlash = name.indexOf('/', path.length());
if (nextSlash != -1) {
name = name.substring(0, nextSlash + 1);
}
}
result.add("/" + name);
}
}
return result;
}
throw new UnsupportedOperationException("Cannot list files for URL " + dirURL);
}
private static HashSet<String> listFiles(HashSet<String> output, File dir, String prefix, boolean recurse) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
String name = prefix + file.getName() + "/";
output.add(name);
if (recurse) {
listFiles(output, file, name, true);
}
} else {
output.add(prefix + file.getName());
}
}
return output;
}
}