KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > SourceLocator


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 2004 Ondrej Lhotak
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 package soot;
21 import soot.options.*;
22 import java.util.*;
23 import java.util.zip.*;
24 import java.io.*;
25
26 /** Provides utility methods to retrieve an input stream for a class name, given
27  * a classfile, or jimple or baf output files. */

28 public class SourceLocator
29 {
30     public SourceLocator( Singletons.Global g ) {}
31     public static SourceLocator v() { return G.v().soot_SourceLocator(); }
32
33     /** Given a class name, uses the soot-class-path to return a ClassSource for the given class. */
34     public ClassSource getClassSource(String JavaDoc className)
35     {
36         if( classPath == null ) {
37             classPath = explodeClassPath(Scene.v().getSootClassPath());
38         }
39         if( classProviders == null ) {
40             setupClassProviders();
41         }
42         for( Iterator cpIt = classProviders.iterator(); cpIt.hasNext(); ) {
43             final ClassProvider cp = (ClassProvider) cpIt.next();
44             ClassSource ret = cp.find(className);
45             if( ret != null ) return ret;
46         }
47         return null;
48     }
49
50     private void setupClassProviders() {
51         classProviders = new LinkedList();
52         switch( Options.v().src_prec() ) {
53             case Options.src_prec_class:
54                 classProviders.add(new CoffiClassProvider());
55                 classProviders.add(new JimpleClassProvider());
56                 classProviders.add(new JavaClassProvider());
57                 break;
58             case Options.src_prec_only_class:
59                 classProviders.add(new CoffiClassProvider());
60                 break;
61             case Options.src_prec_java:
62                 classProviders.add(new JavaClassProvider());
63                 classProviders.add(new CoffiClassProvider());
64                 classProviders.add(new JimpleClassProvider());
65                 break;
66             case Options.src_prec_jimple:
67                 classProviders.add(new JimpleClassProvider());
68                 classProviders.add(new CoffiClassProvider());
69                 classProviders.add(new JavaClassProvider());
70                 break;
71             default:
72                 throw new RuntimeException JavaDoc("Other source precedences are not currently supported.");
73         }
74     }
75
76     private List classProviders;
77     public void setClassProviders( List classProviders ) {
78         this.classProviders = classProviders;
79     }
80
81     private List classPath;
82     public List classPath() { return classPath; }
83     public void invalidateClassPath() {
84         classPath = null;
85     }
86
87     private List sourcePath;
88     public List sourcePath() {
89         if( sourcePath == null ) {
90             sourcePath = new ArrayList();
91             for( Iterator dirIt = classPath.iterator(); dirIt.hasNext(); ) {
92                 final String JavaDoc dir = (String JavaDoc) dirIt.next();
93                 if( !isJar(dir) ) sourcePath.add(dir);
94             }
95         }
96         return sourcePath;
97     }
98
99     private boolean isJar(String JavaDoc path) {
100     File f = new File(path);
101     if(f.isFile() && f.canRead()) {
102         if(path.endsWith("zip") || path.endsWith("jar")) {
103         return true;
104         } else {
105         G.v().out.println("Warning: the following soot-classpath entry is not a supported archive file (must be .zip or .jar): " + path);
106         }
107     }
108     return false;
109     }
110
111     public List getClassesUnder(String JavaDoc aPath) {
112         List fileNames = new ArrayList();
113
114     if (isJar(aPath)) {
115         List inputExtensions = new ArrayList(2);
116             inputExtensions.add(".class");
117             inputExtensions.add(".jimple");
118             inputExtensions.add(".java");
119
120         try {
121         ZipFile archive = new ZipFile(aPath);
122         for (Enumeration entries = archive.entries();
123              entries.hasMoreElements(); ) {
124             ZipEntry entry = (ZipEntry) entries.nextElement();
125             String JavaDoc entryName = entry.getName();
126             int extensionIndex = entryName.lastIndexOf('.');
127             if (extensionIndex >= 0) {
128             String JavaDoc entryExtension = entryName.substring(extensionIndex);
129             if (inputExtensions.contains(entryExtension)) {
130                 entryName = entryName.substring(0, extensionIndex);
131                 entryName = entryName.replace('/', '.');
132                 fileNames.add(entryName);
133             }
134             }
135         }
136         } catch(IOException e) {
137         G.v().out.println("Error reading " + aPath + ": "
138                   + e.toString());
139         throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
140         }
141     } else {
142         File file = new File(aPath);
143
144         File[] files = file.listFiles();
145         if (files == null) {
146         files = new File[1];
147         files[0] = file;
148         }
149
150         for (int i = 0; i < files.length; i++) {
151         if (files[i].isDirectory()) {
152             List l =
153             getClassesUnder(
154                     aPath + File.separatorChar + files[i].getName());
155             Iterator it = l.iterator();
156             while (it.hasNext()) {
157             String JavaDoc s = (String JavaDoc) it.next();
158             fileNames.add(files[i].getName() + "." + s);
159             }
160         } else {
161             String JavaDoc fileName = files[i].getName();
162
163             if (fileName.endsWith(".class")) {
164             int index = fileName.lastIndexOf(".class");
165             fileNames.add(fileName.substring(0, index));
166             }
167
168             if (fileName.endsWith(".jimple")) {
169             int index = fileName.lastIndexOf(".jimple");
170             fileNames.add(fileName.substring(0, index));
171             }
172
173             if (fileName.endsWith(".java")) {
174             int index = fileName.lastIndexOf(".java");
175             fileNames.add(fileName.substring(0, index));
176             }
177         }
178         }
179     }
180         return fileNames;
181     }
182
183     public String JavaDoc getFileNameFor(SootClass c, int rep) {
184         if (rep == Options.output_format_none)
185             return null;
186
187         StringBuffer JavaDoc b = new StringBuffer JavaDoc();
188
189         if( !Options.v().output_jar() ) {
190             b.append(getOutputDir());
191         }
192
193         if ((b.length() > 0) && (b.charAt(b.length() - 1) != File.separatorChar))
194             b.append(File.separatorChar);
195
196         if (rep != Options.output_format_dava) {
197             if(rep == Options.output_format_class) {
198                 b.append(c.getName().replace('.', File.separatorChar));
199             } else {
200                 b.append(c.getName());
201             }
202             b.append(getExtensionFor(rep));
203
204             return b.toString();
205         }
206
207         b.append("dava");
208         b.append(File.separatorChar);
209         {
210             String JavaDoc classPath = b.toString() + "classes";
211             File dir = new File(classPath);
212
213             if (!dir.exists())
214                 try {
215                     dir.mkdirs();
216                 } catch (SecurityException JavaDoc se) {
217                     G.v().out.println("Unable to create " + classPath);
218                     throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
219                 }
220         }
221
222         b.append("src");
223         b.append(File.separatorChar);
224
225         String JavaDoc fixedPackageName = c.getJavaPackageName();
226         if (fixedPackageName.equals("") == false) {
227             b.append(fixedPackageName.replace('.', File.separatorChar));
228             b.append(File.separatorChar);
229         }
230
231         {
232             String JavaDoc path = b.toString();
233             File dir = new File(path);
234
235             if (!dir.exists())
236                 try {
237                     dir.mkdirs();
238                 } catch (SecurityException JavaDoc se) {
239                     G.v().out.println("Unable to create " + path);
240                     throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
241                 }
242         }
243
244         b.append(c.getShortJavaStyleName());
245         b.append(".java");
246
247         return b.toString();
248     }
249
250     /* This is called after sootClassPath has been defined. */
251     public Set classesInDynamicPackage(String JavaDoc str) {
252         HashSet set = new HashSet(0);
253         StringTokenizer strtok = new StringTokenizer(
254                 Scene.v().getSootClassPath(), String.valueOf(File.pathSeparatorChar));
255         while (strtok.hasMoreTokens()) {
256             String JavaDoc path = strtok.nextToken();
257
258             // For jimple files
259
List l = getClassesUnder(path);
260             for( Iterator filenameIt = l.iterator(); filenameIt.hasNext(); ) {
261                 final String JavaDoc filename = (String JavaDoc) filenameIt.next();
262                 if (filename.startsWith(str))
263                     set.add(filename);
264             }
265
266             // For class files;
267
path = path + File.pathSeparatorChar;
268             StringTokenizer tokenizer = new StringTokenizer(str, ".");
269             while (tokenizer.hasMoreTokens()) {
270                 path = path + tokenizer.nextToken();
271                 if (tokenizer.hasMoreTokens())
272                     path = path + File.pathSeparatorChar;
273             }
274             l = getClassesUnder(path);
275             for (Iterator it = l.iterator(); it.hasNext();)
276                 set.add(str + "." + ((String JavaDoc) it.next()));
277         }
278         return set;
279     }
280
281     public String JavaDoc getExtensionFor(int rep) {
282         switch (rep) {
283             case Options.output_format_baf: return ".baf";
284             case Options.output_format_b: return ".b";
285             case Options.output_format_jimple: return ".jimple";
286             case Options.output_format_jimp: return ".jimp";
287             case Options.output_format_shimple: return ".shimple";
288             case Options.output_format_shimp: return ".shimp";
289             case Options.output_format_grimp: return ".grimp";
290             case Options.output_format_grimple: return ".grimple";
291             case Options.output_format_class: return ".class";
292             case Options.output_format_dava: return ".java";
293             case Options.output_format_jasmin: return ".jasmin";
294             case Options.output_format_xml: return ".xml";
295             default:
296                 throw new RuntimeException JavaDoc();
297         }
298     }
299
300     public String JavaDoc getOutputDir() {
301         String JavaDoc ret = Options.v().output_dir();
302         if( ret.length() == 0 ) ret = "sootOutput";
303         File dir = new File(ret);
304
305         if (!dir.exists()) {
306             try {
307                 if( !Options.v().output_jar() ) {
308                     dir.mkdirs();
309                 }
310             } catch (SecurityException JavaDoc se) {
311                 G.v().out.println("Unable to create " + ret);
312                 throw new CompilationDeathException(CompilationDeathException.COMPILATION_ABORTED);
313             }
314         }
315         return ret;
316     }
317
318     private boolean windows = System.getProperty("os.name").startsWith("Windows");
319     private String JavaDoc cwd = System.getProperty("user.dir");
320
321     /** Explodes a class path into a list of individual class path entries. */
322     protected List explodeClassPath( String JavaDoc classPath ) {
323         List ret = new ArrayList();
324
325         StringTokenizer tokenizer =
326             new StringTokenizer(classPath, File.pathSeparator);
327         while( tokenizer.hasMoreTokens() ) {
328             String JavaDoc originalDir = tokenizer.nextToken();
329             String JavaDoc canonicalDir;
330             try {
331                 canonicalDir = new File(originalDir).getCanonicalPath();
332                 ret.add(canonicalDir);
333             } catch( IOException e ) {
334                 throw new CompilationDeathException( "Couldn't resolve classpath entry "+originalDir+": "+e );
335             }
336         }
337         return ret;
338     }
339     public static class FoundFile {
340         FoundFile( ZipFile zipFile, ZipEntry entry ) {
341             this.zipFile = zipFile;
342             this.entry = entry;
343         }
344         FoundFile( File file ) {
345             this.file = file;
346         }
347         public File file;
348         public ZipFile zipFile;
349         public ZipEntry entry;
350         public InputStream inputStream() {
351             try {
352                 if( file != null ) return new FileInputStream(file);
353                 return doJDKBugWorkaround(zipFile.getInputStream(entry),
354                         entry.getSize());
355             } catch( IOException e ) {
356                 throw new RuntimeException JavaDoc( "Caught IOException "+e );
357             }
358         }
359     }
360
361     private static InputStream doJDKBugWorkaround(InputStream is, long size) throws IOException {
362     
363     int sz = (int) size;
364     byte[] buf = new byte[sz];
365                 
366                     
367     final int N = 1024;
368     int ln = 0;
369     int count = 0;
370     while (sz > 0 &&
371            (ln = is.read(buf, count, Math.min(N, sz))) != -1) {
372         count += ln;
373         sz -= ln;
374     }
375     return new ByteArrayInputStream(buf);
376     }
377
378
379     /** Searches for a file with the given name in the exploded classPath. */
380     public FoundFile lookupInClassPath( String JavaDoc fileName ) {
381         for( Iterator dirIt = classPath.iterator(); dirIt.hasNext(); ) {
382             final String JavaDoc dir = (String JavaDoc) dirIt.next();
383             FoundFile ret;
384             if(isJar(dir)) {
385                 ret = lookupInJar(dir, fileName);
386             } else {
387                 ret = lookupInDir(dir, fileName);
388             }
389             if( ret != null ) return ret;
390         }
391         return null;
392     }
393     private FoundFile lookupInDir(String JavaDoc dir, String JavaDoc fileName) {
394         File f = new File( dir+File.separatorChar+fileName );
395         if( f.canRead() ) {
396             return new FoundFile(f);
397         }
398         return null;
399     }
400     private FoundFile lookupInJar(String JavaDoc jar, String JavaDoc fileName) {
401         try {
402             ZipFile jarFile = new ZipFile(jar);
403             ZipEntry entry = jarFile.getEntry(fileName);
404             if( entry == null ) return null;
405             return new FoundFile(jarFile, entry);
406         } catch( IOException e ) {
407             throw new RuntimeException JavaDoc( "Caught IOException "+e+" looking in jar file "+jar+" for file "+fileName );
408         }
409     }
410     private HashMap sourceToClassMap;
411
412     public HashMap getSourceToClassMap(){
413         return sourceToClassMap;
414     }
415     public void setSourceToClassMap(HashMap map){
416         sourceToClassMap = map;
417     }
418     public void addToSourceToClassMap(String JavaDoc key, String JavaDoc val) {
419         sourceToClassMap.put(key, val);
420     }
421     /** Returns the name of the class in which the (possibly inner) class
422      * className appears. */

423     public String JavaDoc getSourceForClass( String JavaDoc className ) {
424         String JavaDoc javaClassName = className;
425         if (className.indexOf("$") != -1) {
426             // class is an inner class and will be in
427
// Outer of Outer$Inner
428
javaClassName = className.substring(0, className.indexOf("$"));
429             //System.out.println("cut off inner class: look for: "+javaClassName);
430
}
431         // always do this because an inner class could be in a class
432
// thats in the map
433
if (sourceToClassMap != null) {
434             //System.out.println("in source map: "+sourceToClassMap);
435
if (sourceToClassMap.get(javaClassName) != null) {
436                 javaClassName = (String JavaDoc)sourceToClassMap.get(javaClassName);
437             }
438         }
439         return javaClassName;
440     }
441 }
442
443
Popular Tags