diff --git a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/layzip/LayeredZipFileSystemProvider.java b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/layzip/LayeredZipFileSystemProvider.java index a83be09..12120ef 100644 --- a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/layzip/LayeredZipFileSystemProvider.java +++ b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/layzip/LayeredZipFileSystemProvider.java @@ -19,28 +19,23 @@ import java.util.Map; import java.util.Optional; -public class LayeredZipFileSystemProvider extends PathFileSystemProvider -{ +public class LayeredZipFileSystemProvider extends PathFileSystemProvider { public static final String SCHEME = "jij"; public static final String URI_SPLIT_REGEX = COMPONENT_SEPERATOR; - @Override - public String getScheme() - { + public String getScheme() { return SCHEME; } @Override - public FileSystem newFileSystem(final URI uri, final Map env) throws IOException - { + public FileSystem newFileSystem(final URI uri, final Map env) throws IOException { final String[] sections = uri.getRawSchemeSpecificPart().split(URI_SPLIT_REGEX); FileSystem workingSystem = FileSystems.getDefault(); //Grab the normal disk FS. String keyPrefix = ""; - if (sections.length > 1) - { + if (sections.length > 1) { final AdaptedURIWithPrefixSelection adaptedURI = adaptUriSections(sections); keyPrefix = adaptedURI.getPrefix(); workingSystem = adaptedURI.getFileSystem(); @@ -50,17 +45,11 @@ public FileSystem newFileSystem(final URI uri, final Map env) throws if (lastSection.startsWith("//")) lastSection = lastSection.substring(2); - if (env.containsKey("packagePath")) - { //User requests specific package as a target; - try - { - return super.newFileSystem(new URI(super.getScheme() + ":" + uri.getRawSchemeSpecificPart()), - env); - } catch (Exception e) - { - throw new UncheckedIOException("Failed to create intermediary FS.", new IOException("Failed to " + - "process data.", - e)); + if (env.containsKey("packagePath")) { //User requests specific package as a target; + try { + return super.newFileSystem(new URI(super.getScheme() + ":" + uri.getRawSchemeSpecificPart()), env); + } catch (Exception e) { + throw new UncheckedIOException("Failed to create intermediary FS.", new IOException("Failed to process data.", e)); } } @@ -68,8 +57,7 @@ public FileSystem newFileSystem(final URI uri, final Map env) throws return getOrCreateNewSystem(keyPrefix, lastPath); } - private String handleAbsolutePrefixOnWindows(final FileSystem workingSystem, String section) - { + private String handleAbsolutePrefixOnWindows(final FileSystem workingSystem, String section) { if (workingSystem.getClass().getName().toLowerCase(Locale.ROOT).contains("windows")) { //This special casing is needed, since else the rooted paths crash on Windows system because: @@ -83,24 +71,19 @@ private String handleAbsolutePrefixOnWindows(final FileSystem workingSystem, Str return section; } - private FileSystem getOrCreateNewSystem(final Path path) - { + private FileSystem getOrCreateNewSystem(Path path) { return getOrCreateNewSystem("", path); } - private FileSystem getOrCreateNewSystem(String keyPrefix, final Path path) - { + private FileSystem getOrCreateNewSystem(String keyPrefix, Path path) { final Map args = new HashMap<>(); args.put("packagePath", path.toAbsolutePath()); - try - { - return super.newFileSystem(new URI(super.getScheme() + ":" + keyPrefix + path.toString() - .replace("\\", "/")), args); - } catch (Exception e) - { - throw new UncheckedIOException("Failed to create intermediary FS.", new IOException("Failed to process " + - "data.", e)); + try { + URI uri = new URI(super.getScheme() + ':' + keyPrefix + path.toUri().toString().replace('\\', '/')); + return super.newFileSystem(uri, args); + } catch (Exception e) { + throw new UncheckedIOException("Failed to create intermediary FS.", new IOException("Failed to process data.", e)); } } @@ -210,8 +193,8 @@ private AdaptedURIWithPrefixSelection adaptUriSections(final String[] sections) //First try a reverse lookup of a key based approach: final Optional rootKnownCandidateSystem = super.getFileSystemFromKey(sections[0]); if (rootKnownCandidateSystem.isPresent()) { - //Okey special case: We have a file system in the root that is known to us. - //We will recursively resolve this untill we have handled all sections: + //Okay special case: We have a file system in the root that is known to us. + //We will recursively resolve this until we have handled all sections: //First deal with the case that we do not have any other paths: if (sections.length == 1) { return new AdaptedURIWithPrefixSelection(rootKnownCandidateSystem.get(), sections[0]); @@ -254,19 +237,16 @@ private final class AdaptedURIWithPrefixSelection { private final String prefix; private final FileSystem fileSystem; - private AdaptedURIWithPrefixSelection(final FileSystem fileSystem, final String prefix) - { + private AdaptedURIWithPrefixSelection(final FileSystem fileSystem, final String prefix) { this.prefix = prefix; this.fileSystem = fileSystem; } - public String getPrefix() - { + public String getPrefix() { return prefix; } - public FileSystem getFileSystem() - { + public FileSystem getFileSystem() { return fileSystem; } } diff --git a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFSUtils.java b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFSUtils.java index d53b171..ed4d1b9 100644 --- a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFSUtils.java +++ b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFSUtils.java @@ -10,59 +10,46 @@ import java.util.Iterator; import java.util.function.Function; -class PathFSUtils -{ - - private PathFSUtils() - { +class PathFSUtils { + private PathFSUtils() { throw new IllegalStateException("Can not instantiate an instance of: PathFSUtils. This is a utility class"); } - public static final DirectoryStream NULL_STREAM = new DirectoryStream() - { + public static final DirectoryStream NULL_STREAM = new DirectoryStream() { @Override - public Iterator iterator() - { - return new Iterator() - { + public Iterator iterator() { + return new Iterator() { @Override - public boolean hasNext() - { + public boolean hasNext() { return false; } @Override - public Path next() - { + public Path next() { return null; } }; } @Override - public void close() throws IOException - { - + public void close() throws IOException { } }; public static DirectoryStream adapt(final DirectoryStream inner, final Function adapter) { return new DirectoryStream() { @Override - public Iterator iterator() - { + public Iterator iterator() { final Iterator targetIterator = inner.iterator(); return new Iterator() { @Override - public boolean hasNext() - { + public boolean hasNext() { return targetIterator.hasNext(); } @Override - public Path next() - { + public Path next() { final Path targetPath = targetIterator.next(); return adapter.apply(targetPath); } @@ -70,8 +57,7 @@ public Path next() } @Override - public void close() throws IOException - { + public void close() throws IOException { inner.close(); } }; diff --git a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystem.java b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystem.java index 7d158a5..ff6baee 100644 --- a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystem.java +++ b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystem.java @@ -19,130 +19,105 @@ import java.util.List; import java.util.Set; -public class PathFileSystem extends FileSystem -{ - private final Path root = new PathPath(this, false, PathPath.ROOT).toAbsolutePath(); +public class PathFileSystem extends FileSystem { + private final Path root = new PathPath(this, false, PathPath.ROOT).toAbsolutePath(); private final PathFileSystemProvider provider; private final String key; - private final Path target; - private final Lazy innerSystem; private final Lazy innerFSTarget; - public PathFileSystem(final PathFileSystemProvider provider, final String key, final Path target) - { + PathFileSystem(PathFileSystemProvider provider, String key, Path target) { this.provider = provider; this.key = key; this.target = target; this.innerSystem = Lazy.of(() -> { - try - { + try { return FileSystems.newFileSystem(target, this.getClass().getClassLoader()); - } - catch (Exception e) - { - return target.getFileSystem(); + } catch (IOException e) { + return sneak(e); + //return target.getFileSystem(); } }); this.innerFSTarget = this.innerSystem.map(fileSystem -> { + if (fileSystem == target.getFileSystem()) + return target; + //We need to process the new FS root directories. //We do this since creating an FS from a zip file changes the root to which we need to make our inner paths relative. - final List possibleRootDirectories = new ArrayList<>(); - fileSystem.getRootDirectories().forEach(possibleRootDirectories::add); - - if (!possibleRootDirectories.isEmpty()) { - for (final Path possibleRootDirectory : possibleRootDirectories) - { - if (possibleRootDirectory.getClass() != target.getClass()) { - return possibleRootDirectory; - } - } - } + final List roots = new ArrayList<>(); + fileSystem.getRootDirectories().forEach(roots::add); + + if (roots.size() != 1) + throw new UnsupportedOperationException("Invalid PathFileSystem, Multiple roots: " + target.toUri()); - return target; + return roots.get(0); }); } - public String getKey() - { + public String getKey() { return this.key; } - public Path getRoot() - { + public Path getRoot() { return root; } @Override - public PathFileSystemProvider provider() - { + public PathFileSystemProvider provider() { return provider; } @Override - public void close() - { + public void close() { innerSystem.ifPresent(LambdaExceptionUtils.uncheckConsume(FileSystem::close)); provider().removeFileSystem(this); } @Override - public boolean isOpen() - { + public boolean isOpen() { return innerSystem.map(FileSystem::isOpen).orElse(true); } @Override - public boolean isReadOnly() - { + public boolean isReadOnly() { return true; } - public A readAttributes(final Path path, final Class type, final LinkOption... options) throws IOException - { - if (path.toAbsolutePath().equals(root)) { + public A readAttributes(Path path, Class type, LinkOption... options) throws IOException { + if (path.toAbsolutePath().equals(root)) return Files.readAttributes(this.target, type, options); - } return innerSystem.get().provider().readAttributes(getOuterTarget(path), type, options); } @Override - public String getSeparator() - { + public String getSeparator() { return "/"; } @Override - public Iterable getRootDirectories() - { + public Iterable getRootDirectories() { return Collections.singletonList(root); } @Override - public Iterable getFileStores() - { + public Iterable getFileStores() { return Collections.emptyList(); } @Override - public Set supportedFileAttributeViews() - { + public Set supportedFileAttributeViews() { return Collections.singleton("basic"); } - public SeekableByteChannel newByteChannel(final Path path, final Set options, final FileAttribute... attrs) throws IOException - { + public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) throws IOException { if (path.toAbsolutePath().equals(root)) { - try - { + try { return Files.newByteChannel(this.target, options, attrs); - } - catch (UncheckedIOException ioe) - { + } catch (UncheckedIOException ioe) { throw ioe.getCause(); } } @@ -150,20 +125,17 @@ public SeekableByteChannel newByteChannel(final Path path, final Set innerTarget.resolve(finalPath.toString())).get(); + Path innerRoot = this.innerFSTarget.get(); + return innerRoot.resolve(path.toString()); } @Override - public Path getPath(final String first, final String... more) - { - if (more.length > 0) - { + public Path getPath(String first, String... more) { + if (more.length > 0) { final String[] args = new String[more.length + 1]; args[0] = first; System.arraycopy(more, 0, args, 1, more.length); @@ -174,58 +146,52 @@ public Path getPath(final String first, final String... more) } @Override - public PathMatcher getPathMatcher(final String syntaxAndPattern) - { + public PathMatcher getPathMatcher(String syntaxAndPattern) { throw new UnsupportedOperationException(); } @Override - public UserPrincipalLookupService getUserPrincipalLookupService() - { + public UserPrincipalLookupService getUserPrincipalLookupService() { throw new UnsupportedOperationException(); } @Override - public WatchService newWatchService() - { + public WatchService newWatchService() { throw new UnsupportedOperationException(); } - public DirectoryStream newDirectoryStream(final Path dir, final DirectoryStream.Filter filter) - { + public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) { if (dir.toAbsolutePath().equals(root)) { - try - { + try { return PathFSUtils.adapt( - Files.newDirectoryStream(this.innerFSTarget.get(), filter), - path -> new PathPath(this, this.innerFSTarget.get().relativize(path)) + Files.newDirectoryStream(this.innerFSTarget.get(), filter), + path -> new PathPath(this, this.innerFSTarget.get().relativize(path)) ); - } - catch (IOException e) - { + } catch (IOException e) { return PathFSUtils.NULL_STREAM; } } - try - { + try { return PathFSUtils.adapt( this.innerSystem.get().provider().newDirectoryStream(getOuterTarget(dir), filter), path -> new PathPath(this, target.relativize(path)) ); - } - catch (IOException e) - { + } catch (IOException e) { return PathFSUtils.NULL_STREAM; } } - public Path getTarget() - { + public Path getTarget() { return target; } public void checkAccess(Path path, AccessMode... modes) throws IOException { innerSystem.get().provider().checkAccess(getOuterTarget(path), modes); } + + @SuppressWarnings("unchecked") + private static R sneak(Exception exception) throws E { + throw (E)exception; + } } diff --git a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystemProvider.java b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystemProvider.java index d9ce531..c015d09 100644 --- a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystemProvider.java +++ b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathFileSystemProvider.java @@ -34,7 +34,7 @@ public String getScheme() { /** * Invoked by FileSystems.newFileSystem, Only returns a value if env contains an entry with the name of - * "package" and Path targeting the file in question. + * "packagePath" and Path targeting the file in question. * If not specified, throws IllegalArgumentException * If uri.getScheme() is not "path" throws IllegalArgumentException * If you wish to create a PathFileSystem explicitly, invoke newFileSystem(Path) @@ -61,10 +61,9 @@ public FileSystem newFileSystem(final URI uri, final Map env) throws /** * Invoked by FileSystems.newFileSystem, Only returns a value if env contains an entry with the name of - * "package" and Path targeting the file in question. + * "packagePath" and Path targeting the file in question. * If none specified, throws UnsupportedOperationException instead of IllegalArgumentException * so that FileSystems.newFileSystem will search for the next provider. - * If you wish to create a UnionFileSystem explicitly, invoke newFileSystem(BiPredicate, Path...) */ @Override public FileSystem newFileSystem(final Path path, final Map env) throws IOException { @@ -112,31 +111,50 @@ private String makeKey(Path path) { return path.getFileName().toString(); } + private static class URIComponents { + String owner; + String path; + + URIComponents(String owner, String path) { + this.owner = owner; + this.path = path; + } + } + + private URIComponents parse(URI uri) { + String key = makeKey(uri); + int idx = key.lastIndexOf(COMPONENT_SEPERATOR); + if (idx == -1) + return new URIComponents(key, null); + String owner = key.substring(0, idx); + String path = key.substring(idx + 1); + return new URIComponents(owner, path); + } + + @Override public Path getPath(final URI uri) { - final String[] parts = uri.getRawSchemeSpecificPart().split(COMPONENT_SEPERATOR); - if (parts.length > 1) { - return getFileSystem(uri).getPath(parts[1]); - } else { + URIComponents parts = parse(uri); + if (parts.path != null) + return getFileSystem(uri).getPath(parts.path); + else return ((PathFileSystem)getFileSystem(uri)).getRoot(); - } } @Override public FileSystem getFileSystem(URI uri) { - String key = makeKey(uri); - String owner = key.split(COMPONENT_SEPERATOR)[0]; - FileSystem fs = fileSystems.get(owner); + URIComponents parts = parse(uri); + FileSystem fs = fileSystems.get(parts.owner); if (fs == null) { - StringBuilder buf = new StringBuilder(); - buf.append("Unknown FileSystem: ").append(uri); - buf.append('\n').append("\tOwner: ").append(owner); - List sorted = new ArrayList<>(fileSystems.keySet()); - Collections.sort(sorted); - for (String known : sorted) - buf.append('\n').append("\tKnown: ").append(known); - throw new FileSystemNotFoundException(buf.toString()); + StringBuilder buf = new StringBuilder(); + buf.append("Unknown FileSystem: ").append(uri); + buf.append('\n').append("\tOwner: ").append(parts.owner); + List sorted = new ArrayList<>(fileSystems.keySet()); + Collections.sort(sorted); + for (String known : sorted) + buf.append('\n').append("\tKnown: ").append(known); + throw new FileSystemNotFoundException(buf.toString()); } return fs; @@ -235,32 +253,27 @@ void removeFileSystem(PathFileSystem fs) { } } - protected URI buildUriFor(final PathPath path) throws URISyntaxException, IllegalArgumentException - { + protected URI buildUriFor(final PathPath path) throws URISyntaxException, IllegalArgumentException { return new URI( - path.getFileSystem().provider().getScheme(), - path.getFileSystem().getKey() + PATH_SEPERATOR + path, - null + path.getFileSystem().provider().getScheme(), + path.getFileSystem().getKey() + PATH_SEPERATOR + path, + null ); } - protected Path createSubPath(final PathFileSystem pathFileSystem, final String... args) - { + protected Path createSubPath(final PathFileSystem pathFileSystem, final String... args) { return new PathPath(pathFileSystem, false, args); } - public Path adaptResolvedPath(final PathPath path) - { + public Path adaptResolvedPath(final PathPath path) { return path; } - public String[] adaptPathParts(final String longstring, final String[] pathParts) - { + public String[] adaptPathParts(final String longstring, final String[] pathParts) { return pathParts; } - protected Optional getFileSystemFromKey(final String section) - { + protected Optional getFileSystemFromKey(final String section) { return Optional.ofNullable(this.fileSystems.get(section)); } } diff --git a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathPath.java b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathPath.java index 88be0e5..ade0049 100644 --- a/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathPath.java +++ b/filesystems/src/main/java/net/minecraftforge/jarjar/nio/pathfs/PathPath.java @@ -40,12 +40,12 @@ protected PathPath(final PathFileSystem fileSystem, final Path innerPath) { this.pathParts = innerPath.toString().replace("\\", "/").split("/"); } - private String[] getPathParts(final String longstring) { - String[] localParts = longstring.equals(this.getFileSystem().getSeparator()) ? new String[] {""} : longstring.replace("\\", this.getFileSystem().getSeparator()).split(this.getFileSystem().getSeparator()); + private String[] getPathParts(String longstring) { + String sep = this.getFileSystem().getSeparator(); + String[] localParts = longstring.equals(sep) ? new String[] {""} : longstring.replace("\\", sep).split(sep); - if (localParts.length > 1 && localParts[0].isEmpty()) { + if (localParts.length > 1 && localParts[0].isEmpty()) localParts = Arrays.copyOfRange(localParts, 1, localParts.length); - } if (this.getFileSystem().provider() != null) return this.getFileSystem().provider().adaptPathParts(longstring, localParts); @@ -77,54 +77,57 @@ public Path getFileName() { return this.pathParts.length > 0 ? new PathPath(this.getFileSystem(), true, this.pathParts[this.pathParts.length-1]) : new PathPath(this.fileSystem, true, ""); } + @Override public Path getParent() { - if (this.pathParts.length > 0 && !(pathParts.length == 1 && pathParts[0].isEmpty())) { + if (this.pathParts.length > 0 && !(pathParts.length == 1 && pathParts[0].isEmpty())) return new PathPath(this.fileSystem, true, Arrays.copyOf(this.pathParts,this.pathParts.length - 1)); - } else { - return null; - } + return null; } + @Override public int getNameCount() { return this.pathParts.length; } + @Override public Path getName(final int index) { - if (index < 0 || index > this.pathParts.length -1) throw new IllegalArgumentException(); + if (index < 0 || index > this.pathParts.length - 1) + throw new IllegalArgumentException(); return new PathPath(this.fileSystem, true, this.pathParts[index]); } @Override public Path subpath(final int beginIndex, final int endIndex) { - if (beginIndex < 0 || beginIndex > this.pathParts.length - 1 || endIndex < 0 || endIndex > this.pathParts.length || beginIndex > endIndex) { - throw new IllegalArgumentException("Out of range "+beginIndex+" to "+endIndex+" for length "+this.pathParts.length); - } + if (beginIndex < 0 || beginIndex > this.pathParts.length - 1 || endIndex < 0 || endIndex > this.pathParts.length || beginIndex > endIndex) + throw new IllegalArgumentException("Out of range " + beginIndex + " to " + endIndex + " for length " + this.pathParts.length); return new PathPath(this.fileSystem, true, Arrays.copyOfRange(this.pathParts, beginIndex, endIndex)); } @Override public boolean startsWith(final Path other) { - if (other.getFileSystem() != this.getFileSystem()) { + if (other.getFileSystem() != this.getFileSystem()) return false; - } + if (other instanceof PathPath) { final PathPath bp = (PathPath) other; return checkArraysMatch(this.pathParts, bp.pathParts, false); } + return false; } @Override public boolean endsWith(final Path other) { - if (other.getFileSystem() != this.getFileSystem()) { + if (other.getFileSystem() != this.getFileSystem()) return false; - } + if (other instanceof PathPath) { final PathPath bp = (PathPath) other; return checkArraysMatch(this.pathParts, bp.pathParts, true); } + return false; } @@ -160,10 +163,12 @@ public Path normalize() { public Path resolve(final Path other) { if (other instanceof PathPath) { final PathPath path = (PathPath) other; - if (path.isAbsolute()) { - return this.getFileSystem().provider().adaptResolvedPath(path); - } - return this.getFileSystem().provider().adaptResolvedPath(new PathPath(this.fileSystem, false, this+fileSystem.getSeparator()+other)); + PathFileSystemProvider provider = this.getFileSystem().provider(); + + if (path.isAbsolute()) + return provider.adaptResolvedPath(path); + + return provider.adaptResolvedPath(new PathPath(this.fileSystem, false, this + fileSystem.getSeparator() + other)); } return other; }