package com.idega.core.ldap.client.cbutil; import java.awt.Image; import java.awt.Toolkit; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; /** * CBJarResources: CBJarResources maps all resources included in a * Zip or Jar file. Additionaly, it provides methods to extract * them as byte arrays, images, or input streams.<p> * This class makes no distinction between jar and zip files, and * makes no use of any jar manifest file, should it exist. */ public final class CBJarResource { /** * The contents of the zip file are cached the first time they are used, to * speed any subsequent access of the same resource. */ protected Hashtable contents=new Hashtable(); /** * When the CBJarResource object is created, the referenced zip file's catalogue * is read. Later, individual zipped files are read using this cache of catalogue entries. */ protected Hashtable entries = new Hashtable(); /** * The name of this object's jar/zip file */ protected String zipFileName; /** * The actual zip or jar file */ protected ZipFile zipFile; private boolean debug = false; /** * creates a CBJarResources. It extracts all resources from a Jar * into an internal hashtable, keyed by resource names. * @param zipFileName a jar or zip file */ public CBJarResource(String zipFileName) { this(zipFileName, false); } /** * Returns the raw name of the zip/jar file. * @return the name of the zip file, e.g. 'help/local/fnord.zip' */ public String getZipFileName() { return this.zipFileName; } /** * Returns the last modified date of the zip file. */ public long getLastModified() { File zip = new File(this.zipFileName); if (zip == null) { return 0; } else { return zip.lastModified(); } } /** * creates a CBJarResources. It extracts all resources from a Jar * into an internal hashtable, keyed by resource names. * @param zipFileName a jar or zip file * @param debug whether to dump the list of files found in the zip file. */ public CBJarResource(String zipFileName, boolean Debug) { this.debug = Debug; this.zipFileName=zipFileName; init(); } /** * Prints a simple identifying string for debugging purposes. */ public String toString() { return "CBJarResource (" + this.zipFileName + ")"; } /** * returns whether a particular resource * exists in the archive. These names are preloaded into a hashtable, so this should be a lightweight operation. * @param name the name of the resource (e.g. a class com/ca/od/util/CBJarResources, or an image file myimages/winona.gif) */ public boolean hasResource(String name) { return this.entries.containsKey(name); } /** * Extracts a jar resource as a blob. Note that this basic method throws no exceptions, but simply returns null on failure. * @param name a resource name. * @returns a resource, or null if no resource available for any reason. */ public byte[] getResource(String name) throws ZipException { return getRawResource(name); } /** * Extracts a file from a jar or zip, returning it as a raw byte array. */ protected byte[] getRawResource(String name) throws ZipException { try { ZipEntry entry = (ZipEntry)this.entries.get(name); InputStream in = this.zipFile.getInputStream(entry); if (entry == null) { throw new ZipException("Unable to find: " + name + " in zip file " + this.zipFileName); } return readZipEntryData(in, entry); } catch (IOException e) { throw new ZipException("Error reading zip file: " + e); } } /** * Returns an Image from a zip file. * @param imageName the name of the image (including path) as saved in the zip file * @param imageCreator a java.awt.Component used to get a Toolkit to construct the Image. * @return a usable java.awt.Image file. */ public Image getImage(String imageName, Toolkit imageCreator) throws ZipException { if (hasResource(imageName) == false) { throw new ZipException("resource: " + imageName + " not found in zip file: " + this.zipFileName); } Image ret = imageCreator.createImage(getRawResource(imageName)); return ret; } /** * Allows a zipped file to be accessed with a (uncompressed) input stream, not unlike * a normal FileInputStream. * @param resourceName the fully qualified name of the object (i.e. with the path of the file as it exists in the zip file) */ public InputStream getInputStream(String resourceName) throws ZipException { try { ZipEntry entry = (ZipEntry)this.entries.get(resourceName); InputStream in = this.zipFile.getInputStream(entry); return in; } catch (IOException e) { throw new ZipException("Error getting input stream: " + e.toString()); } } /** * initializes internal hash tables with Jar file resources. */ protected void init() { try { // extracts just sizes only. this.zipFile = new ZipFile(this.zipFileName); Enumeration e=this.zipFile.entries(); while (e.hasMoreElements()) { ZipEntry ze=(ZipEntry)e.nextElement(); if (this.debug) { System.out.println("zip entry: " + ze); } this.entries.put(ze.getName(), ze); } } catch (NullPointerException e) { CBUtility.log("unable to init zip file - no entries?",1); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * Reads a specific zip entry from the input stream... * @param is the decrypted (important!) input stream to construct an object out of. May be a ZipInputStream, but remember that * ZipInputStream is *not* idempotent (i.e. don't call it on itself!). For the record, ZipFile.getInputStream() is a decrypted stream. * @param ze the single zip entry to extract from the file. */ protected byte[] readZipEntryData(InputStream is, ZipEntry ze) throws java.io.IOException { int size=(int)ze.getSize(); if (size==-1) { CBUtility.log("bizarre size error in zip entry reading = corrupt zip file?"); return null; } byte[] b=new byte[size]; int rb=0; int chunk=0; while ((size - rb) > 0) { chunk=is.read(b,rb,size - rb); if (chunk==-1) { break; } rb+=chunk; } /* DEBUG System.out.println("successfully read: " + ze.getName()+" rb="+rb+",size="+size+",csize="+ze.getCompressedSize()); System.out.println("successfully read value:\n" + new String(b)); for (int i=0; i<10; i++) System.out.print(CBUtility.byte2Hex(b[i]) + " "); System.out.println("\n"); /* */ return b; } /** * Dumps a zip entry into a string. * @param ze a ZipEntry */ protected String dumpZipEntry(ZipEntry ze) { StringBuffer sb=new StringBuffer(); if (ze.isDirectory()) { sb.append("dir: "); } else { sb.append("file: "); } if (ze.getMethod()==ZipEntry.STORED) { sb.append("stored "); } else { sb.append("deflated "); } sb.append(ze.getName()); sb.append("\t\t"); sb.append(""+ze.getSize()); if (ze.getMethod()==ZipEntry.DEFLATED) { sb.append("/"+ze.getCompressedSize()); } return (sb.toString()); } /** * Is a test driver. Given a jar file and a resource name, it trys to * extract the resource and then tells us whether it could or not. * * <strong>Example</strong> * Let's say you have a JAR file which jarred up a bunch of gif image * files. Now, by using CBJarResources, you could extract, create, and display * those images on-the-fly. * <pre> * ... * CBJarResources JR=new CBJarResources("GifBundle.jar"); * Image image=Toolkit.createImage(JR.getResource("logo.gif"); * Image logo=Toolkit.getDefaultToolkit().createImage( * JR.getResources("logo.gif") * ); * ... * </pre> */ public static void main(String[] args) throws IOException { if (args.length!=2) { CBUtility.log("usage: java CBJarResources <jar file name> <resource name>"); System.exit(1); } CBJarResource jr=new CBJarResource(args[0]); byte[] buff=jr.getResource(args[1]); if (buff==null) { System.out.println("Could not find "+args[1]+"."); } else { System.out.println("Found "+args[1]+ " (length="+buff.length+")."); } } protected void finalize() { try { this.zipFile.close(); } catch (Exception e) {} } /** * Returns the *names* only of any resources with a particular prefix (such as 'images/'). * This is similar the wildcard search 'prefix*', but no actual '*' character * is used. The search is case insensitive. */ public String[] getPrefixedResources(String prefix) { prefix = prefix.toLowerCase(); Vector results = new Vector(); Enumeration keys = this.entries.keys(); // cycle through all available entry names (keys) looking for prefixed entries while (keys.hasMoreElements()) { String name = (String)keys.nextElement(); if (name.toLowerCase().startsWith(prefix)) { results.add(name); } } // laboriously cast to strings for returning. if (results.size() == 0) { return new String[] {}; } else { // ???? return (String[]) (results.toArray); return (String[]) results.toArray(new String[results.size()]); /* Object[] temp = results.toArray(); String[] ret = new String[temp.length]; for (int i=0; i<temp.length; i++) ret[i] = (String) temp[i]; return ret; */ } } } // End of CBJarResources class.