/* * 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(); addLastModifiedTime(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(); } }