/* Soot - a J*va Optimization Framework * Copyright (C) 2003 Jerome Miecznikowski * Copyright (C) 2004-2005 Nomair A. Naeem * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package soot.dava; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import soot.Body; import soot.BooleanType; import soot.ByteType; import soot.CharType; import soot.DoubleType; import soot.FloatType; import soot.G; import soot.IntType; import soot.LongType; import soot.Modifier; import soot.RefType; import soot.Scene; import soot.ShortType; import soot.Singletons; import soot.SootClass; import soot.SootField; import soot.SootMethod; import soot.Type; import soot.UnitPrinter; import soot.dava.internal.AST.ASTNode; import soot.dava.toolkits.base.renamer.RemoveFullyQualifiedName; import soot.options.Options; import soot.tagkit.DoubleConstantValueTag; import soot.tagkit.FloatConstantValueTag; import soot.tagkit.IntegerConstantValueTag; import soot.tagkit.LongConstantValueTag; import soot.tagkit.StringConstantValueTag; import soot.tagkit.Tag; import soot.util.Chain; import soot.util.IterableSet; public class DavaPrinter { public DavaPrinter(Singletons.Global g) { } public static DavaPrinter v() { return G.v().soot_dava_DavaPrinter(); } private void printStatementsInBody(Body body, java.io.PrintWriter out) { if (Options.v().verbose()) System.out.println("Printing "+body.getMethod().getName()); Chain units = ((DavaBody) body).getUnits(); if (units.size() != 1) { throw new RuntimeException("DavaBody AST doesn't have single root."); } UnitPrinter up = new DavaUnitPrinter((DavaBody)body); ((ASTNode) units.getFirst()).toString(up); out.print( up.toString() ); } public void printTo(SootClass cl, PrintWriter out) { //IterableSet packagesUsed = new IterableSet(); IterableSet importList = new IterableSet(); { String curPackage = cl.getJavaPackageName(); if (!curPackage.equals("")) { out.println("package " + curPackage + ";"); out.println(); } if (cl.hasSuperclass()) { SootClass superClass = cl.getSuperclass(); importList.add(superClass.toString()); //packagesUsed.add(superClass.getJavaPackageName()); } Iterator interfaceIt = cl.getInterfaces().iterator(); while (interfaceIt.hasNext()) { String interfacePackage = ((SootClass) interfaceIt.next()).toString(); if(!importList.contains(interfacePackage)) importList.add(interfacePackage); //if (!packagesUsed.contains(interfacePackage)) // packagesUsed.add(interfacePackage); } Iterator methodIt = cl.methodIterator(); while (methodIt.hasNext()) { SootMethod dm = (SootMethod) methodIt.next(); if (dm.hasActiveBody()){ //packagesUsed = packagesUsed.union(((DavaBody) dm.getActiveBody()).get_PackagesUsed()); importList = importList.union(((DavaBody) dm.getActiveBody()).getImportList()); } Iterator<SootClass> eit = dm.getExceptions().iterator(); while (eit.hasNext()) { String thrownPackage =eit.next().toString(); if(!importList.contains(thrownPackage)) importList.add(thrownPackage); //if (!packagesUsed.contains(thrownPackage)) // packagesUsed.add(thrownPackage); } Iterator pit = dm.getParameterTypes().iterator(); while (pit.hasNext()) { Type t = (Type) pit.next(); if (t instanceof RefType) { String paramPackage = ((RefType) t).getSootClass().toString(); if (!importList.contains(paramPackage)) importList.add(paramPackage); //if (packagesUsed.contains(paramPackage) == false) // packagesUsed.add(paramPackage); } } Type t = dm.getReturnType(); if (t instanceof RefType) { String returnPackage = ((RefType) t).getSootClass().toString(); if (!importList.contains(returnPackage)) importList.add(returnPackage); //if (packagesUsed.contains(returnPackage) == false) // packagesUsed.add(returnPackage); } } Iterator fieldIt = cl.getFields().iterator(); while (fieldIt.hasNext()) { SootField f = (SootField) fieldIt.next(); if (f.isPhantom()) continue; Type t = f.getType(); if (t instanceof RefType) { String fieldPackage = ((RefType) t).getSootClass().toString(); if (!importList.contains(fieldPackage)) importList.add(fieldPackage); } } Iterator pit = importList.iterator(); List toImport = new ArrayList(); while (pit.hasNext()){ /* * dont import any file which has currentPackage.className * dont import any file which starts with java.lang */ String temp = (String)pit.next(); //System.out.println("temp is "+temp); if(temp.indexOf("java.lang")>-1 ){ //problem is that we need to import sub packages java.lang.ref //for instance if the type is java.lang.ref.WeakReference String tempClassName = RemoveFullyQualifiedName.getClassName(temp); if(temp.equals("java.lang."+tempClassName)){ //System.out.println("temp was not printed as it belongs to java.lang"); continue; } } if(curPackage.length()>0 && temp.indexOf(curPackage)>-1){ //System.out.println("here "+temp); continue; } if(cl.toString().equals(temp)) continue; //System.out.println("printing"+); toImport.add(temp); } /* * Check that we are not importing two classes with the same last name * If yes then remove explicit import and import the whole package * else output explicit import statement */ Iterator it = toImport.iterator(); while(it.hasNext()){ String temp = (String)it.next(); if(RemoveFullyQualifiedName.containsMultiple(toImport.iterator(),temp,null)){ //there are atleast two imports with this className //import package add * if(temp.lastIndexOf('.')>-1){ temp = temp.substring(0,temp.lastIndexOf('.')); out.println("import " + temp + ".*;"); } else throw new DecompilationException("Cant find the DOT . for fullyqualified name"); } else{ if(temp.lastIndexOf('.')==-1){ //dot not found this is a class belonging to this package so dont add } else out.println("import " + temp + ";"); } } boolean addNewLine=false; addNewLine=true; // out.println("import " + temp + ";"); if(addNewLine) out.println(); /*if (!packagesUsed.isEmpty()) out.println(); packagesUsed.add("java.lang"); packagesUsed.add(curPackage); */ Dava.v().set_CurrentPackageContext(importList); //Dava.v().set_CurrentPackageContext(packagesUsed); Dava.v().set_CurrentPackage(curPackage); } // Print class name + modifiers { String classPrefix = ""; classPrefix = classPrefix + " " + Modifier.toString(cl.getModifiers()); classPrefix = classPrefix.trim(); if (!cl.isInterface()) { classPrefix = classPrefix + " class"; classPrefix = classPrefix.trim(); } out.print(classPrefix + " " + cl.getShortJavaStyleName()); } // Print extension if (cl.hasSuperclass() && !(cl.getSuperclass().getName().equals("java.lang.Object"))){ String superClassName = cl.getSuperclass().getName(); //Nomair Naeem 8th Feb 2006 //also check if the super class name is not a fully qualified //name. in which case if the package is imported no need for //the long name superClassName = RemoveFullyQualifiedName.getReducedName(importList,superClassName,cl.getType()); out.print(" extends " + superClassName + ""); } // Print interfaces { Iterator interfaceIt = cl.getInterfaces().iterator(); if (interfaceIt.hasNext()) { if( cl.isInterface() ) out.print(" extends "); else out.print(" implements "); out.print("" + ((SootClass) interfaceIt.next()).getName() + ""); while (interfaceIt.hasNext()) out.print( ", " + ((SootClass) interfaceIt.next()).getName() + ""); } } out.println(); out.println("{"); // Print fields { Iterator fieldIt = cl.getFields().iterator(); if (fieldIt.hasNext()) { while (fieldIt.hasNext()) { SootField f = (SootField) fieldIt.next(); if (f.isPhantom()) continue; String declaration = null; Type fieldType = f.getType(); String qualifiers = Modifier.toString(f.getModifiers()) + " "; qualifiers += RemoveFullyQualifiedName.getReducedName(importList,fieldType.toString(),fieldType); qualifiers = qualifiers.trim(); if(qualifiers.equals("")) declaration = Scene.v().quotedNameOf(f.getName()); else declaration = qualifiers + " " + Scene.v().quotedNameOf(f.getName()) + ""; if (f.isFinal() && f.isStatic()) { if (fieldType instanceof DoubleType && f.hasTag("DoubleConstantValueTag")) { double val = ((DoubleConstantValueTag) f.getTag("DoubleConstantValueTag")).getDoubleValue(); out.println(" " + declaration + " = "+ val + ";"); } else if (fieldType instanceof FloatType && f.hasTag("FloatConstantValueTag")) { float val = ((FloatConstantValueTag) f.getTag("FloatConstantValueTag")).getFloatValue(); out.println(" " + declaration + " = "+ val + "f;"); } else if (fieldType instanceof LongType && f.hasTag("LongConstantValueTag")) { long val = ((LongConstantValueTag) f.getTag("LongConstantValueTag")).getLongValue(); out.println(" " + declaration + " = "+ val + "l;"); } else if (fieldType instanceof CharType && f.hasTag("IntegerConstantValueTag")) { int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue(); out.println(" " + declaration + " = '" + ((char) val) + "';"); } else if (fieldType instanceof BooleanType && f.hasTag("IntegerConstantValueTag")) { int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue(); if (val == 0) out.println(" " + declaration+ " = false;"); else out.println(" " + declaration+ " = true;"); } else if ((fieldType instanceof IntType || fieldType instanceof ByteType || fieldType instanceof ShortType) && f.hasTag("IntegerConstantValueTag")) { int val = ((IntegerConstantValueTag) f.getTag("IntegerConstantValueTag")).getIntValue(); out.println(" " + declaration + " = "+ val + ";"); } else if (f.hasTag("StringConstantValueTag")) { String val = ((StringConstantValueTag) f.getTag("StringConstantValueTag")).getStringValue(); out.println(" " + declaration + " = \""+ val + "\";"); } else { // System.out.println("Couldnt find type of // field"+f.getDeclaration()); out.println(" " + declaration + ";"); } } // field is static final else { out.println(" " + declaration + ";"); } } } } // Print methods { Iterator methodIt = cl.methodIterator(); if (methodIt.hasNext()) { if (cl.getMethodCount() != 0) out.println(); while (methodIt.hasNext()) { SootMethod method = (SootMethod) methodIt.next(); if (method.isPhantom()) continue; if (!Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers())) { if (!method.hasActiveBody()) throw new RuntimeException( "method " + method.getName() + " has no active body!"); else printTo(method.getActiveBody(), out); if (methodIt.hasNext()) out.println(); } else { //if method is abstract then print the declaration out.print(" "); out.print(method.getDavaDeclaration()); out.println(";"); if (methodIt.hasNext()) out.println(); } } } } /* * January 23rd, 2006 * In trying to handle the suepr class problem we need to introduce an inner class * Instead of creating a data structure for it we are right now just going to print it in the form * of a string * * It would be interesting to later have an internal inner class structure so that we could * decompile inner classes into inner classes */ if(G.v().SootClassNeedsDavaSuperHandlerClass.contains(cl)){ out.println("\n private static class DavaSuperHandler{"); out.println(" java.util.Vector myVector = new java.util.Vector();"); out.println("\n public Object get(int pos){"); out.println(" return myVector.elementAt(pos);"); out.println(" }"); out.println("\n public void store(Object obj){"); out.println(" myVector.add(obj);"); out.println(" }"); out.println(" }"); } out.println("}"); } /** * Prints out the method corresponding to b Body, (declaration and body), * in the textual format corresponding to the IR used to encode b body. * * @param out a PrintWriter instance to print to. */ private void printTo(Body b, PrintWriter out) { b.validate(); String decl = b.getMethod().getDavaDeclaration(); { out.println(" " + decl); for( Iterator tIt = b.getMethod().getTags().iterator(); tIt.hasNext(); ) { final Tag t = (Tag) tIt.next(); if (Options.v().print_tags_in_output()){ out.println(t); } } out.println(" {"); /* The locals are now printed out from within the toString method of ASTMethodNode Nomair A Naeem 10-MARCH-2005 */ //printLocalsInBody(b, out); } printStatementsInBody(b, out); out.println(" }"); } }