1 /*
2  * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 /*
26  * Portions Copyright (c) 2011 Jonas Maebe
27  */
28 
29 
30 package fpc.tools.javapp;
31 
32 import java.util.*;
33 import java.io.*;
34 import java.util.jar.*;
35 
36 
37 /**
38  * Strores flag values according to command line options
39  * and sets path where to find classes.
40  *
41  * @author  Sucheta Dambalkar
42  */
43 public class JavapEnvironment {
44 
45     //Access flags
46     public static final int PRIVATE = 0;
47     public static final int PROTECTED  = 1;
48     public static final int PACKAGE = 2;
49     public static final int PUBLIC  = 3;
50 
51     //search path flags.
52     private static final int start = 0;
53     private static final int  cmdboot= 1;
54     private static final int sunboot = 2;
55     private static final int  javaclass= 3;
56     private static final int  cmdextdir= 4;
57     private static final int  javaext= 5;
58     private static final int  cmdclasspath= 6;
59     private static final int  envclasspath= 7;
60     private static final int  javaclasspath= 8;
61     private static final int  currentdir = 9;
62 
63 
64     // JavapEnvironment flag settings
65     boolean showLineAndLocal = false;
66     int showAccess = PACKAGE;
67     boolean showVerbose = false;
68     String classPathString = null;
69     String bootClassPathString = null;
70     String extDirsString = null;
71     boolean extDirflag;
72     boolean nothingToDo = true;
73     boolean showallAttr = false;
74     boolean generateInclude = false;
75     String classpath = null;
76     String outputName = "java";
77     ArrayList<String> excludePrefixes;
78     ArrayList<String> skelPrefixes;
79     String prefix_constant = "";
80     String prefix_field = "f";
81     String prefix_innerclass = "Inner";
82     boolean addVarOverloads = false;
83 
JavapEnvironment()84     public JavapEnvironment() {
85     	excludePrefixes = new ArrayList<String>();
86     	skelPrefixes = new ArrayList<String>();
87     }
88 
89     /**
90      *  According to which flags are set,
91      *  returns file input stream for classfile to disassemble.
92      */
93 
getFileInputStream(String Name)94     public InputStream getFileInputStream(String Name){
95         InputStream fileInStream = null;
96         int searchpath = cmdboot;
97         extDirflag = false;
98         try{
99             if(searchpath == cmdboot){
100                 if(bootClassPathString != null){
101                     //search in specified bootclasspath.
102                     classpath = bootClassPathString;
103                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
104                     //no classes found in search path.
105                     else searchpath = cmdextdir;
106                 }
107                 else searchpath = sunboot;
108             }
109 
110             if(searchpath == sunboot){
111                 if(System.getProperty("sun.boot.class.path") != null){
112                     //search in sun.boot.class.path
113                     classpath = System.getProperty("sun.boot.class.path");
114                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
115                     //no classes found in search path
116                     else searchpath = cmdextdir;
117                 }
118                 else searchpath = javaclass;
119             }
120 
121             if(searchpath == javaclass){
122                 if(System.getProperty("java.class.path") != null){
123                     //search in java.class.path
124                     classpath =System.getProperty("java.class.path");
125                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
126                     //no classes found in search path
127                     else searchpath = cmdextdir;
128                 }
129                 else searchpath = cmdextdir;
130             }
131 
132             if(searchpath == cmdextdir){
133                 if(extDirsString != null){
134                     //search in specified extdir.
135                     classpath = extDirsString;
136                     extDirflag = true;
137                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
138                     //no classes found in search path
139                     else {
140                         searchpath = cmdclasspath;
141                         extDirflag = false;
142                     }
143                 }
144                 else searchpath = javaext;
145             }
146 
147             if(searchpath == javaext){
148                 if(System.getProperty("java.ext.dirs") != null){
149                     //search in java.ext.dirs
150                     classpath = System.getProperty("java.ext.dirs");
151                     extDirflag = true;
152                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
153                     //no classes found in search path
154                     else {
155                         searchpath = cmdclasspath;
156                         extDirflag = false;
157                     }
158                 }
159                 else searchpath = cmdclasspath;
160             }
161             if(searchpath == cmdclasspath){
162                 if(classPathString != null){
163                     //search in specified classpath.
164                     classpath = classPathString;
165                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
166                     //no classes found in search path
167                     else searchpath = 8;
168                 }
169                 else searchpath = envclasspath;
170             }
171 
172             if(searchpath == envclasspath){
173                 if(System.getProperty("env.class.path")!= null){
174                     //search in env.class.path
175                     classpath = System.getProperty("env.class.path");
176                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
177                     //no classes found in search path.
178                     else searchpath = javaclasspath;
179                 }
180                 else searchpath = javaclasspath;
181             }
182 
183             if(searchpath == javaclasspath){
184                 if(("application.home") == null){
185                     //search in java.class.path
186                     classpath = System.getProperty("java.class.path");
187                     if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
188                     //no classes found in search path.
189                     else searchpath = currentdir;
190                 }
191                 else searchpath = currentdir;
192             }
193 
194             if(searchpath == currentdir){
195                 classpath = ".";
196                 //search in current dir.
197                 if((fileInStream = resolvefilename(Name)) != null) return fileInStream;
198                 else {
199                     //no classes found in search path.
200                     error("Could not find "+ Name);
201                     System.exit(1);
202                 }
203             }
204         }catch(SecurityException excsec){
205             excsec.printStackTrace();
206             error("fatal exception");
207         }catch(NullPointerException excnull){
208             excnull.printStackTrace();
209             error("fatal exception");
210         }catch(IllegalArgumentException excill){
211             excill.printStackTrace();
212             error("fatal exception");
213         }
214 
215         return null;
216     }
217 
218 
error(String msg)219     public void error(String msg) {
220         System.err.println("ERROR:" +msg);
221     }
222 
223     /**
224      * Resolves file name for classfile to disassemble.
225      */
resolvefilename(String name)226     public InputStream resolvefilename(String name){
227         String classname = name.replace('.', '/') + ".class";
228         while (true) {
229             InputStream instream = extDirflag
230                 ? resolveExdirFilename(classname)
231                 : resolveclasspath(classname);
232             if (instream != null)
233                 return instream;
234             int lastindex = classname.lastIndexOf('/');
235             if (lastindex == -1) return null;
236             classname = classname.substring(0, lastindex) + "$" +
237                 classname.substring(lastindex + 1);
238         }
239     }
240 
241     /**
242      * Resolves file name for classfile to disassemble if flag exdir is set.
243      */
resolveExdirFilename(String classname)244     public InputStream resolveExdirFilename(String classname){
245         if(classpath.indexOf(File.pathSeparator) != -1){
246             //separates path
247             StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
248             while(st.hasMoreTokens()){
249                 String path = st.nextToken();
250                 InputStream in = resolveExdirFilenamehelper(path, classname);
251                 if (in != null)
252                     return in;
253             }
254         }else return (resolveExdirFilenamehelper(classpath, classname));
255 
256         return null;
257     }
258 
259     /**
260      * Resolves file name for classfile to disassemble.
261      */
resolveclasspath(String classname)262     public InputStream resolveclasspath(String classname){
263         if(classpath.indexOf(File.pathSeparator) != -1){
264             StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
265             //separates path.
266             while(st.hasMoreTokens()){
267                 String path = (st.nextToken()).trim();
268                 InputStream in = resolveclasspathhelper(path, classname);
269                 if(in != null) return in;
270 
271             }
272             return null;
273         }
274         else return (resolveclasspathhelper(classpath, classname));
275     }
276 
277 
278     /**
279      * Returns file input stream for classfile to disassemble if exdir is set.
280      */
resolveExdirFilenamehelper(String path, String classname)281     public InputStream resolveExdirFilenamehelper(String path, String classname){
282         File fileobj = new File(path);
283         if(fileobj.isDirectory()){
284             // gets list of files in that directory.
285             File[] filelist = fileobj.listFiles();
286             for(int i = 0; i < filelist.length; i++){
287                 try{
288                     //file is a jar file.
289                     if(filelist[i].toString().endsWith(".jar")){
290                         JarFile jfile = new JarFile(filelist[i]);
291                         if((jfile.getEntry(classname)) != null){
292 
293                             InputStream filein = jfile.getInputStream(jfile.getEntry(classname));
294                             int bytearraysize = filein.available();
295                             byte []b =  new byte[bytearraysize];
296                             int totalread = 0;
297                             while(totalread < bytearraysize){
298                                 totalread += filein.read(b, totalread, bytearraysize-totalread);
299                             }
300                             InputStream inbyte = new ByteArrayInputStream(b);
301                             filein.close();
302                             return inbyte;
303                         }
304                     } else {
305                         //not a jar file.
306                         String filename = path+"/"+ classname;
307                         File file = new File(filename);
308                         if(file.isFile()){
309                             return (new FileInputStream(file));
310                         }
311                     }
312                 }catch(FileNotFoundException fnexce){
313                     fnexce.printStackTrace();
314                     error("cant read file");
315                     error("fatal exception");
316                 }catch(IOException ioexc){
317                     ioexc.printStackTrace();
318                     error("fatal exception");
319                 }
320             }
321         }
322 
323         return null;
324     }
325 
326 
327     /**
328      * Returns file input stream for classfile to disassemble.
329      */
resolveclasspathhelper(String path, String classname)330     public InputStream resolveclasspathhelper(String path, String classname){
331         File fileobj = new File(path);
332         try{
333             if(fileobj.isDirectory()){
334                 //is a directory.
335                 String filename = path+"/"+ classname;
336                 File file = new File(filename);
337                 if(file.isFile()){
338                     return (new FileInputStream(file));
339                 }
340 
341             }else if(fileobj.isFile()){
342                 if(fileobj.toString().endsWith(".jar")){
343                     //is a jar file.
344                     JarFile jfile = new JarFile(fileobj);
345                     if((jfile.getEntry(classname)) != null){
346                         InputStream filein = jfile.getInputStream(jfile.getEntry(classname));
347                         int bytearraysize = filein.available();
348                         byte []b =  new byte[bytearraysize];
349                         int totalread = 0;
350                         while(totalread < bytearraysize){
351                                 totalread += filein.read(b, totalread, bytearraysize-totalread);
352                         }
353                         InputStream inbyte = new ByteArrayInputStream(b);
354                         filein.close();
355                          return inbyte;
356                     }
357                 }
358             }
359         }catch(FileNotFoundException fnexce){
360             fnexce.printStackTrace();
361             error("cant read file");
362             error("fatal exception");
363         }catch(IOException ioexce){
364             ioexce.printStackTrace();
365             error("fatal exception");
366         }
367         return null;
368     }
369 
370 
371 
getJarEntries(String jarname)372     protected SortedSet<String> getJarEntries(String jarname) {
373     	SortedSet<String> res = new TreeSet<String>();
374 
375     	try{
376     		JarFile jfile = new JarFile(jarname);
377     		Enumeration<JarEntry> entries = jfile.entries();
378     		while (entries.hasMoreElements()) {
379     			JarEntry entry = entries.nextElement();
380     			String name = entry.getName();
381     			int classpos = name.lastIndexOf(".class");
382     			if ((classpos != -1) &&
383     					!PascalClassData.isInnerClass(name.substring(0, classpos)) &&
384     					!entry.isDirectory()) {
385     				res.add(name.substring(0, classpos));
386     			}
387     		}
388     	}catch(FileNotFoundException fnexce){
389 //    		fnexce.printStackTrace();
390 //    		error("cant read file");
391 //    		error("fatal exception");
392     	}catch(IOException ioexc){
393 //    		ioexc.printStackTrace();
394 //    		error("fatal exception");
395     	}
396     	return res;
397     }
398 
399 
getDirEntries(File fileobj, boolean includeJarEntries)400     protected SortedSet<String> getDirEntries(File fileobj, boolean includeJarEntries) {
401     	SortedSet<String> res = new TreeSet<String>();
402 
403     	File[] filelist = fileobj.listFiles();
404     	for(int i = 0; i < filelist.length; i++){
405     		//file is a jar file.
406     		String fname = filelist[i].toString();
407     		if(includeJarEntries &&
408     				fname.endsWith(".jar")){
409     			res.addAll(getJarEntries(fname));
410     		}
411     		else if (fname.endsWith(".class")) {
412     			int classpos = fname.lastIndexOf(".class");
413     			if (classpos != -1)
414     				fname = fname.substring(0, classpos);
415     			if (!PascalClassData.isInnerClass(fname))
416     				res.add(fname);
417     		}
418     	}
419     	return res;
420     }
421 
422     /**
423      * Returns list of non-nested classes found in a path
424      */
getExdirEntries(String path)425     public SortedSet<String> getExdirEntries(String path){
426     	File fileobj = new File(path);
427     	if(fileobj.isDirectory()){
428     		return getDirEntries(fileobj,true);
429     	}
430     	return new TreeSet<String>();
431     }
432 
433 
434     /**
435      * Returns list of non-nested classes found in class path
436      */
getClasspathEntries(String path)437     public SortedSet<String>  getClasspathEntries(String path){
438         File fileobj = new File(path);
439         if(fileobj.isDirectory()){
440         	return getDirEntries(fileobj, false);
441 
442         }else if(fileobj.toString().endsWith(".jar")){
443         	return getJarEntries(fileobj.toString());
444         }
445         return new TreeSet<String>();
446     }
447 
448 
449     /**
450      * Return a list of all non-nested classes in the currently set exdir classpath
451      */
getAllExdirEntries()452     public SortedSet<String> getAllExdirEntries(){
453     	SortedSet<String> res;
454         if(classpath.indexOf(File.pathSeparator) != -1){
455         	res = new TreeSet<String>();
456             //separates path
457             StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
458             while(st.hasMoreTokens()){
459                 String path = st.nextToken();
460                 res.addAll(getExdirEntries(path));
461             }
462         }else res = getExdirEntries(classpath);
463 
464         return res;
465     }
466 
467     /**
468      * Return a list of all non-nested classes in the currently set classpath
469      */
getAllClasspathEntries()470     public SortedSet<String> getAllClasspathEntries(){
471     	SortedSet<String> res;
472         if(classpath.indexOf(File.pathSeparator) != -1){
473         	res = new TreeSet<String>();
474             StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
475             //separates path.
476             while(st.hasMoreTokens()){
477                 String path = (st.nextToken()).trim();
478                 res.addAll(getClasspathEntries(path));
479             }
480         }
481         else res = getClasspathEntries(classpath);
482         return res;
483     }
484 
485 
getAllEntries()486     public SortedSet<String> getAllEntries(){
487     	if (extDirflag)
488     	  return getAllExdirEntries();
489     	else
490       	  return getAllClasspathEntries();
491     }
492 
493 
getClassesList()494     public SortedSet<String> getClassesList(){
495     	SortedSet<String> res = new TreeSet<String>();
496         int searchpath = cmdboot;
497         extDirflag = false;
498         try{
499             if(searchpath == cmdboot){
500                 if(bootClassPathString != null){
501                     //search in specified bootclasspath.
502                     classpath = bootClassPathString;
503                     res.addAll(getAllEntries());
504                     searchpath = cmdextdir;
505                 }
506                 else searchpath = sunboot;
507             }
508 
509             if(searchpath == sunboot){
510                 if(System.getProperty("sun.boot.class.path") != null){
511                     //search in sun.boot.class.path
512                     classpath = System.getProperty("sun.boot.class.path");
513                     res.addAll(getAllEntries());
514                     searchpath = cmdextdir;
515                 }
516                 else searchpath = javaclass;
517             }
518 
519             if(searchpath == javaclass){
520                 if(System.getProperty("java.class.path") != null){
521                     //search in java.class.path
522                     classpath =System.getProperty("java.class.path");
523                     res.addAll(getAllEntries());
524                     searchpath = cmdextdir;
525                 }
526                 else searchpath = cmdextdir;
527             }
528 
529             if(searchpath == cmdextdir){
530                 if(extDirsString != null){
531                     //search in specified extdir.
532                     classpath = extDirsString;
533                     extDirflag = true;
534                     res.addAll(getAllEntries());
535                     searchpath = cmdclasspath;
536                     extDirflag = false;
537                 }
538                 else searchpath = javaext;
539             }
540 
541             if(searchpath == javaext){
542                 if(System.getProperty("java.ext.dirs") != null){
543                     //search in java.ext.dirs
544                     classpath = System.getProperty("java.ext.dirs");
545                     extDirflag = true;
546                     res.addAll(getAllEntries());
547                     searchpath = cmdclasspath;
548                     extDirflag = false;
549                 }
550                 else searchpath = cmdclasspath;
551             }
552             if(searchpath == cmdclasspath){
553                 if(classPathString != null){
554                     //search in specified classpath.
555                     classpath = classPathString;
556                     res.addAll(getAllEntries());
557                     searchpath = 8;
558                 }
559                 else searchpath = envclasspath;
560             }
561 
562             if(searchpath == envclasspath){
563                 if(System.getProperty("env.class.path")!= null){
564                     //search in env.class.path
565                     classpath = System.getProperty("env.class.path");
566                     res.addAll(getAllEntries());
567                     searchpath = javaclasspath;
568                 }
569                 else searchpath = javaclasspath;
570             }
571 
572             if(searchpath == javaclasspath){
573                 if(("application.home") == null){
574                     //search in java.class.path
575                     classpath = System.getProperty("java.class.path");
576                     res.addAll(getAllEntries());
577                     searchpath = currentdir;
578                 }
579                 else searchpath = currentdir;
580             }
581 
582             if(searchpath == currentdir){
583                 classpath = ".";
584                 //search in current dir.
585                 res.addAll(getAllEntries());
586             }
587         }catch(SecurityException excsec){
588             excsec.printStackTrace();
589             error("fatal exception");
590         }catch(NullPointerException excnull){
591             excnull.printStackTrace();
592             error("fatal exception");
593         }catch(IllegalArgumentException excill){
594             excill.printStackTrace();
595             error("fatal exception");
596         }
597 
598         return res;
599     }
600 
601 
602 
603 
604 }
605