/* Soot - a J*va Optimization Framework
* Copyright (C) 2003 Jerome Miecznikowski
*
* 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.toolkits.base.misc;
import soot.*;
import java.io.*;
import java.util.*;
import soot.util.*;
import soot.dava.*;
import java.util.jar.*;
public class PackageNamer
{
public PackageNamer( Singletons.Global g ) {}
public static PackageNamer v() { return G.v().soot_dava_toolkits_base_misc_PackageNamer(); }
public boolean has_FixedNames(){
return fixed;
}
public boolean use_ShortName( String fixedPackageName, String fixedShortClassName){
if (fixed == false)
return false;
if (fixedPackageName.equals( Dava.v().get_CurrentPackage()))
return true;
IterableSet packageContext = Dava.v().get_CurrentPackageContext();
if (packageContext == null)
return true;
packageContext = patch_PackageContext( packageContext);
int count = 0;
StringTokenizer st = new StringTokenizer( classPath, pathSep);
while (st.hasMoreTokens()) {
String classpathDir = st.nextToken();
Iterator packIt = packageContext.iterator();
while (packIt.hasNext())
if (package_ContainsClass( classpathDir, (String) packIt.next(), fixedShortClassName))
if (++count > 1)
return false;
}
return true;
}
public String get_FixedClassName( String originalFullClassName)
{
if (fixed == false)
return originalFullClassName;
Iterator<NameHolder> it = appRoots.iterator();
while (it.hasNext()) {
NameHolder h = it.next();
if (h.contains_OriginalName( new StringTokenizer( originalFullClassName, "."), true))
return h.get_FixedName( new StringTokenizer( originalFullClassName, "."), true);
}
return originalFullClassName.substring( originalFullClassName.lastIndexOf( ".") + 1);
}
public String get_FixedPackageName( String originalPackageName)
{
if (fixed == false)
return originalPackageName;
if (originalPackageName.equals( ""))
return "";
Iterator<NameHolder> it = appRoots.iterator();
while (it.hasNext()) {
NameHolder h = it.next();
if (h.contains_OriginalName( new StringTokenizer( originalPackageName, "."), false))
return h.get_FixedName( new StringTokenizer( originalPackageName, "."), false);
}
return originalPackageName;
}
private class NameHolder
{
private final String originalName;
private String packageName, className;
private final ArrayList<NameHolder> children;
private NameHolder parent;
private boolean isClass;
public NameHolder( String name, NameHolder parent, boolean isClass)
{
originalName = name;
className = name;
packageName = name;
this.parent = parent;
this.isClass = isClass;
children = new ArrayList<NameHolder>();
}
public NameHolder get_Parent() {
return parent;
}
public void set_ClassAttr() {
isClass = true;
}
public boolean is_Class() {
if (children.isEmpty())
return true;
else
return isClass;
}
public boolean is_Package() {
return (children.isEmpty() == false);
}
public String get_PackageName() {
return packageName;
}
public String get_ClassName() {
return className;
}
public void set_PackageName(String packageName) {
this.packageName = packageName;
}
public void set_ClassName(String className) {
this.className = className;
}
public String get_OriginalName() {
return originalName;
}
public ArrayList<NameHolder> get_Children() {
return children;
}
public String get_FixedPackageName() {
if (parent == null)
return "";
return parent.retrieve_FixedPackageName();
}
public String retrieve_FixedPackageName()
{
if (parent == null)
return packageName;
return parent.get_FixedPackageName() + "." + packageName;
}
public String get_FixedName( StringTokenizer st, boolean forClass)
{
if (st.nextToken().equals( originalName) == false)
throw new RuntimeException( "Unable to resolve naming.");
return retrieve_FixedName( st, forClass);
}
private String retrieve_FixedName( StringTokenizer st, boolean forClass)
{
if (st.hasMoreTokens() == false) {
if (forClass)
return className;
else
return packageName;
}
String subName = st.nextToken();
Iterator<NameHolder> cit = children.iterator();
while (cit.hasNext()) {
NameHolder h = cit.next();
if (h.get_OriginalName().equals( subName)) {
if (forClass)
return h.retrieve_FixedName( st, forClass);
else
return packageName + "." + h.retrieve_FixedName( st, forClass);
}
}
throw new RuntimeException( "Unable to resolve naming.");
}
public String get_OriginalPackageName( StringTokenizer st)
{
if (st.hasMoreTokens() == false)
return get_OriginalName();
String subName = st.nextToken();
Iterator<NameHolder> cit = children.iterator();
while (cit.hasNext()) {
NameHolder h = cit.next();
if (h.get_PackageName().equals( subName)) {
String originalSubPackageName = h.get_OriginalPackageName( st);
if (originalSubPackageName == null)
return null;
else
return get_OriginalName() + "." + originalSubPackageName;
}
}
return null;
}
public boolean contains_OriginalName( StringTokenizer st, boolean forClass)
{
if (get_OriginalName().equals( st.nextToken()) == false)
return false;
return finds_OriginalName( st, forClass);
}
private boolean finds_OriginalName( StringTokenizer st, boolean forClass)
{
if (st.hasMoreTokens() == false)
return (((forClass) && (is_Class())) || ((!forClass) && (is_Package())));
String subName = st.nextToken();
Iterator<NameHolder> cit = children.iterator();
while (cit.hasNext()) {
NameHolder h = cit.next();
if (h.get_OriginalName().equals( subName))
return h.finds_OriginalName( st, forClass);
}
return false;
}
public void fix_ClassNames( String curPackName)
{
if ((is_Class()) && (keywords.contains( className))) {
String tClassName = className;
if (Character.isLowerCase( className.charAt( 0))) {
tClassName = tClassName.substring( 0, 1).toUpperCase() + tClassName.substring( 1);
className = tClassName;
}
for (int i=0; keywords.contains( className); i++)
className = tClassName + "_c" + i;
}
Iterator<NameHolder> it = children.iterator();
while (it.hasNext())
it.next().fix_ClassNames( curPackName + "." + packageName);
}
public void fix_PackageNames()
{
if ((is_Package()) && (verify_PackageName() == false)) {
String tPackageName = packageName;
if (Character.isUpperCase( packageName.charAt( 0))) {
tPackageName = tPackageName.substring( 0, 1).toLowerCase() + tPackageName.substring( 1);
packageName = tPackageName;
}
for (int i=0; verify_PackageName() == false; i++)
packageName = tPackageName + "_p" + i;
}
Iterator<NameHolder> it = children.iterator();
while (it.hasNext())
it.next().fix_PackageNames();
}
public boolean verify_PackageName()
{
return ((keywords.contains( packageName) == false) &&
(siblingClashes( packageName) == false) &&
((is_Class() == false) || (className.equals( packageName) == false)));
}
public boolean siblingClashes( String name)
{
Iterator<NameHolder> it = null;
if (parent == null) {
if (appRoots.contains( this))
it = appRoots.iterator();
else
throw new RuntimeException( "Unable to find package siblings.");
}
else
it = parent.get_Children().iterator();
while (it.hasNext()) {
NameHolder sibling = it.next();
if (sibling == this)
continue;
if (((sibling.is_Package()) && (sibling.get_PackageName().equals( name))) ||
((sibling.is_Class()) && (sibling.get_ClassName().equals( name))))
return true;
}
return false;
}
public void dump( String indentation)
{
G.v().out.print( indentation + "\"" + originalName + "\", \"" + packageName + "\", \"" + className + "\" (");
if (is_Class())
G.v().out.print("c");
if (is_Package())
G.v().out.print("p");
G.v().out.println( ")");
Iterator<NameHolder> it = children.iterator();
while (it.hasNext())
it.next().dump( indentation + " ");
}
}
private boolean fixed = false;
private final ArrayList<NameHolder> appRoots = new ArrayList<NameHolder>();
private final ArrayList<NameHolder> otherRoots = new ArrayList<NameHolder>();
private final HashSet<String> keywords = new HashSet<String>();
private char fileSep;
private String classPath, pathSep;
public void fixNames()
{
if (fixed)
return;
String[] keywordArray =
{
"abstract", "default", "if", "private", "this", "boolean",
"do", "implements", "protected", "throw", "break",
"double", "import", "public", "throws", "byte", "else",
"instanceof", "return", "transient", "case", "extends",
"int", "short", "try", "catch", "final", "interface",
"static", "void", "char", "finally", "long", "strictfp",
"volatile", "class", "float", "native", "super", "while",
"const", "for", "new", "switch", "continue", "goto",
"package", "synchronized", "true", "false", "null"
};
for (String element : keywordArray)
keywords.add( element);
Iterator classIt = Scene.v().getLibraryClasses().iterator();
while (classIt.hasNext())
add_ClassName( ((SootClass) classIt.next()).getName(), otherRoots);
classIt = Scene.v().getApplicationClasses().iterator();
while (classIt.hasNext())
add_ClassName( ((SootClass) classIt.next()).getName(), appRoots);
Iterator<NameHolder> arit = appRoots.iterator();
while (arit.hasNext())
arit.next().fix_ClassNames( "");
arit = appRoots.iterator();
while (arit.hasNext())
arit.next().fix_PackageNames();
fileSep = System.getProperty( "file.separator").charAt(0);
pathSep = System.getProperty( "path.separator");
classPath = System.getProperty( "java.class.path");
fixed = true;
}
private void add_ClassName( String className, ArrayList<NameHolder> roots)
{
ArrayList<NameHolder> children = roots;
NameHolder curNode = null;
StringTokenizer st = new StringTokenizer( className, ".");
while (st.hasMoreTokens()) {
String curName = st.nextToken();
NameHolder child = null;
boolean found = false;
Iterator<NameHolder> lit = children.iterator();
while (lit.hasNext()) {
child = lit.next();
if (child.get_OriginalName().equals( curName)) {
if (st.hasMoreTokens() == false)
child.set_ClassAttr();
found = true;
break;
}
}
if (!found) {
child = new NameHolder( curName, curNode, st.hasMoreTokens() == false);
children.add( child);
}
curNode = child;
children = child.get_Children();
}
}
public boolean package_ContainsClass( String classpathDir, String packageName, String className)
{
File p = new File( classpathDir);
if (p.exists() == false)
return false;
packageName = packageName.replace( '.', fileSep);
if ((packageName.length() > 0) && (packageName.charAt( packageName.length() - 1) != fileSep))
packageName += fileSep;
String name = packageName + className + ".class";
if (p.isDirectory()) {
if ((classpathDir.length() > 0) && (classpathDir.charAt( classpathDir.length() - 1) != fileSep))
classpathDir += fileSep;
return (new File( classpathDir + name)).exists();
}
else {
JarFile jf = null;
try {
jf = new JarFile( p);
}
catch (IOException ioe) {
return false;
}
return (jf.getJarEntry( name) != null);
}
}
IterableSet patch_PackageContext( IterableSet currentContext)
{
IterableSet newContext = new IterableSet();
Iterator it = currentContext.iterator();
while (it.hasNext()) {
String
currentPackage = (String) it.next(),
newPackage = null;
StringTokenizer st = new StringTokenizer( currentPackage, ".");
if (st.hasMoreTokens() == false) {
newContext.add( currentPackage);
continue;
}
String firstToken = st.nextToken();
Iterator<NameHolder> arit = appRoots.iterator();
while (arit.hasNext()) {
NameHolder h = arit.next();
if (h.get_PackageName().equals( firstToken)) {
newPackage = h.get_OriginalPackageName( st);
break;
}
}
if (newPackage != null)
newContext.add( newPackage);
else
newContext.add( currentPackage);
}
return newContext;
}
}