You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
6.7 KiB
265 lines
6.7 KiB
/* Identifier Copyright (C) 1999 Jochen Hoenicke.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
package jode.obfuscator;
|
|
import jode.GlobalOptions;
|
|
import java.io.*;
|
|
import @COLLECTIONS@.Map;
|
|
import @COLLECTIONS@.Iterator;
|
|
|
|
public abstract class Identifier {
|
|
/**
|
|
* This is a doubly list of identifiers, that must have always
|
|
* have the same names, and same preserved settings.
|
|
*/
|
|
private Identifier right = null;
|
|
private Identifier left = null;
|
|
|
|
private boolean reachable = false;
|
|
private boolean preserved = false;
|
|
|
|
private String alias = null;
|
|
private boolean wasAliased = false;
|
|
|
|
public Identifier(String alias) {
|
|
this.alias = alias;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns true, if this identifier is reachable in some way, false if it
|
|
* is dead and can be removed.
|
|
*/
|
|
public final boolean isReachable() {
|
|
return reachable;
|
|
}
|
|
|
|
/**
|
|
* true, if this identifier must preserve its name, false if the
|
|
* name may be obfuscated.
|
|
*/
|
|
public final boolean isPreserved() {
|
|
return preserved;
|
|
}
|
|
|
|
/**
|
|
* Marks this identifier as preserved. This will also make the
|
|
* identifier reachable, if it isn't already.
|
|
*
|
|
* You shouldn't call this directly, but use setPreserved instead.
|
|
*/
|
|
protected void setSinglePreserved() {
|
|
}
|
|
|
|
/**
|
|
* Marks this identifier as reachable.
|
|
*
|
|
* You should override this method for method identifier, which may
|
|
* mark other methods as reachable.
|
|
*
|
|
* You shouldn't call this directly, but use setReachable instead.
|
|
*/
|
|
protected void setSingleReachable() {
|
|
if (getParent() != null)
|
|
getParent().setReachable();
|
|
}
|
|
|
|
/**
|
|
* Mark all shadows as reachable.
|
|
*/
|
|
public void setReachable() {
|
|
if (!reachable) {
|
|
reachable = true;
|
|
setSingleReachable();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mark all shadows as preserved.
|
|
*/
|
|
public void setPreserved() {
|
|
if (!preserved) {
|
|
preserved = true;
|
|
Identifier ptr = this;
|
|
while (ptr != null) {
|
|
ptr.setSinglePreserved();
|
|
ptr = ptr.left;
|
|
}
|
|
ptr = right;
|
|
while (ptr != null) {
|
|
ptr.setSinglePreserved();
|
|
ptr = ptr.right;
|
|
}
|
|
}
|
|
}
|
|
|
|
public Identifier getRepresentative() {
|
|
Identifier ptr = this;
|
|
while (ptr.left != null)
|
|
ptr = ptr.left;
|
|
return ptr;
|
|
}
|
|
|
|
public final boolean isRepresentative() {
|
|
return left == null;
|
|
}
|
|
|
|
public final boolean wasAliased() {
|
|
return getRepresentative().wasAliased;
|
|
}
|
|
|
|
public final void setAlias(String name) {
|
|
if (name != null) {
|
|
Identifier rep = getRepresentative();
|
|
rep.wasAliased = true;
|
|
rep.alias = name;
|
|
}
|
|
}
|
|
|
|
public final String getAlias() {
|
|
return getRepresentative().alias;
|
|
}
|
|
|
|
/**
|
|
* Mark that this identifier and the given identifier must always have
|
|
* the same name.
|
|
*/
|
|
public void addShadow(Identifier orig) {
|
|
if (isPreserved() && !orig.isPreserved())
|
|
orig.setPreserved();
|
|
else if (!isPreserved() && orig.isPreserved())
|
|
setPreserved();
|
|
|
|
Identifier ptr = this;
|
|
while (ptr.right != null)
|
|
ptr = ptr.right;
|
|
|
|
/* Check if orig is already on the ptr chain */
|
|
Identifier check = orig;
|
|
while (check.right != null)
|
|
check = check.right;
|
|
if (check == ptr)
|
|
return;
|
|
|
|
while (orig.left != null)
|
|
orig = orig.left;
|
|
ptr.right = orig;
|
|
orig.left = ptr;
|
|
}
|
|
|
|
static int serialnr = 0;
|
|
|
|
public void buildTable(Renamer renameRule) {
|
|
if (!isReachable()
|
|
&& (Main.stripping & Main.STRIP_UNREACH) != 0)
|
|
return;
|
|
|
|
if (isPreserved()) {
|
|
if (GlobalOptions.verboseLevel > 4)
|
|
GlobalOptions.err.println(toString() + " is preserved");
|
|
} else {
|
|
Identifier rep = getRepresentative();
|
|
if (!rep.wasAliased) {
|
|
rep.wasAliased = true;
|
|
|
|
// set alias to empty string, so it won't conflict!
|
|
rep.alias = "";
|
|
Iterator aliases = renameRule.generateNames(this);
|
|
next_alias:
|
|
for (;;) {
|
|
String newAlias = (String) aliases.next();
|
|
Identifier ptr = rep;
|
|
while (ptr != null) {
|
|
if (ptr.conflicting(newAlias))
|
|
continue next_alias;
|
|
ptr = ptr.right;
|
|
}
|
|
setAlias(newAlias.toString());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (Iterator i = getChilds(); i.hasNext(); )
|
|
((Identifier)i.next()).buildTable(renameRule);
|
|
}
|
|
|
|
public void writeTable(Map table, boolean reversed) {
|
|
if (!isReachable()
|
|
&& (Main.stripping & Main.STRIP_UNREACH) != 0)
|
|
return;
|
|
|
|
if (getAlias().length() != 0) {
|
|
String name = getName();
|
|
Identifier outer = getParent();
|
|
while (outer != null && outer.getAlias().length() == 0) {
|
|
if (outer.getName().length() > 0)
|
|
name = outer.getName() + "." + name;
|
|
outer = outer.getParent();
|
|
}
|
|
if (reversed)
|
|
table.put(getFullAlias(), name);
|
|
else
|
|
table.put(getFullName(), getAlias());
|
|
}
|
|
|
|
for (Iterator i = getChilds(); i.hasNext(); )
|
|
((Identifier)i.next()).writeTable(table, reversed);
|
|
}
|
|
|
|
public void readTable(Map table) {
|
|
Identifier rep = getRepresentative();
|
|
if (!rep.wasAliased) {
|
|
String newAlias = (String) table.get(getFullName());
|
|
if (newAlias != null) {
|
|
rep.wasAliased = true;
|
|
rep.setAlias(newAlias);
|
|
}
|
|
}
|
|
for (Iterator i = getChilds(); i.hasNext(); )
|
|
((Identifier)i.next()).readTable(table);
|
|
}
|
|
|
|
public void applyPreserveRule(IdentifierMatcher preserveRule) {
|
|
if (preserveRule.matches(this)) {
|
|
System.err.println("preserving: "+this);
|
|
setReachable();
|
|
Identifier ident = this;
|
|
while (ident != null) {
|
|
ident.setPreserved();
|
|
ident = ident.getParent();
|
|
}
|
|
}
|
|
for (Iterator i = getChilds(); i.hasNext(); )
|
|
((Identifier)i.next()).applyPreserveRule(preserveRule);
|
|
}
|
|
public abstract Iterator getChilds();
|
|
public abstract Identifier getParent();
|
|
public abstract String getName();
|
|
public abstract String getType();
|
|
public abstract String getFullName();
|
|
public abstract String getFullAlias();
|
|
public abstract boolean conflicting(String newAlias);
|
|
|
|
/**
|
|
* This is called by ClassBundle when it a class is added with
|
|
* ClassBundle.analyzeIdentifier().
|
|
*/
|
|
public void analyze() {
|
|
}
|
|
}
|
|
|