WALA/com.ibm.wala.core/src/com/ibm/wala/classLoader/JarStreamModule.java

268 lines
6.5 KiB
Java

/******************************************************************************
* Copyright (c) 2002 - 2014 IBM Corporation.
* 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:
* IBM Corporation - initial API and implementation
*****************************************************************************/
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 Module getContainer() {
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);
}
}