1 32 package net.sf.retrotranslator.transformer; 33 34 import java.io.*; 35 import java.util.*; 36 import java.util.jar.*; 37 import java.util.regex.Pattern ; 38 import java.util.zip.*; 39 40 43 class JarFileContainer extends FileContainer { 44 45 private static Pattern SIGNATURE_ENTRY = Pattern.compile("META-INF/SIG-.+|META-INF/.+\\.(SF|DSA|RSA)"); 46 private static Pattern SIGNATURE_ATTRIBUTE = Pattern.compile("Magic|.+-Digest(-.+)?"); 47 48 private Map<String , JarFileEntry> entries; 49 private boolean modified; 50 51 public JarFileContainer(File location) { 52 super(location); 53 } 54 55 public Collection<? extends FileEntry> getEntries() { 56 if (entries == null) init(); 57 return new ArrayList<JarFileEntry>(entries.values()); 58 } 59 60 public void removeEntry(String name) { 61 if (entries != null) { 62 entries.remove(name); 63 } 64 } 65 66 private void init() { 67 entries = new LinkedHashMap<String , JarFileEntry>(); 68 try { 69 FileInputStream fileInputStream = new FileInputStream(location); 70 try { 71 ZipInputStream stream = new ZipInputStream(fileInputStream); 72 ZipEntry entry; 73 while ((entry = stream.getNextEntry()) != null) { 74 if (!entry.isDirectory()) { 75 byte[] content = readFully(stream, (int) entry.getSize()); 76 entries.put(entry.getName(), new JarFileEntry(entry.getName(), content)); 77 } 78 } 79 } finally { 80 fileInputStream.close(); 81 } 82 } catch (IOException e) { 83 throw new RuntimeException (e); 84 } 85 } 86 87 public void putEntry(String name, byte[] contents) { 88 if (entries == null) entries = new LinkedHashMap<String , JarFileEntry>(); 89 entries.put(name, new JarFileEntry(name, contents)); 90 modified = true; 91 } 92 93 public void flush(SystemLogger logger) { 94 if (!modified) return; 95 try { 96 FileOutputStream stream = new FileOutputStream(location); 97 try { 98 flush(stream, logger); 99 modified = false; 100 } finally { 101 stream.close(); 102 } 103 } catch (IOException e) { 104 throw new RuntimeException (e); 105 } 106 } 107 108 private void flush(FileOutputStream fileOutputStream, SystemLogger logger) throws IOException { 109 JarFileEntry manifestEntry = entries.get(JarFile.MANIFEST_NAME); 110 Manifest manifest = manifestEntry == null ? new Manifest() 111 : new Manifest(new ByteArrayInputStream(manifestEntry.getContent())); 112 fixMainAttributes(manifest); 113 boolean signatureRemoved = removeSignatureAttributes(manifest); 114 JarOutputStream stream = new JarOutputStream(fileOutputStream, manifest); 115 stream.setLevel(Deflater.BEST_COMPRESSION); 116 for (JarFileEntry entry : this.entries.values()) { 117 if (entry == manifestEntry) continue; 118 if (SIGNATURE_ENTRY.matcher(entry.getName()).matches()) { 119 signatureRemoved = true; 120 continue; 121 } 122 stream.putNextEntry(new ZipEntry(entry.getName())); 123 byte[] content = entry.getContent(); 124 if (content != null) stream.write(content); 125 } 126 if (signatureRemoved) { 127 logger.log(new Message(Level.INFO, "Removing signature from " + location, location, null)); 128 } 129 stream.close(); 130 } 131 132 private void fixMainAttributes(Manifest manifest) { 133 Attributes attributes = manifest.getMainAttributes(); 134 attributes.putValue("Manifest-Version", "1.0"); 135 attributes.putValue("Created-By", 136 System.getProperty("java.vm.version") + " (" + System.getProperty("java.vm.vendor") + ")"); 137 String title = getClass().getPackage().getImplementationTitle(); 138 String version = getClass().getPackage().getImplementationVersion(); 139 if (title != null && version != null) { 140 attributes.putValue("Retrotranslator-Version", title + " " + version); 141 } 142 } 143 144 private boolean removeSignatureAttributes(Manifest manifest) { 145 for (Attributes attributes : manifest.getEntries().values()) { 146 Iterator<Map.Entry<Object , Object >> iterator = attributes.entrySet().iterator(); 147 while (iterator.hasNext()) { 148 if (SIGNATURE_ATTRIBUTE.matcher(iterator.next().getKey().toString()).matches()) { 149 iterator.remove(); 150 } 151 } 152 } 153 return false; 154 } 155 156 private static class JarFileEntry extends FileEntry { 157 158 private byte[] content; 159 160 public JarFileEntry(String name, byte[] content) { 161 super(name); 162 this.content = content; 163 } 164 165 public byte[] getContent() { 166 return content; 167 } 168 } 169 } 170 | Popular Tags |