| CLPath.java |
1 // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2
3 package jminusminus;
4
5 import java.io.*;
6 import java.util.ArrayList;
7 import java.util.StringTokenizer;
8 import java.util.zip.ZipEntry;
9 import java.util.zip.ZipFile;
10
11 /**
12 * This class can be used to locate and load system, extension, and user-defined class files from
13 * directories and zip (jar) files.
14 */
15 class CLPath {
16 // Stores the individual directories, zip, and jar files from the class path.
17 private ArrayList<String> dirs;
18
19 /**
20 * Returns a list of conceptual directories defining the class path.
21 *
22 * @param classPath the directory names defining the class path.
23 * @return a list of conceptual directories defining the class path.
24 */
25 private ArrayList<String> loadClassPath(String classPath) {
26 ArrayList<String> container = new ArrayList<String>();
27
28 // Add directories/jars/zips from the classpath.
29 StringTokenizer entries = new StringTokenizer(classPath, File.pathSeparator);
30 while (entries.hasMoreTokens()) {
31 container.add(entries.nextToken());
32 }
33
34 // Add system directories.
35 if (System.getProperty("sun.boot.class.path") != null) {
36 entries = new StringTokenizer(System.getProperty("sun.boot.class.path"),
37 File.pathSeparator);
38 while (entries.hasMoreTokens()) {
39 container.add(entries.nextToken());
40 }
41 } else {
42 String dir = System.getProperty("java.home") + File.separatorChar + "lib" +
43 File.separatorChar + "rt.jar";
44 container.add(dir);
45 }
46 return container;
47 }
48
49 /**
50 * Constructs a CLPath object.
51 */
52 public CLPath() {
53 this(null, null);
54 }
55
56 /**
57 * Constructs a CLPath object given the directory names defining the path and the directory
58 * for the Java extension classes.
59 *
60 * @param path the directory names defining the class path, separated by path separator.
61 * @param extdir the directory for the Java extension classes.
62 */
63 public CLPath(String path, String extdir) {
64 if (path == null) {
65 // No path specified, use CLASSPATH.
66 path = System.getProperty("java.class.path");
67 }
68 if (path == null) {
69 // Last resort, use current directory.
70 path = ".";
71 }
72 dirs = loadClassPath(path);
73 if (extdir == null) {
74 // Java extension classes.
75 extdir = System.getProperty("java.ext.dirs");
76 }
77 if (extdir != null) {
78 File extDirectory = new File(extdir);
79 if (extDirectory.isDirectory()) {
80 File[] extFiles = extDirectory.listFiles();
81 for (File file : extFiles) {
82 if (file.isFile() &&
83 (file.getName().endsWith(".zip") || file.getName().endsWith(".jar"))) {
84 dirs.add(file.getName());
85 } else {
86 // Wrong suffix; ignore.
87 }
88 }
89 }
90 }
91 }
92
93 /**
94 * Returns a CLInputStream instance for the class with specified name (fully-qualified;
95 * tokens separated by '/') or null if the class was not found.
96 *
97 * @param name the fully-qualified name of the class (eg, java/util/ArrayList).
98 * @return a CLInputStream instance for the class with specified name or null if the class
99 * was not found.
100 */
101 public CLInputStream loadClass(String name) {
102 CLInputStream reader = null;
103 for (int i = 0; i < dirs.size(); i++) {
104 String dir = dirs.get(i);
105 File file = new File(dir);
106 if (file.isDirectory()) {
107 File theClass = new File(dir, name.replace('/', File.separatorChar) + ".class");
108 if (theClass.canRead()) {
109 try {
110 reader = new CLInputStream(new BufferedInputStream(new
111 FileInputStream(theClass)));
112 } catch (FileNotFoundException e) {
113 // Ignore
114 }
115 }
116 } else if (file.isFile()) {
117 try {
118 ZipFile zip = new ZipFile(dir);
119 ZipEntry entry = zip.getEntry(name + ".class");
120 if (entry != null) {
121 reader = new CLInputStream(zip.getInputStream(entry));
122 }
123 } catch (IOException e) {
124 // Ignore
125 }
126 } else {
127 // Bogus entry; ignore
128 }
129 }
130 return reader;
131 }
132 }
133
134 /**
135 * This class inherits from java.io.DataInputStream and provides an extra function for reading
136 * unsigned int from the input stream, which is required for reading Java class files.
137 */
138 class CLInputStream extends DataInputStream {
139 /**
140 * Constructs a CLInputStream object from the specified input stream.
141 *
142 * @param in input stream.
143 */
144 public CLInputStream(InputStream in) {
145 super(in);
146 }
147
148 /**
149 * Reads four input bytes and returns a {@code long} value in the range 0 through 4294967295.
150 * Let a, b, c, d be the four bytes. The value returned is:
151 *
152 * <pre>
153 * ( b[ 0 ] & 0xFF ) << 24 ) |
154 * ( ( b[ 1 ] & 0xFF ) << 16 ) |
155 * ( ( b[ 2 ] & 0xFF ) << 8 ) |
156 * ( b[ 3 ] & 0xFF )
157 * </pre>
158 *
159 * @return the unsigned 32-bit value.
160 * @throws EOFException if this stream reaches the end before reading all the bytes.
161 * @throws IOException if an I/O error occurs.
162 */
163 public long readUnsignedInt() throws IOException {
164 byte[] b = new byte[4];
165 long mask = 0xFF, l;
166 in.read(b);
167 l = ((b[0] & mask) << 24) | ((b[1] & mask) << 16) | ((b[2] & mask) << 8) | (b[3] & mask);
168 return l;
169 }
170 }
171