/*******************************************************************************
* Copyright (c) 2015-2015 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* * Davy Landman - Davy.Landman@cwi.nl - CWI
* * Jurgen Vinju - Jurgen.Vinju@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.uri.jar;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import org.rascalmpl.uri.FileTree;
import org.rascalmpl.uri.URIResolverRegistry;
import org.rascalmpl.uri.URIUtil;
import org.rascalmpl.value.ISourceLocation;
public class JarInputStreamResolver extends JarFileResolver {
private final URIResolverRegistry CTX;
public JarInputStreamResolver(URIResolverRegistry registry) {
this.CTX = registry;
}
@Override
protected FileTree getFileHierchyCache(ISourceLocation jarLocation) {
try {
final ISourceLocation lookupKey = URIUtil.changeQuery(jarLocation, "mod=" + CTX.lastModified(jarLocation));
return fsCache.get(lookupKey, j -> {
try {
return new JarInputStreamFileTree(CTX.getInputStream(jarLocation));
}
catch (IOException e) {
throw new RuntimeException(e);
}
});
}
catch (URISyntaxException | IOException e) {
throw new RuntimeException(e);
}
}
private JarEntry skipToEntry(JarInputStream stream, ISourceLocation jarLocation, String subPath) throws IOException {
int pos = ((JarInputStreamFileTree)getFileHierchyCache(jarLocation)).getPosition(subPath);
if (pos != -1) {
JarEntry entry;
do {
entry = stream.getNextJarEntry();
}
while (pos-- > 0);
return entry;
}
return null;
}
@Override
public InputStream getInputStream(ISourceLocation jarLocation, String subPath) throws IOException {
final JarInputStream stream = new JarInputStream(CTX.getInputStream(jarLocation));
if (skipToEntry(stream, jarLocation, subPath) != null) {
// ideally we could just return the stream
// except that the JarInputStream doesn't hold the InputStream contract.
// Mainly, the read(byte[],int,int) works correctly, as that it stops at
// the boundary of the file but the read() doesn't limit itself to the end
// of the nested file, but works on the whole stream.
return new InputStream() {
@Override
public int read() throws IOException {
byte[] result = new byte[1];
if (stream.read(result, 0, 1) != -1) {
return result[0] & 0xFF;
}
return -1;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return stream.read(b, off, len);
}
@Override
public int read(byte[] b) throws IOException {
return stream.read(b, 0, b.length);
}
@Override
public void close() throws IOException {
stream.close();
}
@Override
public int available() throws IOException {
return stream.available();
}
@Override
public long skip(long n) throws IOException {
return stream.skip(n);
}
};
}
try {
stream.close();
}
catch (IOException e) {
}
return null;
}
}