Read jar files from input stream as a fallback. Do not rely on existsing files.

This commit is contained in:
Juergen Graf 2012-06-08 15:24:38 +02:00
parent 69846ed275
commit cb02231692
2 changed files with 262 additions and 1 deletions

View File

@ -0,0 +1,252 @@
package com.ibm.wala.classLoader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.io.FileSuffixes;
import com.ibm.wala.util.warnings.Warning;
import com.ibm.wala.util.warnings.Warnings;
/**
* Read in a jar file from an input stream. Most parts are copied from the NestedJarFileModule class
* and adapted to work with an input stream.
* @author Juergen Graf <juergen.graf@gmail.com>
*/
public class JarStreamModule implements Module {
private static final boolean DEBUG = false;
private final JarInputStream stream;
/**
* For efficiency, we cache the byte[] holding each ZipEntry's contents; this will help avoid multiple unzipping TODO: use a soft
* reference?
*/
private HashMap<String, byte[]> cache = null;
public JarStreamModule(JarInputStream stream) {
if (stream == null) {
throw new IllegalArgumentException("null stream");
}
this.stream = stream;
}
public InputStream getInputStream(String name) {
populateCache();
byte[] b = cache.get(name);
return new ByteArrayInputStream(b);
}
private void populateCache() {
if (cache != null) {
return;
}
cache = HashMapFactory.make();
try {
for (ZipEntry z = stream.getNextEntry(); z != null; z = stream.getNextEntry()) {
final String name = z.getName();
if (DEBUG) {
System.err.println(("got entry: " + name));
}
if (FileSuffixes.isClassFile(name) || FileSuffixes.isSourceFile(name)) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] temp = new byte[1024];
int n = stream.read(temp);
while (n != -1) {
out.write(temp, 0, n);
n = stream.read(temp);
}
byte[] bb = out.toByteArray();
cache.put(name, bb);
}
}
} catch (IOException e) {
// just go with what we have
Warnings.add(new Warning() {
@Override
public String getMsg() {
return "could not read contents of jar input stream.";
}
});
}
}
protected long getEntrySize(String name) {
populateCache();
byte[] b = cache.get(name);
return b.length;
}
/*
* @see com.ibm.wala.classLoader.Module#getEntries()
*/
public Iterator<ModuleEntry> getEntries() {
populateCache();
final Iterator<String> it = cache.keySet().iterator();
return new Iterator<ModuleEntry>() {
String next = null;
{
advance();
}
private void advance() {
if (it.hasNext()) {
next = it.next();
} else {
next = null;
}
}
public boolean hasNext() {
return next != null;
}
public ModuleEntry next() {
ModuleEntry result = new Entry(next);
advance();
return result;
}
public void remove() {
Assertions.UNREACHABLE();
}
};
}
/**
* @author sfink an entry in a nested jar file.
*/
private class Entry implements ModuleEntry {
private final String name;
Entry(String name) {
this.name = name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getName()
*/
public String getName() {
return name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isClassFile()
*/
public boolean isClassFile() {
return FileSuffixes.isClassFile(getName());
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getInputStream()
*/
public InputStream getInputStream() {
return JarStreamModule.this.getInputStream(name);
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile()
*/
public boolean isModuleFile() {
return false;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#asModule()
*/
public Module asModule() {
Assertions.UNREACHABLE();
return null;
}
@Override
public String toString() {
return "nested entry: " + name;
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#getClassName()
*/
public String getClassName() {
return FileSuffixes.stripSuffix(getName());
}
/*
* @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile()
*/
public boolean isSourceFile() {
return FileSuffixes.isSourceFile(getName());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entry other = (Entry) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private JarStreamModule getOuterType() {
return JarStreamModule.this;
}
}
@Override
public String toString() {
return "Jar input stream " + stream.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (stream.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
JarStreamModule other = (JarStreamModule) obj;
return stream.equals(other.stream);
}
}

View File

@ -17,11 +17,14 @@ import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.zip.ZipException;
import com.ibm.wala.classLoader.JarFileModule;
import com.ibm.wala.classLoader.JarStreamModule;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.classLoader.NestedJarFileModule;
@ -153,9 +156,15 @@ public class FileProvider {
JarEntry entry = jc.getJarEntry();
JarFileModule parent = new JarFileModule(f);
return new NestedJarFileModule(parent, entry);
} else {
/** BEGIN Custom change: try to load from input stream as fallback */
} else if (url.getProtocol().equals("file")) {
String filePath = filePathFromURL(url);
return new JarFileModule(new JarFile(filePath, false));
} else {
final URLConnection in = url.openConnection();
final JarInputStream jarIn = new JarInputStream(in.getInputStream());
return new JarStreamModule(jarIn);
/** END Custom change: try to load from input stream as fallback */
}
}