1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 package com.sun.org.apache.bcel.internal.util;
6 
7 /* ====================================================================
8  * The Apache Software License, Version 1.1
9  *
10  * Copyright (c) 2001 The Apache Software Foundation.  All rights
11  * reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  *
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  *
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in
22  *    the documentation and/or other materials provided with the
23  *    distribution.
24  *
25  * 3. The end-user documentation included with the redistribution,
26  *    if any, must include the following acknowledgment:
27  *       "This product includes software developed by the
28  *        Apache Software Foundation (http://www.apache.org/)."
29  *    Alternately, this acknowledgment may appear in the software itself,
30  *    if and wherever such third-party acknowledgments normally appear.
31  *
32  * 4. The names "Apache" and "Apache Software Foundation" and
33  *    "Apache BCEL" must not be used to endorse or promote products
34  *    derived from this software without prior written permission. For
35  *    written permission, please contact apache@apache.org.
36  *
37  * 5. Products derived from this software may not be called "Apache",
38  *    "Apache BCEL", nor may "Apache" appear in their name, without
39  *    prior written permission of the Apache Software Foundation.
40  *
41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52  * SUCH DAMAGE.
53  * ====================================================================
54  *
55  * This software consists of voluntary contributions made by many
56  * individuals on behalf of the Apache Software Foundation.  For more
57  * information on the Apache Software Foundation, please see
58  * <http://www.apache.org/>.
59  */
60 
61 import java.util.*;
62 import java.util.zip.*;
63 import java.io.*;
64 
65 /**
66  * Responsible for loading (class) files from the CLASSPATH. Inspired by
67  * sun.tools.ClassPath.
68  *
69  * @version $Id: ClassPath.java,v 1.4 2007-07-19 04:34:52 ofung Exp $
70  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
71  */
72 public class ClassPath implements Serializable {
73   public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath();
74 
75   private PathEntry[] paths;
76   private String      class_path;
77 
78   /**
79    * Search for classes in given path.
80    */
ClassPath(String class_path)81   public ClassPath(String class_path) {
82     this.class_path = class_path;
83 
84     ArrayList vec = new ArrayList();
85 
86     for(StringTokenizer tok=new StringTokenizer(class_path,
87                             SecuritySupport.getSystemProperty("path.separator"));
88         tok.hasMoreTokens();)
89     {
90       String path = tok.nextToken();
91 
92       if(!path.equals("")) {
93         File file = new File(path);
94 
95         try {
96           if(SecuritySupport.getFileExists(file)) {
97             if(file.isDirectory())
98               vec.add(new Dir(path));
99             else
100               vec.add(new Zip(new ZipFile(file)));
101           }
102         } catch(IOException e) {
103           System.err.println("CLASSPATH component " + file + ": " + e);
104         }
105       }
106     }
107 
108     paths = new PathEntry[vec.size()];
109     vec.toArray(paths);
110   }
111 
112   /**
113    * Search for classes in CLASSPATH.
114    * @deprecated Use SYSTEM_CLASS_PATH constant
115    */
ClassPath()116   public ClassPath() {
117     // this(getClassPath());
118     this("");
119   }
120 
121   /** @return used class path string
122    */
toString()123   public String toString() {
124     return class_path;
125   }
126 
hashCode()127   public int hashCode() {
128     return class_path.hashCode();
129   }
130 
equals(Object o)131   public boolean equals(Object o) {
132     if(o instanceof ClassPath) {
133       return class_path.equals(((ClassPath)o).class_path);
134     }
135 
136     return false;
137   }
138 
getPathComponents(String path, ArrayList list)139   private static final void getPathComponents(String path, ArrayList list) {
140     if(path != null) {
141       StringTokenizer tok = new StringTokenizer(path, File.pathSeparator);
142 
143       while(tok.hasMoreTokens()) {
144         String name = tok.nextToken();
145         File   file = new File(name);
146 
147         if(SecuritySupport.getFileExists(file)) {
148           list.add(name);
149         }
150       }
151     }
152   }
153 
154   /** Checks for class path components in the following properties:
155    * "java.class.path", "sun.boot.class.path", "java.ext.dirs"
156    *
157    * @return class path as used by default by BCEL
158    */
getClassPath()159   public static final String getClassPath() {
160 
161     String class_path, boot_path, ext_path;
162 
163     try {
164       class_path = SecuritySupport.getSystemProperty("java.class.path");
165       boot_path  = SecuritySupport.getSystemProperty("sun.boot.class.path");
166       ext_path   = SecuritySupport.getSystemProperty("java.ext.dirs");
167     }
168     catch (SecurityException e) {
169         return "";
170     }
171 
172     ArrayList list = new ArrayList();
173 
174     getPathComponents(class_path, list);
175     getPathComponents(boot_path, list);
176 
177     ArrayList dirs = new ArrayList();
178     getPathComponents(ext_path, dirs);
179 
180     for(Iterator e = dirs.iterator(); e.hasNext(); ) {
181       File ext_dir = new File((String)e.next());
182       String[] extensions = SecuritySupport.getFileList(ext_dir, new FilenameFilter() {
183         public boolean accept(File dir, String name) {
184           name = name.toLowerCase();
185           return name.endsWith(".zip") || name.endsWith(".jar");
186         }
187       });
188 
189       if(extensions != null)
190         for(int i=0; i < extensions.length; i++)
191           list.add(ext_path + File.separatorChar + extensions[i]);
192     }
193 
194     StringBuffer buf = new StringBuffer();
195 
196     for(Iterator e = list.iterator(); e.hasNext(); ) {
197       buf.append((String)e.next());
198 
199       if(e.hasNext())
200         buf.append(File.pathSeparatorChar);
201     }
202 
203     return buf.toString().intern();
204   }
205 
206   /**
207    * @param name fully qualified class name, e.g. java.lang.String
208    * @return input stream for class
209    */
getInputStream(String name)210   public InputStream getInputStream(String name) throws IOException {
211     return getInputStream(name, ".class");
212   }
213 
214   /**
215    * Return stream for class or resource on CLASSPATH.
216    *
217    * @param name fully qualified file name, e.g. java/lang/String
218    * @param suffix file name ends with suff, e.g. .java
219    * @return input stream for file on class path
220    */
getInputStream(String name, String suffix)221   public InputStream getInputStream(String name, String suffix) throws IOException {
222     InputStream is = null;
223 
224     try {
225       is = getClass().getClassLoader().getResourceAsStream(name + suffix);
226     } catch(Exception e) { }
227 
228     if(is != null)
229       return is;
230 
231     return getClassFile(name, suffix).getInputStream();
232   }
233 
234   /**
235    * @param name fully qualified file name, e.g. java/lang/String
236    * @param suffix file name ends with suff, e.g. .java
237    * @return class file for the java class
238    */
getClassFile(String name, String suffix)239   public ClassFile getClassFile(String name, String suffix) throws IOException {
240     for(int i=0; i < paths.length; i++) {
241       ClassFile cf;
242 
243       if((cf = paths[i].getClassFile(name, suffix)) != null)
244         return cf;
245     }
246 
247     throw new IOException("Couldn't find: " + name + suffix);
248   }
249 
250   /**
251    * @param name fully qualified class name, e.g. java.lang.String
252    * @return input stream for class
253    */
getClassFile(String name)254   public ClassFile getClassFile(String name) throws IOException {
255     return getClassFile(name, ".class");
256   }
257 
258   /**
259    * @param name fully qualified file name, e.g. java/lang/String
260    * @param suffix file name ends with suffix, e.g. .java
261    * @return byte array for file on class path
262    */
getBytes(String name, String suffix)263   public byte[] getBytes(String name, String suffix) throws IOException {
264     InputStream is = getInputStream(name, suffix);
265 
266     if(is == null)
267       throw new IOException("Couldn't find: " + name + suffix);
268 
269     DataInputStream dis   = new DataInputStream(is);
270     byte[]          bytes = new byte[is.available()];
271     dis.readFully(bytes);
272     dis.close(); is.close();
273 
274     return bytes;
275   }
276 
277   /**
278    * @return byte array for class
279    */
getBytes(String name)280   public byte[] getBytes(String name) throws IOException {
281     return getBytes(name, ".class");
282   }
283 
284   /**
285    * @param name name of file to search for, e.g. java/lang/String.java
286    * @return full (canonical) path for file
287    */
getPath(String name)288   public String getPath(String name) throws IOException {
289     int    index  = name.lastIndexOf('.');
290     String suffix = "";
291 
292     if(index > 0) {
293       suffix = name.substring(index);
294       name   = name.substring(0, index);
295     }
296 
297     return getPath(name, suffix);
298   }
299 
300   /**
301    * @param name name of file to search for, e.g. java/lang/String
302    * @param suffix file name suffix, e.g. .java
303    * @return full (canonical) path for file, if it exists
304    */
getPath(String name, String suffix)305   public String getPath(String name, String suffix) throws IOException {
306     return getClassFile(name, suffix).getPath();
307   }
308 
309   private static abstract class PathEntry implements Serializable {
getClassFile(String name, String suffix)310     abstract ClassFile getClassFile(String name, String suffix) throws IOException;
311   }
312 
313   /** Contains information about file/ZIP entry of the Java class.
314    */
315   public interface ClassFile {
316     /** @return input stream for class file.
317      */
getInputStream()318     public abstract InputStream getInputStream() throws IOException;
319 
320     /** @return canonical path to class file.
321      */
getPath()322     public abstract String getPath();
323 
324     /** @return base path of found class, i.e. class is contained relative
325      * to that path, which may either denote a directory, or zip file
326      */
getBase()327     public abstract String getBase();
328 
329     /** @return modification time of class file.
330      */
getTime()331     public abstract long getTime();
332 
333     /** @return size of class file.
334      */
getSize()335     public abstract long getSize();
336   }
337 
338   private static class Dir extends PathEntry {
339     private String dir;
340 
Dir(String d)341     Dir(String d) { dir = d; }
342 
getClassFile(String name, String suffix)343     ClassFile getClassFile(String name, String suffix) throws IOException {
344       final File file = new File(dir + File.separatorChar +
345                                  name.replace('.', File.separatorChar) + suffix);
346 
347       return SecuritySupport.getFileExists(file)? new ClassFile() {
348         public InputStream getInputStream() throws IOException { return new FileInputStream(file); }
349 
350         public String      getPath()        { try {
351           return file.getCanonicalPath();
352         } catch(IOException e) { return null; }
353 
354         }
355         public long        getTime()        { return file.lastModified(); }
356         public long        getSize()        { return file.length(); }
357         public String getBase() {  return dir;  }
358 
359       } : null;
360     }
361 
toString()362     public String toString() { return dir; }
363   }
364 
365   private static class Zip extends PathEntry {
366     private ZipFile zip;
367 
368     Zip(ZipFile z) { zip = z; }
369 
370     ClassFile getClassFile(String name, String suffix) throws IOException {
371       final ZipEntry entry = zip.getEntry(name.replace('.', '/') + suffix);
372 
373       return (entry != null)? new ClassFile() {
374         public InputStream getInputStream() throws IOException { return zip.getInputStream(entry); }
375         public String      getPath()        { return entry.toString(); }
376         public long        getTime()        { return entry.getTime(); }
377         public long        getSize()       { return entry.getSize(); }
378         public String getBase() {
379           return zip.getName();
380         }
381       } : null;
382     }
383   }
384 }
385