package ch.akuhn.hapax.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** Visits all entries in a ZIP file, including entries in nested ZIP files. * * @author Adrian Kuhn * */ public class Ziperator implements Iterable<Ziperator.Entry> { private File file; private boolean recurse; public Ziperator(String fname) { this(new File(fname)); } public Ziperator(File file) { this.file = file; this.recurse(); } public Ziperator recurse() { this.recurse = true; return this; } public Ziperator dontRecurse() { this.recurse = false; return this; } public static class Entry { public Entry parent; public ZipEntry entry; public InputStream in; public Entry(Entry parent, ZipEntry entry, InputStream in) { this.parent = parent; this.entry = entry; this.in = in; } @Override public String toString() { return parent + "::" + entry; } public boolean isSourceArchive() { return isArchive() && entry.getName().indexOf("src") > 0; } public boolean isArchive() { return entry.getName().endsWith(".zip") || entry.getName().endsWith(".jar"); } } @Override public Iterator<Entry> iterator() { return new Iter(file).setRecurse(recurse); } private static class Iter implements Iterator<Entry> { private Entry parent; private ZipInputStream zip; private Entry next; private Iterator<Entry> children; private boolean recurse; public Iter(File file) { this.parent = null; try { this.zip = new ZipInputStream(new FileInputStream(file)); } catch (FileNotFoundException ex) { throw new RuntimeException(ex); } } public Iterator<Entry> setRecurse(boolean recurse) { this.recurse = recurse; return this; } public Iter(Entry parent, InputStream in) { this.parent = parent; this.zip = new ZipInputStream(in); } @Override public boolean hasNext() { try { if (children != null) { if (children.hasNext()) return true; children = null; } if (next != null) return true; ZipEntry entry = zip.getNextEntry(); if (entry == null) return false; next = new Entry(parent, entry, zip); if (next == null) return false; if (recurse && next.isArchive()) { children = new Iter(next, zip).setRecurse(recurse); return this.hasNext(); } return true; } catch (IOException ex) { throw new RuntimeException(ex); } } @Override public Entry next() { if (!hasNext()) throw new NoSuchElementException(); if (next == null) return children.next(); Entry each = next; next = null; return each; } @Override public void remove() { throw new UnsupportedOperationException(); } } }