package org.rascalmpl.uri.jar;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import org.rascalmpl.uri.ISourceLocationInput;
import org.rascalmpl.uri.URIResolverRegistry;
import org.rascalmpl.value.ISourceLocation;
import org.rascalmpl.value.IValueFactory;
import org.rascalmpl.values.ValueFactoryFactory;
public class JarURIResolver implements ISourceLocationInput {
private static final IValueFactory VF = ValueFactoryFactory.getValueFactory();
private final JarFileResolver file = new JarFileResolver();
private final JarFileResolver inputStream;
public JarURIResolver(URIResolverRegistry registry) {
inputStream = new JarInputStreamResolver(registry);
}
@Override
public String scheme() {
return "jar";
}
private JarFileResolver getTargetResolver(ISourceLocation uri) {
if (uri.getScheme().startsWith("jar+")) {
return inputStream;
}
return file;
}
private static String getInsideJarPath(ISourceLocation uri) {
String path = uri.getPath();
if (path != null && !path.isEmpty()) {
int bang = path.lastIndexOf('!');
if (bang != -1) {
path = path.substring(bang + 1);
while (path.startsWith("/")) {
path = path.substring(1);
}
return path;
}
}
return "";
}
private static ISourceLocation getJarPath(ISourceLocation uri) throws IOException {
boolean isWrapped = uri.getScheme().startsWith("jar+");
try {
String path = uri.getPath();
if (path != null && !path.isEmpty()) {
int bang = path.lastIndexOf('!');
if (bang != -1) {
return VF.sourceLocation(
isWrapped ? uri.getScheme().substring("jar+".length()) : "file",
isWrapped ? uri.getAuthority() : "",
path.substring(path.indexOf("/"), bang));
}
}
throw new IOException("The jar and the internal path should be separated with a ! (" + uri.getPath() + ")");
}
catch (UnsupportedOperationException | URISyntaxException e) {
throw new IOException("Invalid URI: \"" + uri +"\"", e);
}
}
@Override
public InputStream getInputStream(ISourceLocation uri) throws IOException {
return getTargetResolver(uri).getInputStream(getJarPath(uri), getInsideJarPath(uri));
}
@Override
public boolean isDirectory(ISourceLocation uri) {
if (uri.getPath() != null && (uri.getPath().endsWith("!") || uri.getPath().endsWith("!/"))) {
// if the uri is the root of a jar, and it ends with a ![/], it should be considered a
// directory
return true;
}
try {
return getTargetResolver(uri).isDirectory(getJarPath(uri), getInsideJarPath(uri));
}
catch (IOException e) {
return false;
}
}
@Override
public boolean exists(ISourceLocation uri) {
try {
return getTargetResolver(uri).exists(getJarPath(uri), getInsideJarPath(uri));
}
catch (IOException e) {
return false;
}
}
@Override
public boolean isFile(ISourceLocation uri) {
try {
return getTargetResolver(uri).isFile(getJarPath(uri), getInsideJarPath(uri));
}
catch (IOException e) {
return false;
}
}
@Override
public Charset getCharset(ISourceLocation uri) throws IOException {
return null; // one day we might read the meta-inf?
}
@Override
public long lastModified(ISourceLocation uri) throws IOException {
return getTargetResolver(uri).lastModified(getJarPath(uri), getInsideJarPath(uri));
}
@Override
public String[] list(ISourceLocation uri) throws IOException {
return getTargetResolver(uri).list(getJarPath(uri), getInsideJarPath(uri));
}
@Override
public boolean supportsHost() {
return true; // someone we wrap might support host
}
}