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: /* #ifdef JAVA5 */
022: // /* A list of pairs of (name, class) of already loaded classes. */
023: // private java.util.Vector<Object> loadedClasses;
024: /* #else */
025: private java.util.Vector loadedClasses;
026:
027: /* #endif */
028:
029: public ZipLoader(String name) throws java.io.IOException {
030: this .zipname = name;
031: this .zar = new java.util.zip.ZipFile(name);
032: size = 0;
033: java.util.Enumeration e = this .zar.entries();
034: while (e.hasMoreElements()) {
035: java.util.zip.ZipEntry ent = (java.util.zip.ZipEntry) e
036: .nextElement();
037: if (!ent.isDirectory())
038: size++;
039: }
040: /* #ifdef JAVA5 */
041: // loadedClasses = new java.util.Vector<Object>(size);
042: /* #else */
043: loadedClasses = new java.util.Vector(size);
044: /* #endif */
045: }
046:
047: public Class loadClass(String name, boolean resolve)
048: throws ClassNotFoundException {
049: Class clas;
050: int index = loadedClasses.indexOf(name);
051: if (index >= 0)
052: clas = (Class) loadedClasses.elementAt(index + 1);
053: else if (zar == null && loadedClasses.size() == 2 * size)
054: clas = Class.forName(name);
055: else {
056: boolean reopened = false;
057: String member_name = name.replace('.', '/') + ".class";
058: if (this .zar == null) {
059: try {
060: this .zar = new java.util.zip.ZipFile(zipname);
061: reopened = true;
062: } catch (java.io.IOException ex) {
063: throw new ClassNotFoundException(
064: "IOException while loading " + member_name
065: + " from ziparchive \"" + name
066: + "\": " + ex.toString());
067: }
068: }
069: java.util.zip.ZipEntry member = zar.getEntry(member_name);
070: if (member == null) {
071: if (reopened) {
072: try {
073: close();
074: } catch (java.io.IOException e) {
075: throw new RuntimeException("failed to close \""
076: + zipname + "\"");
077: }
078: }
079: clas = Class.forName(name);
080: } else {
081: try {
082: int member_size = (int) member.getSize();
083: java.io.InputStream strm = zar
084: .getInputStream(member);
085: byte[] bytes = new byte[member_size];
086: new java.io.DataInputStream(strm).readFully(bytes);
087: clas = defineClass(name, bytes, 0, member_size);
088: loadedClasses.addElement(name);
089: loadedClasses.addElement(clas);
090: if (2 * size == loadedClasses.size())
091: close();
092: } catch (java.io.IOException ex) {
093: throw new ClassNotFoundException(
094: "IOException while loading " + member_name
095: + " from ziparchive \"" + name
096: + "\": " + ex.toString());
097: }
098: }
099: }
100:
101: if (resolve)
102: resolveClass(clas);
103: return clas;
104: }
105:
106: /** Load all classes immediately from zip archive, close archive.
107: * @return main class (1st class in archive).
108: */
109: public Class loadAllClasses() throws java.io.IOException {
110: java.util.Enumeration e = this .zar.entries();
111: Class mainClass = null;
112: while (e.hasMoreElements()) {
113: java.util.zip.ZipEntry member = (java.util.zip.ZipEntry) e
114: .nextElement();
115: String name = member.getName().replace('/', '.');
116: name = name.substring(0, name.length() - "/class".length());
117: int member_size = (int) member.getSize();
118: java.io.InputStream strm = zar.getInputStream(member);
119: byte[] bytes = new byte[member_size];
120: new java.io.DataInputStream(strm).readFully(bytes);
121: Class clas = defineClass(name, bytes, 0, member_size);
122: if (mainClass == null)
123: mainClass = clas;
124: loadedClasses.addElement(name);
125: loadedClasses.addElement(clas);
126: }
127: close();
128: return mainClass;
129: }
130:
131: /** Close the zip archive - loadClass will reopen if necessary. */
132: public void close() throws java.io.IOException {
133: if (zar != null)
134: zar.close();
135: zar = null;
136: }
137:
138: }
|