/******************************************************************************* * Copyright (C) 2009-2011 Amir Hassan <amir@viel-zu.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ******************************************************************************/ package org.wooden.util; import java.awt.Component; import java.awt.Image; import java.awt.Toolkit; import java.awt.image.RasterFormatException; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import javax.swing.ImageIcon; public class JarResource implements DataResource { private File soureFile; private JarFile jar; private HashMap jarCache; private Vector changedEntries; private boolean cached; public JarResource(File jarfile) throws IOException { this.jarCache = new HashMap(); this.changedEntries = new Vector(); this.cached = false; this.jar = new JarFile(jarfile); } public JarResource(URL url) throws IOException { this(url, true, true); } public JarResource(URL url, boolean preload, boolean cache) throws IOException { this.jarCache = new HashMap(); this.changedEntries = new Vector(); this.cached = false; this.cached = cache; if (preload) this.preloadResource(url, cache); else this.jar = new JarFile(new File(url.getFile())); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { try { if (JarResource.this.jar != null) JarResource.this.close(true); } catch (IOException ioexception) {} } }); } public void cache(String name, byte data[]) { if (this.isCached()) this.jarCache.put(name, data); } public synchronized void clearCache() { this.jarCache.clear(); } public void close(boolean writeChange) throws IOException, MalformedURLException { this.jar.close(); if (writeChange) { Vector newEntries = null; JarOutputStream out = new JarOutputStream(this.soureFile.toURL() .openConnection().getOutputStream()); if (this.cached) { int len = this.changedEntries.size(); for (int i = 0; i < len; i++) this.jarCache.put(((JarEntry) this.changedEntries.get(i)).getName(), this.changedEntries); newEntries = new Vector(this.jarCache.values()); } else { Enumeration enumEntries = this.jar.entries(); newEntries = new Vector(); Object e; int index; while (enumEntries.hasMoreElements()) if ((index = this.changedEntries.indexOf(e = enumEntries .nextElement())) > -1) newEntries.add(this.changedEntries.get(index)); else newEntries.add(e); } JarEntry entries[] = (JarEntry[]) newEntries.toArray(new JarEntry[0]); for (JarEntry entrie : entries) out.putNextEntry(entrie); out.close(); } } public Enumeration enumateResourcePaths() { Enumeration entries = this.jar.entries(); Vector paths = new Vector(); for (; entries.hasMoreElements(); paths.add(((JarEntry) entries .nextElement()).getName())) ; return paths.elements(); } public ImageIcon getIcon(String name, Component observer) throws IOException { ImageIcon icon = new ImageIcon(this.getImage(name, observer)); if (icon.getImageLoadStatus() == 4) throw new RasterFormatException("Illegal Icon Image"); while (icon.getImageLoadStatus() != 8) try { Thread.sleep(50L); } catch (InterruptedException interruptedexception) {} return icon; } public Image getImage(String name, Component observer) throws IOException { Toolkit kit = null; Image img = null; if (observer == null) throw new NullPointerException("Observer can't be null"); kit = observer.getToolkit(); if (kit == null) kit = Toolkit.getDefaultToolkit(); img = kit.createImage(this.getResource(name)); for (int i = 0; i < 10 && img.getWidth(observer) < 0; i++) try { Thread.sleep(50L); } catch (InterruptedException ex) { ex.printStackTrace(); } if (img.getWidth(observer) < 0) { throw new RasterFormatException("Illegal Image Format"); } else { kit.prepareImage(img, observer.getWidth(), observer.getHeight(), observer); return img; } } @Override public byte[] getResource(String name) throws IOException { if (this.isCached()) return (byte[]) this.jarCache.get(name); JarEntry e = this.jar.getJarEntry(name); if (e == null) throw new IllegalArgumentException((new StringBuilder( "Unknown Resource: ")).append(name).toString()); InputStream in = this.jar.getInputStream(e); int read = 0; byte buffer[] = new byte[8192]; ByteArrayOutputStream out = new ByteArrayOutputStream(); while ((read = in.read(buffer, 0, buffer.length)) != -1) out.write(buffer, 0, read); return out.toByteArray(); } @Override public InputStream getResourceStream(String name) throws IOException { JarEntry e = this.jar.getJarEntry(name); if (e == null) throw new IllegalArgumentException((new StringBuilder( "Unknown Resource: ")).append(name).toString()); else return this.jar.getInputStream(e); } @Override public synchronized boolean isCached() { return this.cached; } private void preloadResource(URL url, boolean cache) throws IOException { JarOutputStream out; ByteArrayOutputStream buffer; String u = url.toString(); if (!u.startsWith("jar:")) { u = (new StringBuilder("jar:")).append(u).append("!/").toString(); url = new URL(u); } out = null; JarURLConnection connection = null; buffer = new ByteArrayOutputStream(); try { File tmp = File.createTempFile("jar", ".res"); tmp.deleteOnExit(); connection = (JarURLConnection) url.openConnection(); JarFile remoteJar = connection.getJarFile(); out = new JarOutputStream(new FileOutputStream(tmp)); InputStream in_e; for (Enumeration remoteEntries = remoteJar.entries(); remoteEntries .hasMoreElements(); in_e.close()) { JarEntry entry = (JarEntry) remoteEntries.nextElement(); in_e = remoteJar.getInputStream(entry); int d; while ((d = in_e.read()) != -1) buffer.write(d); byte data[] = buffer.toByteArray(); entry.setSize(data.length); this.cache(entry.getName(), data); out.putNextEntry(entry); out.write(data); out.closeEntry(); buffer.reset(); } out.close(); this.jar = new JarFile(tmp); } catch (Exception ex) { ex.printStackTrace(); if (out != null) out.close(); throw new IOException(ex.getMessage()); } } @Override public void setResource(String name, byte data[]) throws IOException { JarEntry res = new JarEntry(name); res.setSize(data.length); if (this.isCached()) this.jarCache.put(name, data); } }