/* --- Copyright (c) Chris Rathman 1999. All rights reserved. ----------------- > File: jasper/Jasper.java > Purpose: Write Jasmin and browser files from input java class files > Author: Chris Rathman, 12 June 1999 > Version: 1.00 */ package jasper; import java.io.*; import java.util.zip.*; /*======================================================================= = Class: Jasper = = = = Desc: program to write Jasmin & Browse files = =======================================================================*/ public class Jasper { public static final String version = "v1.00"; // jasper software version number /*----------------------------------------------------------------------- - Method: main - - - - Desc: program entry point - -----------------------------------------------------------------------*/ public static void main(String[] args) { String accessPermission; boolean jasmin = true; boolean browse = false; boolean recurse = false; java.util.Vector classList = new java.util.Vector(); for (int i = 0; i < args.length; i++) { if (args[i].charAt(0) != '-') { // put the class file name into the list of programs to read addClassFile(args[i], classList); } else { if (args[i].equals("--jasmin")) { // turn off the output to the jasmin assembly files jasmin = false; } else if(args[i].equals("-jasmin")) { // turn on the output to the jasmin assembly files jasmin = true; } else if(args[i].equals("-browse")) { // enable the output to the browse files browse = true; } else if(args[i].equals("-recurse")) { // recurse through the inheritance and composition for the class recurse = true; } else if(args[i].equals("-version")) { // print out the program name and version number printVersion(); System.exit(0); } else if(args[i].equals("--version")) { // print out the program name, version number and BSD License printVersion(); printLicense(); System.exit(0); } else if((args[i].equals("-?")) || (args[i].equals("-help"))) { // explain the program usage and options which are available printVersion(); printOptions(); System.exit(0); } else { // option not recognized so give up System.out.println("Unrecognized option: " + args[i]); System.out.println("Could not run jasper."); printVersion(); printOptions(); System.exit(0); } } } // read in the files (and add new ones along the way for recurse option for (int i = 0; i < classList.size(); i++) { // get the next class to read in String fileName = (String)classList.elementAt(i); // pull in the class ClassFile cls = new ClassFile(fileName); // output the assembly files if (jasmin) cls.jasmin(); // echo the browse output if (browse) browseDump(cls); // if recurse, then add classes to list that are referred to by inheritance and composition if (recurse) recurseClasses(cls, classList); } } /*----------------------------------------------------------------------- - Method: recurseClasses - - - - Desc: trundle through browse strings to find class ref's - -----------------------------------------------------------------------*/ static void recurseClasses(ClassFile cls, java.util.Vector classList) { // bring in super class String newClass = cls.browseSuper(); if (!newClass.equals("")) addClassFile(newClass + ".class", classList); // bring in interface classes String[] newClassArray = cls.browseInterfaces(); for (int j = 0; j < newClassArray.length; j++) { newClass = newClassArray[j]; addClassFile(newClass + ".class", classList); } // bring in field types newClassArray = cls.browseFields(); for (int j = 0; j < newClassArray.length; j++) { // kill the field access permission attributes newClass = stripAccess(newClassArray[j]); // reduce the string to the field type if (newClass.indexOf(' ') > 0) newClass = newClass.substring(0, newClass.indexOf(' ')); // strip off any array indexes on the field type if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); // add the class to the list of classes to read addClassFile(newClass + ".class", classList); } // bring in method types newClassArray = cls.browseMethods(); for (int j = 0; j < newClassArray.length; j++) { // kill the field access permission attributes newClass = stripAccess(newClassArray[j]); // reduce the string to the field type if (newClass.indexOf(' ') > 0) newClass = newClass.substring(0, newClass.indexOf(' ')); // strip off any array indexes on the field type if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); // add the class to the list of classes to read addClassFile(newClass + ".class", classList); // bring in method parameters String params = newClassArray[j]; params = params.substring(params.indexOf('(')+1); params = params.substring(0, params.indexOf(')')+1); while (params.length() > 1) { int n = params.indexOf(','); if (n > 0) { newClass = params.substring(0, n); params = params.substring(n + 2); } else { newClass = params.substring(0, params.indexOf(')')); params = ""; } if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); addClassFile(newClass + ".class", classList); } } // bring in the fields referenced by class methods String[][] newClassRef = cls.browseFieldrefs(); for (int j = 0; j < newClassRef.length; j++) { for (int k = 0; k < newClassRef[j].length; k++) { // kill the field access permission attributes newClass = stripAccess(newClassRef[j][k]); // reduce the string to the field type if (newClass.indexOf(' ') > 0) newClass = newClass.substring(0, newClass.indexOf(' ')); // strip off any array indexes on the field type if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); // add the class to the list of classes to read addClassFile(newClass + ".class", classList); // get the class name of the field being referred to newClass = stripAccess(newClassRef[j][k]); if (newClass.lastIndexOf(' ') > 0) newClass = newClass.substring(newClass.lastIndexOf(' ') + 1); // strip off the field name if (newClass.lastIndexOf('.') > 0) newClass = newClass.substring(0, newClass.lastIndexOf('.')); // add the class to the list of classes to read addClassFile(newClass + ".class", classList); } } // bring in the methods referenced by class methods newClassRef = cls.browseMethodrefs(); for (int j = 0; j < newClassRef.length; j++) { for (int k = 0; k < newClassRef[j].length; k++) { // kill the field access permission attributes newClass = stripAccess(newClassRef[j][k]); // reduce the string to the method return type if (newClass.indexOf(' ') > 0) newClass = newClass.substring(0, newClass.indexOf(' ')); // strip off any array indexes on the return type if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); if (!newClass.equals("new")) { // add the class to the list of classes to read addClassFile(newClass + ".class", classList); // get the class name of the method being referred to newClass = stripAccess(newClassRef[j][k]); if (newClass.indexOf('(') > 0) newClass = newClass.substring(0, newClass.indexOf('(')); if (newClass.lastIndexOf(' ') > 0) newClass = newClass.substring(newClass.lastIndexOf(' ') + 1); // strip off the method name if (newClass.lastIndexOf('.') > 0) newClass = newClass.substring(0, newClass.lastIndexOf('.')); // add the class to the list of classes to read addClassFile(newClass + ".class", classList); } // bring in method parameters String params = newClassRef[j][k]; params = params.substring(params.indexOf('(')+1); params = params.substring(0, params.indexOf(')')+1); while (params.length() > 1) { int n = params.indexOf(','); if (n > 0) { newClass = params.substring(0, n); params = params.substring(n + 2); } else { newClass = params.substring(0, params.indexOf(')')); params = ""; } if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); addClassFile(newClass + ".class", classList); } } } // bring in the interface methods referenced by class methods newClassRef = cls.browseMethodrefs(); for (int j = 0; j < newClassRef.length; j++) { for (int k = 0; k < newClassRef[j].length; k++) { // kill the field access permission attributes newClass = stripAccess(newClassRef[j][k]); // reduce the string to the method return type if (newClass.indexOf(' ') > 0) newClass = newClass.substring(0, newClass.indexOf(' ')); // strip off any array indexes on the return type if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); if (!newClass.equals("new")) { // add the class to the list of classes to read addClassFile(newClass + ".class", classList); // get the class name of the method being referred to newClass = stripAccess(newClassRef[j][k]); if (newClass.indexOf('(') > 0) newClass = newClass.substring(0, newClass.indexOf('(')); if (newClass.lastIndexOf(' ') > 0) newClass = newClass.substring(newClass.lastIndexOf(' ') + 1); // strip off the method name if (newClass.lastIndexOf('.') > 0) newClass = newClass.substring(0, newClass.lastIndexOf('.')); // add the class to the list of classes to read addClassFile(newClass + ".class", classList); } // bring in method parameters String params = newClassRef[j][k]; params = params.substring(params.indexOf('(')+1); params = params.substring(0, params.indexOf(')')+1); while (params.length() > 1) { int n = params.indexOf(','); if (n > 0) { newClass = params.substring(0, n); params = params.substring(n + 2); } else { newClass = params.substring(0, params.indexOf(')')); params = ""; } if (newClass.indexOf('[') > 0) newClass = newClass.substring(0, newClass.indexOf('[')); addClassFile(newClass + ".class", classList); } } } } /*----------------------------------------------------------------------- - Method: addClassFile - - - - Desc: if class not in process list, then add it - -----------------------------------------------------------------------*/ static void addClassFile(String name, java.util.Vector classList) { // normalize the file name String fileName = ClassFile.parseFileDir(name) + ClassFile.parseFileName(name) + "." + ClassFile.parseFileExt(name); // don't add the primitive types since there is no class file associated with them if (fileName.equals(".class")) return; if (fileName.equals("byte.class")) return; if (fileName.equals("short.class")) return; if (fileName.equals("int.class")) return; if (fileName.equals("long.class")) return; if (fileName.equals("boolean.class")) return; if (fileName.equals("float.class")) return; if (fileName.equals("double.class")) return; if (fileName.equals("char.class")) return; if (fileName.equals("void.class")) return; // check if file has already been read in for (int i = 0; i < classList.size(); i++) { if (((String)classList.elementAt(i)).equals(fileName)) return; } // add class to the list of those read classList.add(fileName); } /*----------------------------------------------------------------------- - Method: stripAccess - - - - Desc: strip access permission from fields and methods - - element[i][0] = permission string to match - - element[i][1] = field/method as synthetic - -----------------------------------------------------------------------*/ static String stripAccess(String newClass) { // loop until all the known access flags are stripped boolean flag = true; while (flag) { flag = false; for (int i = 0; i < accessStrings.length; i++) { String s = accessStrings[i][0]; if (newClass.substring(0, s.length()).equals(s)) { // strip the attribute away from the string newClass = newClass.substring(s.length()); flag = true; // check if this is a synthetic field/method boolean synthetic = accessStrings[i][1].equals("1"); if (synthetic) return ""; } } } return newClass; } /*----------------------------------------------------------------------- - Method: accessStrings - - - - Desc: array of access permission strings used for strip - - element[i][0] = permission string to match - - element[i][1] = synthetic field/method) ("1"=true) - -----------------------------------------------------------------------*/ static String[][] accessStrings = { {"public ", "0"}, {"private ", "0"}, {"protected ", "0"}, {"static ", "0"}, {"final ", "0"}, {"synchronized ", "0"}, {"volatile ", "0"}, {"transient ", "0"}, {"native ", "0"}, {"abstract ", "0"}, {"#deprecated# ", "0"}, {"#synthetic# ", "1"}, }; /*----------------------------------------------------------------------- - Method: browseDump - - - - Desc: echo the browse - -----------------------------------------------------------------------*/ static void browseDump(ClassFile cls) { String[] ix = cls.browseInterfaces(); String[] fx = cls.browseFields(); String[] mx = cls.browseMethods(); String[][] mf = cls.browseFieldrefs(); String[][] mm = cls.browseMethodrefs(); String[][] mi = cls.browseInterfaceMethodrefs(); String[][] ic = cls.browseInnerClasses(); System.out.println("+++++++++++++++++++++++"); System.out.println(" SourceFile = " + cls.browseSourceFile()); System.out.println(" class = " + cls.browseClass()); System.out.println(" extends = " + cls.browseSuper()); for (int i = 0; i < ix.length; i++) System.out.println(" implements = " + ix[i]); for (int i = 0; i < fx.length; i++) System.out.println(" field = " + fx[i]); for (int i = 0; i < mx.length; i++) { System.out.println(" method = " + mx[i]); for (int j = 0; j < mf[i].length; j++) System.out.println(" fields = " + mf[i][j]); for (int j = 0; j < mm[i].length; j++) System.out.println(" methods = " + mm[i][j]); for (int j = 0; j < mi[i].length; j++) System.out.println(" interfaces = " + mi[i][j]); } for (int i = 0; i < ic.length; i++) { System.out.println("innerClass[" + i + "] = " + ic[i][0]); System.out.println("outerClass[" + i + "] = " + ic[i][1]); System.out.println("innerName[" + i + "] = " + ic[i][2]); } } /*----------------------------------------------------------------------- - Method: printVersion - - - - Desc: echo the program name and version number - -----------------------------------------------------------------------*/ private static void printVersion() { System.out.println("Jasper Version " + version + " Copyright (c) Chris Rathman 1999. All rights reserved."); System.out.println("Syntax: java [java-options] jasper/Jasper [jasper-options] files.class"); System.out.println(""); } /*----------------------------------------------------------------------- - Method: printOptions - - - - Desc: echo the program options - -----------------------------------------------------------------------*/ private static void printOptions() { System.out.println("Jasper recognizes the following options:"); System.out.println(" --jasmin Disable jasmin file output"); System.out.println(" -jasmin Enable jasmin file output (default)"); System.out.println(" -browse Enable output to the browse files"); System.out.println(" -recurse Recurse through the inheritance and composition for the class"); System.out.println(" -help View Jasper help"); System.out.println(" -version View Jasper version number"); System.out.println(" --version View Jasper license"); System.out.println(""); } /*----------------------------------------------------------------------- - Method: printLicense - - - - Desc: Echo the software license - -----------------------------------------------------------------------*/ static void printLicense() { System.out.println(""); System.out.println("Redistribution and use in source and binary forms, with or without"); System.out.println("modification, are permitted provided that the following conditions"); System.out.println("are met:"); System.out.println(""); System.out.println(" 1. Redistributions of source code must retain the above copyright"); System.out.println(" notice, this list of conditions and the following disclaimer."); System.out.println(" 2. Redistributions in binary form must reproduce the above copyright"); System.out.println(" notice, this list of conditions and the following disclaimer in the"); System.out.println(" documentation and/or other materials provided with the distribution."); System.out.println(" 3. All advertising materials mentioning features or use of this software"); System.out.println(" must display the following acknowledgement:"); System.out.println(" This product includes software developed by Chris Rathman and"); System.out.println(" its contributors."); System.out.println(" 4. Neither the name of Chris Rathman nor the names of its contributors"); System.out.println(" may be used to endorse or promote products derived from this software"); System.out.println(" without specific prior written permission."); System.out.println(""); System.out.println("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''"); System.out.println("AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE"); System.out.println("IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE"); System.out.println("ARE DISCLAIMED. IN NO EVENT SHALL CHRIS RATHMAN OR CONTRIBUTORS BE LIABLE FOR"); System.out.println("ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES"); System.out.println("(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;"); System.out.println("LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND"); System.out.println("ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT"); System.out.println("(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"); System.out.println("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."); System.out.println(""); } }