package com.topjohnwu.signing; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public abstract class JarMap implements Closeable { LinkedHashMap entryMap; public static JarMap open(String file) throws IOException { return new FileMap(new File(file), true, ZipFile.OPEN_READ); } public static JarMap open(File file, boolean verify) throws IOException { return new FileMap(file, verify, ZipFile.OPEN_READ); } public static JarMap open(String file, boolean verify) throws IOException { return new FileMap(new File(file), verify, ZipFile.OPEN_READ); } public static JarMap open(InputStream is, boolean verify) throws IOException { return new StreamMap(is, verify); } public File getFile() { return null; } public abstract Manifest getManifest() throws IOException; public InputStream getInputStream(ZipEntry ze) throws IOException { JarMapEntry e = getMapEntry(ze.getName()); return e != null ? e.data.getInputStream() : null; } public OutputStream getOutputStream(ZipEntry ze) { if (entryMap == null) entryMap = new LinkedHashMap<>(); JarMapEntry e = new JarMapEntry(ze.getName()); entryMap.put(ze.getName(), e); return e.data; } public byte[] getRawData(ZipEntry ze) throws IOException { JarMapEntry e = getMapEntry(ze.getName()); return e != null ? e.data.toByteArray() : null; } public abstract Enumeration entries(); public final ZipEntry getEntry(String name) { return getJarEntry(name); } public JarEntry getJarEntry(String name) { return getMapEntry(name); } JarMapEntry getMapEntry(String name) { JarMapEntry e = null; if (entryMap != null) e = (JarMapEntry) entryMap.get(name); return e; } private static class FileMap extends JarMap { private JarFile jarFile; FileMap(File file, boolean verify, int mode) throws IOException { jarFile = new JarFile(file, verify, mode); } @Override public File getFile() { return new File(jarFile.getName()); } @Override public Manifest getManifest() throws IOException { return jarFile.getManifest(); } @Override public InputStream getInputStream(ZipEntry ze) throws IOException { InputStream is = super.getInputStream(ze); return is != null ? is : jarFile.getInputStream(ze); } @Override public byte[] getRawData(ZipEntry ze) throws IOException { byte[] b = super.getRawData(ze); if (b != null) return b; ByteArrayStream bytes = new ByteArrayStream(); bytes.readFrom(jarFile.getInputStream(ze)); return bytes.toByteArray(); } @Override public Enumeration entries() { return jarFile.entries(); } @Override public JarEntry getJarEntry(String name) { JarEntry e = getMapEntry(name); return e != null ? e : jarFile.getJarEntry(name); } @Override public void close() throws IOException { jarFile.close(); } } private static class StreamMap extends JarMap { private JarInputStream jis; StreamMap(InputStream is, boolean verify) throws IOException { jis = new JarInputStream(is, verify); entryMap = new LinkedHashMap<>(); JarEntry entry; while ((entry = jis.getNextJarEntry()) != null) { entryMap.put(entry.getName(), new JarMapEntry(entry, jis)); } } @Override public Manifest getManifest() { return jis.getManifest(); } @Override public Enumeration entries() { return Collections.enumeration(entryMap.values()); } @Override public void close() throws IOException { jis.close(); } } private static class JarMapEntry extends JarEntry { ByteArrayStream data; JarMapEntry(JarEntry je, InputStream is) { super(je); data = new ByteArrayStream(); data.readFrom(is); } JarMapEntry(String s) { super(s); data = new ByteArrayStream(); } } }