/*
* FindBugs - Find Bugs in Java programs
* Copyright (C) 2006, University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.umd.cs.findbugs.classfile.impl;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import edu.umd.cs.findbugs.classfile.ICodeBaseEntry;
import edu.umd.cs.findbugs.classfile.ICodeBaseIterator;
import edu.umd.cs.findbugs.classfile.ICodeBaseLocator;
import edu.umd.cs.findbugs.io.IO;
import edu.umd.cs.findbugs.util.Archive;
import edu.umd.cs.findbugs.util.MapCache;
/**
* Implementation of ICodeBase to read from a zip file or jar file.
*
* @author David Hovemeyer
*/
public class ZipInputStreamCodeBase extends AbstractScannableCodeBase {
final static boolean DEBUG = false;
final File file;
final MapCache<String, ZipInputStreamCodeBaseEntry> map = new MapCache<String, ZipInputStreamCodeBaseEntry>(10000);
final HashSet<String> entries = new HashSet<String>();
/**
* Constructor.
*
* @param codeBaseLocator
* the codebase locator for this codebase
* @param file
* the File containing the zip file (may be a temp file if the
* codebase was copied from a nested zipfile in another codebase)
*/
public ZipInputStreamCodeBase(ICodeBaseLocator codeBaseLocator, File file) throws IOException {
super(codeBaseLocator);
this.file = file;
setLastModifiedTime(file.lastModified());
ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
try {
ZipEntry ze;
if (DEBUG) {
System.out.println("Reading zip input stream " + file);
}
while ((ze = zis.getNextEntry()) != null) {
String name = ze.getName();
if (!ze.isDirectory()
&& (name.equals("META-INF/MANIFEST.MF") || name.endsWith(".class") || Archive.isArchiveFileName(name))) {
entries.add(name);
if (name.equals("META-INF/MANIFEST.MF")) {
map.put(name, build(zis, ze));
}
}
zis.closeEntry();
}
} finally {
zis.close();
}
if (DEBUG) {
System.out.println("Done with zip input stream " + file);
}
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.classfile.ICodeBase#lookupResource(java.lang.String)
*/
public ICodeBaseEntry lookupResource(String resourceName) {
// Translate resource name, in case a resource name
// has been overridden and the resource is being accessed
// using the overridden name.
resourceName = translateResourceName(resourceName);
if (!entries.contains(resourceName)) {
return null;
}
try {
ZipInputStreamCodeBaseEntry z = map.get(resourceName);
if (z != null) {
return z;
}
ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
try {
ZipEntry ze;
boolean found = false;
int countDown = 20;
while ((ze = zis.getNextEntry()) != null && countDown >= 0) {
if (ze.getName().equals(resourceName)) {
found = true;
}
if (found) {
countDown--;
if (map.containsKey(ze.getName())) {
continue;
}
z = build(zis, ze);
map.put(ze.getName(), z);
}
zis.closeEntry();
}
} finally {
zis.close();
}
z = map.get(resourceName);
if (z == null) {
throw new AssertionError("Could not find " + resourceName);
}
return z;
} catch (IOException e) {
return null;
}
}
ZipInputStreamCodeBaseEntry build(ZipInputStream zis, ZipEntry ze) throws IOException {
long sz = ze.getSize();
ByteArrayOutputStream out;
if (sz < 0 || sz > Integer.MAX_VALUE) {
out = new ByteArrayOutputStream();
} else {
out = new ByteArrayOutputStream((int) sz);
}
IO.copy(zis, out);
byte[] bytes = out.toByteArray();
setLastModifiedTime(ze.getTime());
return new ZipInputStreamCodeBaseEntry(this, ze, bytes);
}
class MyIterator implements ICodeBaseIterator {
ZipInputStream zis;
ZipEntry ze;
MyIterator() {
try {
zis = new ZipInputStream(new FileInputStream(file));
ze = zis.getNextEntry();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void getNextEntry() throws IOException {
ze = zis.getNextEntry();
if (ze == null) {
zis.close();
}
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.classfile.ICodeBaseIterator#hasNext()
*/
public boolean hasNext() throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
return ze != null;
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.classfile.ICodeBaseIterator#next()
*/
public ICodeBaseEntry next() throws InterruptedException {
try {
if (Thread.interrupted()) {
throw new InterruptedException();
}
ZipInputStreamCodeBaseEntry z = build(zis, ze);
zis.closeEntry();
getNextEntry();
return z;
} catch (IOException e) {
throw new RuntimeException("Failure getting next entry in " + file, e);
}
}
}
public ICodeBaseIterator iterator() {
return new MyIterator();
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.classfile.ICodeBase#getPathName()
*/
public String getPathName() {
return file.getName();
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.classfile.ICodeBase#close()
*/
public void close() {
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return file.getName();
}
}