001: // Copyright (c) 1997 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: /** Load classes from a Zip archive.
007: * @author Per Bothner
008: */
009:
010: public class ZipLoader extends ClassLoader {
011: /** The zip archive from which we will load the classes.
012: * The format of the archive is the same as classes.zip. */
013: java.util.zip.ZipFile zar;
014:
015: /** Number of classes managed by this loader. */
016: int size;
017:
018: /** name of ZipFile */
019: private String zipname;
020:
021: /* A list of pairs of (name, class) of already loaded classes. */
022: private java.util.Vector loadedClasses;
023:
024: public ZipLoader(String name) throws java.io.IOException {
025: this .zipname = name;
026: this .zar = new java.util.zip.ZipFile(name);
027: size = 0;
028: java.util.Enumeration e = this .zar.entries();
029: while (e.hasMoreElements()) {
030: java.util.zip.ZipEntry ent = (java.util.zip.ZipEntry) e
031: .nextElement();
032: if (!ent.isDirectory())
033: size++;
034: }
035: loadedClasses = new java.util.Vector(size);
036: }
037:
038: public Class loadClass(String name, boolean resolve)
039: throws ClassNotFoundException {
040: Class clas;
041: int index = loadedClasses.indexOf(name);
042: if (index >= 0)
043: clas = (Class) loadedClasses.elementAt(index + 1);
044: else if (zar == null && loadedClasses.size() == 2 * size)
045: clas = Class.forName(name);
046: else {
047: boolean reopened = false;
048: String member_name = name.replace('.', '/') + ".class";
049: if (this .zar == null) {
050: try {
051: this .zar = new java.util.zip.ZipFile(zipname);
052: reopened = true;
053: } catch (java.io.IOException ex) {
054: throw new ClassNotFoundException(
055: "IOException while loading " + member_name
056: + " from ziparchive \"" + name
057: + "\": " + ex.toString());
058: }
059: }
060: java.util.zip.ZipEntry member = zar.getEntry(member_name);
061: if (member == null) {
062: if (reopened) {
063: try {
064: close();
065: } catch (java.io.IOException e) {
066: throw new RuntimeException("failed to close \""
067: + zipname + "\"");
068: }
069: }
070: clas = Class.forName(name);
071: } else {
072: try {
073: int member_size = (int) member.getSize();
074: java.io.InputStream strm = zar
075: .getInputStream(member);
076: byte[] bytes = new byte[member_size];
077: new java.io.DataInputStream(strm).readFully(bytes);
078: clas = defineClass(name, bytes, 0, member_size);
079: loadedClasses.addElement(name);
080: loadedClasses.addElement(clas);
081: if (2 * size == loadedClasses.size())
082: close();
083: } catch (java.io.IOException ex) {
084: throw new ClassNotFoundException(
085: "IOException while loading " + member_name
086: + " from ziparchive \"" + name
087: + "\": " + ex.toString());
088: }
089: }
090: }
091:
092: if (resolve)
093: resolveClass(clas);
094: return clas;
095: }
096:
097: /** Load all classes immediately from zip archive, close archive. */
098: public void loadAllClasses() throws java.io.IOException {
099: java.util.Enumeration e = this .zar.entries();
100: while (e.hasMoreElements()) {
101: java.util.zip.ZipEntry member = (java.util.zip.ZipEntry) e
102: .nextElement();
103: String name = member.getName().replace('/', '.');
104: name = name.substring(0, name.length() - "/class".length());
105: int member_size = (int) member.getSize();
106: java.io.InputStream strm = zar.getInputStream(member);
107: byte[] bytes = new byte[member_size];
108: new java.io.DataInputStream(strm).readFully(bytes);
109: Class clas = defineClass(name, bytes, 0, member_size);
110: loadedClasses.addElement(name);
111: loadedClasses.addElement(clas);
112: }
113: close();
114: }
115:
116: /** Close the zip archive. loadClass will reopen if necessary. */
117: public void close() throws java.io.IOException {
118: if (zar != null)
119: zar.close();
120: zar = null;
121: }
122:
123: }
|