make use of collection classes

conflictFields, conflictMethod added and reworked
serialization preserving added


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@979 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 25 years ago
parent 8cffa60d13
commit 20b87f4b55
  1. 571
      jode/jode/obfuscator/ClassIdentifier.java

@ -19,27 +19,36 @@
package jode.obfuscator; package jode.obfuscator;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.Obfuscator;
import jode.bytecode.*; import jode.bytecode.*;
///#ifdef JDK12 ///#ifdef JDK12
///import java.util.Comparator;
///import java.util.Collection;
///import java.util.Collections; ///import java.util.Collections;
///import java.util.Arrays; ///import java.util.Arrays;
///import java.util.Iterator;
///import java.util.List;
///import java.util.LinkedList;
///import java.util.Map;
///#else ///#else
import jode.util.Comparator;
import jode.util.Collection;
import jode.util.Collections; import jode.util.Collections;
import jode.util.Arrays; import jode.util.Arrays;
import jode.util.Iterator;
import jode.util.List;
import jode.util.LinkedList;
import jode.util.Map;
///#endif ///#endif
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.OutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Random; import java.util.Random;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
public class ClassIdentifier extends Identifier { public class ClassIdentifier extends Identifier {
ClassBundle bundle;
PackageIdentifier pack; PackageIdentifier pack;
String name; String name;
ClassInfo info; ClassInfo info;
@ -52,23 +61,21 @@ public class ClassIdentifier extends Identifier {
* are MethodIdentifier * are MethodIdentifier
*/ */
Identifier[] identifiers; Identifier[] identifiers;
Vector knownSubClasses = new Vector(); List knownSubClasses = new LinkedList();
Vector virtualReachables = new Vector(); List virtualReachables = new LinkedList();
public ClassIdentifier(ClassBundle bundle, PackageIdentifier pack, public ClassIdentifier(PackageIdentifier pack,
String name, ClassInfo info) { String name, ClassInfo info) {
super(name); super(name);
this.bundle = bundle;
this.pack = pack; this.pack = pack;
this.name = name; this.name = name;
this.info = info; this.info = info;
} }
public void addSubClass(ClassIdentifier ci) { public void addSubClass(ClassIdentifier ci) {
knownSubClasses.addElement(ci); knownSubClasses.add(ci);
Enumeration enum = virtualReachables.elements(); for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) {
while (enum.hasMoreElements()) { String[] method = (String[]) i.next();
String[] method = (String[]) enum.nextElement();
ci.reachableIdentifier(method[0], method[1], true); ci.reachableIdentifier(method[0], method[1], true);
} }
} }
@ -96,15 +103,6 @@ public class ClassIdentifier extends Identifier {
} }
} }
public void applyPreserveRule(int preserveRule) {
if ((preserveRule & (info.getModifiers() ^ Modifier.PRIVATE)) != 0) {
setReachable();
setPreserved();
}
for (int i=0; i< identifiers.length; i++)
identifiers[i].applyPreserveRule(preserveRule);
}
public void reachableIdentifier(String name, String typeSig, public void reachableIdentifier(String name, String typeSig,
boolean isVirtual) { boolean isVirtual) {
boolean found = false; boolean found = false;
@ -119,12 +117,10 @@ public class ClassIdentifier extends Identifier {
/*XXXXXXXX super reachableIdentifier */ /*XXXXXXXX super reachableIdentifier */
} /*ELSE*/ } /*ELSE*/
if (isVirtual) { if (isVirtual) {
Enumeration enum = knownSubClasses.elements(); for (Iterator i = knownSubClasses.iterator(); i.hasNext(); )
while (enum.hasMoreElements()) ((ClassIdentifier)i.next())
((ClassIdentifier)enum.nextElement())
.reachableIdentifier(name, typeSig, false); .reachableIdentifier(name, typeSig, false);
virtualReachables.addElement virtualReachables.add(new String[] { name, typeSig });
(new String[] { name, typeSig });
} }
} }
@ -138,6 +134,120 @@ public class ClassIdentifier extends Identifier {
} }
} }
/**
* This is partly taken from the classpath project.
*/
public long calcSerialVersionUID() {
final MessageDigest md;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
GlobalOptions.err.println("Can't calculate serialVersionUID");
return 0L;
}
OutputStream digest = new OutputStream() {
public void write(int b) {
md.update((byte) b);
}
public void write(byte[] data, int offset, int length) {
md.update(data, offset, length);
}
};
DataOutputStream out = new DataOutputStream(digest);
try {
out.writeUTF(info.getName());
int modifiers = info.getModifiers();
// just look at interesting bits
modifiers = modifiers & ( Modifier.ABSTRACT | Modifier.FINAL
| Modifier.INTERFACE | Modifier.PUBLIC );
out.writeInt(modifiers);
ClassInfo[] interfaces
= (ClassInfo[]) info.getInterfaces().clone();
Arrays.sort(interfaces, new Comparator() {
public int compare( Object o1, Object o2 ) {
return ((ClassInfo)o1).getName()
.compareTo(((ClassInfo)o2).getName());
}
});
for( int i=0; i < interfaces.length; i++ ) {
out.writeUTF(interfaces[i].getName());
}
Comparator identCmp = new Comparator() {
public int compare(Object o1, Object o2) {
Identifier i1 = (Identifier)o1;
Identifier i2 = (Identifier)o2;
boolean special1 = (i1.equals("<init>")
|| i1.equals("<clinit>"));
boolean special2 = (i2.equals("<init>")
|| i2.equals("<clinit>"));
// Put constructors at the beginning
if (special1 != special2) {
return special1 ? -1 : 1;
}
int comp = i1.getName().compareTo(i2.getName());
if (comp != 0) {
return comp;
} else {
return i1.getType().compareTo(i2.getType());
}
}
};
List idents = Arrays.asList((Object[]) identifiers.clone());
List fields = idents.subList(0, fieldCount);
List methods = idents.subList(fieldCount, idents.size());
Collections.sort(fields, identCmp);
Collections.sort(methods, identCmp);
for (Iterator i = fields.iterator(); i.hasNext();) {
FieldIdentifier field = (FieldIdentifier) i.next();
modifiers = field.info.getModifiers();
if ((modifiers & Modifier.PRIVATE) != 0
&& (modifiers & (Modifier.STATIC
| Modifier.TRANSIENT)) != 0)
continue;
out.writeUTF(field.getName());
out.writeInt(modifiers);
out.writeUTF(field.getType());
}
for(Iterator i = methods.iterator(); i.hasNext(); ) {
MethodIdentifier method = (MethodIdentifier) i.next();
modifiers = method.info.getModifiers();
if( Modifier.isPrivate(modifiers))
continue;
out.writeUTF(method.getName());
out.writeInt(modifiers);
// the replacement of '/' with '.' was needed to make computed
// SUID's agree with those computed by JDK
out.writeUTF(method.getType().replace('/', '.'));
}
out.close();
byte[] sha = md.digest();
long result = 0;
for (int i=0; i < 8; i++) {
result += (long)(sha[i] & 0xFF) << (8 * i);
}
return result;
} catch (IOException ex) {
ex.printStackTrace();
GlobalOptions.err.println("Can't calculate serialVersionUID");
return 0L;
}
}
/** /**
* Preserve all fields, that are necessary, to serialize * Preserve all fields, that are necessary, to serialize
* a compatible class. * a compatible class.
@ -145,16 +255,46 @@ public class ClassIdentifier extends Identifier {
public void preserveSerializable() { public void preserveSerializable() {
preserveIdentifier("writeObject", "(Ljava.io.ObjectOutputStream)V"); preserveIdentifier("writeObject", "(Ljava.io.ObjectOutputStream)V");
preserveIdentifier("readObject", "(Ljava.io.ObjectOutputStream)V"); preserveIdentifier("readObject", "(Ljava.io.ObjectOutputStream)V");
if (Obfuscator.preserveSerial) { if ((Main.options & Main.OPTION_PRESERVESERIAL) != 0) {
/* XXX - add a field serializableVersionUID if not existent */ setPreserved();
preserveIdentifier("serializableVersionUID", "I"); boolean hasSerialUID = false;
for (int i=0; i< fieldCount; i++) {
if ("serialVersionUID".equals(identifiers[i].getName())
&& "J".equals(identifiers[i].getType())) {
identifiers[i].setReachable();
identifiers[i].setPreserved();
hasSerialUID = true;
break;
}
}
if (!hasSerialUID) {
/* add a field serializableVersionUID if not existent */
long serialVersion = calcSerialVersionUID();
Identifier[] newIdents = new Identifier[identifiers.length+1];
System.arraycopy(identifiers, 0, newIdents, 0, fieldCount);
System.arraycopy(identifiers, fieldCount,
newIdents, fieldCount + 1,
identifiers.length - fieldCount);
FieldInfo UIDField = new FieldInfo
(info, "serialVersionUID", "J",
Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
UIDField.setConstant(new Long(serialVersion));
FieldIdentifier fident = new FieldIdentifier(this, UIDField);
fident.setPreserved();
fident.setReachable();
newIdents[fieldCount++] = fident;
identifiers = newIdents;
}
for (int i=0; i < fieldCount; i++) { for (int i=0; i < fieldCount; i++) {
FieldIdentifier ident = (FieldIdentifier) identifiers[i]; FieldIdentifier ident = (FieldIdentifier) identifiers[i];
if ((ident.info.getModifiers() if ((ident.info.getModifiers()
& (Modifier.TRANSIENT | Modifier.STATIC)) == 0) & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
identifiers[i].setPreserved(); ident.setPreserved();
ident.setNotConstant();
}
/* XXX - only preserve them if writeObject not existent /* XXX - only preserve them if writeObject not existent
* or if writeObject calls defaultWriteObject * or if writeObject calls defaultWriteObject, and similar
* for readObject
*/ */
} }
} }
@ -169,16 +309,16 @@ public class ClassIdentifier extends Identifier {
public void setSingleReachable() { public void setSingleReachable() {
super.setSingleReachable(); super.setSingleReachable();
bundle.analyzeIdentifier(this); Main.getClassBundle().analyzeIdentifier(this);
} }
public void analyzeSuperClasses(ClassInfo superclass) { public void analyzeSuperClasses(ClassInfo superclass) {
while (superclass != null) { while (superclass != null) {
if (superclass.getName().equals("java.lang.Serializable")) if (superclass.getName().equals("java.io.Serializable"))
preserveSerializable(); preserveSerializable();
ClassIdentifier superident ClassIdentifier superident = Main.getClassBundle()
= bundle.getClassIdentifier(superclass.getName()); .getClassIdentifier(superclass.getName());
if (superident != null) { if (superident != null) {
superident.addSubClass(this); superident.addSubClass(this);
} else { } else {
@ -217,8 +357,8 @@ public class ClassIdentifier extends Identifier {
if (superclass.getName().equals("java.lang.Serializable")) if (superclass.getName().equals("java.lang.Serializable"))
preserveSerializable(); preserveSerializable();
ClassIdentifier superident ClassIdentifier superident = Main.getClassBundle()
= bundle.getClassIdentifier(superclass.getName()); .getClassIdentifier(superclass.getName());
if (superident != null) { if (superident != null) {
for (int i=superident.fieldCount; for (int i=superident.fieldCount;
i < superident.identifiers.length; i++) { i < superident.identifiers.length; i++) {
@ -261,7 +401,7 @@ public class ClassIdentifier extends Identifier {
FieldInfo[] finfos = info.getFields(); FieldInfo[] finfos = info.getFields();
MethodInfo[] minfos = info.getMethods(); MethodInfo[] minfos = info.getMethods();
if (Obfuscator.swapOrder) { if (Main.swapOrder) {
Random rand = new Random(); Random rand = new Random();
Collections.shuffle(Arrays.asList(finfos), rand); Collections.shuffle(Arrays.asList(finfos), rand);
Collections.shuffle(Arrays.asList(minfos), rand); Collections.shuffle(Arrays.asList(minfos), rand);
@ -275,7 +415,7 @@ public class ClassIdentifier extends Identifier {
identifiers[fieldCount + i] identifiers[fieldCount + i]
= new MethodIdentifier(this, minfos[i]); = new MethodIdentifier(this, minfos[i]);
if (identifiers[fieldCount + i].getName().equals("<clinit>")) { if (identifiers[fieldCount + i].getName().equals("<clinit>")) {
/* If there is a static initializer, it is automagically /* If there is a static initializer, it is automatically
* reachable (even if this class wouldn't be otherwise). * reachable (even if this class wouldn't be otherwise).
*/ */
identifiers[fieldCount + i].setPreserved(); identifiers[fieldCount + i].setPreserved();
@ -289,18 +429,26 @@ public class ClassIdentifier extends Identifier {
ifaceNames = new String[ifaces.length]; ifaceNames = new String[ifaces.length];
for (int i=0; i < ifaces.length; i++) { for (int i=0; i < ifaces.length; i++) {
ifaceNames[i] = ifaces[i].getName(); ifaceNames[i] = ifaces[i].getName();
ClassIdentifier ifaceident ClassIdentifier ifaceident = Main.getClassBundle()
= bundle.getClassIdentifier(ifaceNames[i]); .getClassIdentifier(ifaceNames[i]);
initSuperClasses(ifaces[i]); initSuperClasses(ifaces[i]);
} }
if (info.getSuperclass() != null) { if (info.getSuperclass() != null) {
superName = info.getSuperclass().getName(); superName = info.getSuperclass().getName();
ClassIdentifier superident ClassIdentifier superident = Main.getClassBundle()
= bundle.getClassIdentifier(superName); .getClassIdentifier(superName);
initSuperClasses(info.getSuperclass()); initSuperClasses(info.getSuperclass());
} }
if ((Main.stripping & Main.STRIP_SOURCE) != 0) {
info.setSourceFile(null);
}
if ((Main.stripping & Main.STRIP_INNERINFO) != 0) {
info.setInnerClasses(new InnerClassInfo[0]);
info.setOuterClasses(new InnerClassInfo[0]);
info.setExtraClasses(new InnerClassInfo[0]);
}
// load inner classes // load inner classes
InnerClassInfo[] innerClasses = info.getInnerClasses(); InnerClassInfo[] innerClasses = info.getInnerClasses();
InnerClassInfo[] outerClasses = info.getOuterClasses(); InnerClassInfo[] outerClasses = info.getOuterClasses();
@ -308,53 +456,69 @@ public class ClassIdentifier extends Identifier {
if (outerClasses != null) { if (outerClasses != null) {
for (int i=0; i < outerClasses.length; i++) { for (int i=0; i < outerClasses.length; i++) {
if (outerClasses[i].outer != null) { if (outerClasses[i].outer != null) {
bundle.getClassIdentifier(outerClasses[i].outer); Main.getClassBundle()
.getClassIdentifier(outerClasses[i].outer);
} }
} }
} }
if (innerClasses != null) { if (innerClasses != null) {
for (int i=0; i < innerClasses.length; i++) { for (int i=0; i < innerClasses.length; i++) {
bundle.getClassIdentifier(innerClasses[i].inner); Main.getClassBundle()
.getClassIdentifier(innerClasses[i].inner);
} }
} }
if (extraClasses != null) { if (extraClasses != null) {
for (int i=0; i < extraClasses.length; i++) { for (int i=0; i < extraClasses.length; i++) {
bundle.getClassIdentifier(extraClasses[i].inner); Main.getClassBundle()
.getClassIdentifier(extraClasses[i].inner);
if (extraClasses[i].outer != null) if (extraClasses[i].outer != null)
bundle.getClassIdentifier(extraClasses[i].outer); Main.getClassBundle()
.getClassIdentifier(extraClasses[i].outer);
} }
} }
} }
public void buildTable(int renameRule) { public void buildTable(Renamer renameRule) {
super.buildTable(renameRule); super.buildTable(renameRule);
for (int i=0; i < identifiers.length; i++) for (int i=0; i < identifiers.length; i++)
if (!Obfuscator.shouldStrip || identifiers[i].isReachable()) if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable())
identifiers[i].buildTable(renameRule); identifiers[i].buildTable(renameRule);
} }
public void readTable(Hashtable table) { public void readTable(Map table) {
super.readTable(table); super.readTable(table);
for (int i=0; i < identifiers.length; i++) for (int i=0; i < identifiers.length; i++)
if (!Obfuscator.shouldStrip || identifiers[i].isReachable()) if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable())
identifiers[i].readTable(table); identifiers[i].readTable(table);
} }
public void writeTable(Hashtable table) { public void writeTable(Map table) {
super.writeTable(table); super.writeTable(table);
for (int i=0; i < identifiers.length; i++) for (int i=0; i < identifiers.length; i++)
if (!Obfuscator.shouldStrip || identifiers[i].isReachable()) if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable())
identifiers[i].writeTable(table); identifiers[i].writeTable(table);
} }
public void addIfaces(Vector result, String[] ifaces) { /**
* Add the ClassInfo objects of the interfaces of ancestor. But if
* an interface of ancestor is not reachable it will add its interfaces
* instead.
* @param result The Collection where the interfaces should be added to.
* @param ancestor The ancestor whose interfaces should be added.
*/
public void addIfaces(Collection result, ClassIdentifier ancestor) {
String[] ifaces = ancestor.ifaceNames;
ClassInfo[] ifaceInfos = ancestor.info.getInterfaces();
for (int i=0; i < ifaces.length; i++) { for (int i=0; i < ifaces.length; i++) {
ClassIdentifier ifaceident ClassIdentifier ifaceident
= bundle.getClassIdentifier(ifaces[i]); = Main.getClassBundle().getClassIdentifier(ifaces[i]);
if (ifaceident != null && !ifaceident.isReachable()) if (ifaceident != null && !ifaceident.isReachable())
addIfaces(result, ifaceident.ifaceNames); addIfaces(result, ifaceident);
else else
result.addElement(ClassInfo.forName(ifaces[i])); result.add(ifaceInfos[i]);
} }
} }
@ -366,24 +530,23 @@ public class ClassIdentifier extends Identifier {
* other entries are the interfaces. * other entries are the interfaces.
*/ */
public void transformSuperIfaces() { public void transformSuperIfaces() {
if (!Obfuscator.shouldStrip) if ((Main.stripping & Main.STRIP_UNREACH) == 0)
return; return;
Vector newIfaces = new Vector(); Collection newIfaces = new LinkedList();
addIfaces(newIfaces, ifaceNames); ClassIdentifier ancestor = this;
String nameOfSuper = superName;
while(true) { while(true) {
addIfaces(newIfaces, ancestor);
ClassIdentifier superident ClassIdentifier superident
= bundle.getClassIdentifier(nameOfSuper); = Main.getClassBundle().getClassIdentifier(ancestor.superName);
if (superident == null || superident.isReachable()) if (superident == null || superident.isReachable())
break; break;
ancestor = superident;
addIfaces(newIfaces, superident.ifaceNames);
nameOfSuper = superident.superName;
} }
ClassInfo[] ifaces = new ClassInfo[newIfaces.size()]; ClassInfo superInfo = ancestor.info.getSuperclass();
newIfaces.copyInto(ifaces); ClassInfo[] ifaces = (ClassInfo[])
info.setSuperclass(ClassInfo.forName(nameOfSuper)); newIfaces.toArray(new ClassInfo[newIfaces.size()]);
info.setSuperclass(superInfo);
info.setInterfaces(ifaces); info.setInterfaces(ifaces);
} }
@ -391,11 +554,11 @@ public class ClassIdentifier extends Identifier {
InnerClassInfo[] outerClasses = info.getOuterClasses(); InnerClassInfo[] outerClasses = info.getOuterClasses();
if (outerClasses != null) { if (outerClasses != null) {
int newOuterCount = outerClasses.length; int newOuterCount = outerClasses.length;
if (Obfuscator.shouldStrip) { if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
for (int i=0; i < outerClasses.length; i++) { for (int i=0; i < outerClasses.length; i++) {
if (outerClasses[i].outer != null) { if (outerClasses[i].outer != null) {
ClassIdentifier outerIdent ClassIdentifier outerIdent = Main.getClassBundle()
= bundle.getClassIdentifier(outerClasses[i].outer); .getClassIdentifier(outerClasses[i].outer);
if (outerIdent != null && !outerIdent.isReachable()) if (outerIdent != null && !outerIdent.isReachable())
newOuterCount--; newOuterCount--;
} }
@ -409,7 +572,8 @@ public class ClassIdentifier extends Identifier {
String lastClass = getFullAlias(); String lastClass = getFullAlias();
for (int i=0; i<outerClasses.length; i++) { for (int i=0; i<outerClasses.length; i++) {
ClassIdentifier outerIdent = outerClasses[i].outer != null ClassIdentifier outerIdent = outerClasses[i].outer != null
? bundle.getClassIdentifier(outerClasses[i].outer) ? (Main.getClassBundle()
.getClassIdentifier(outerClasses[i].outer))
: null; : null;
if (outerIdent != null && !outerIdent.isReachable()) if (outerIdent != null && !outerIdent.isReachable())
@ -435,10 +599,10 @@ public class ClassIdentifier extends Identifier {
InnerClassInfo[] innerClasses = info.getInnerClasses(); InnerClassInfo[] innerClasses = info.getInnerClasses();
if (innerClasses != null) { if (innerClasses != null) {
int newInnerCount = innerClasses.length; int newInnerCount = innerClasses.length;
if (Obfuscator.shouldStrip) { if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
for (int i=0; i < innerClasses.length; i++) { for (int i=0; i < innerClasses.length; i++) {
ClassIdentifier innerIdent ClassIdentifier innerIdent = Main.getClassBundle()
= bundle.getClassIdentifier(innerClasses[i].inner); .getClassIdentifier(innerClasses[i].inner);
if (innerIdent != null && !innerIdent.isReachable()) if (innerIdent != null && !innerIdent.isReachable())
newInnerCount--; newInnerCount--;
} }
@ -449,10 +613,11 @@ public class ClassIdentifier extends Identifier {
InnerClassInfo[] newInners = new InnerClassInfo[newInnerCount]; InnerClassInfo[] newInners = new InnerClassInfo[newInnerCount];
int pos = 0; int pos = 0;
for (int i=0; i<innerClasses.length; i++) { for (int i=0; i<innerClasses.length; i++) {
ClassIdentifier innerIdent ClassIdentifier innerIdent = Main.getClassBundle()
= bundle.getClassIdentifier(innerClasses[i].inner); .getClassIdentifier(innerClasses[i].inner);
if (innerIdent != null if (innerIdent != null
&& Obfuscator.shouldStrip && !innerIdent.isReachable()) && (Main.stripping & Main.STRIP_UNREACH) != 0
&& !innerIdent.isReachable())
continue; continue;
String inner = innerIdent == null String inner = innerIdent == null
@ -474,13 +639,14 @@ public class ClassIdentifier extends Identifier {
InnerClassInfo[] extraClasses = info.getExtraClasses(); InnerClassInfo[] extraClasses = info.getExtraClasses();
if (extraClasses != null) { if (extraClasses != null) {
int newExtraCount = extraClasses.length; int newExtraCount = extraClasses.length;
if (Obfuscator.shouldStrip) { if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
for (int i=0; i < extraClasses.length; i++) { for (int i=0; i < extraClasses.length; i++) {
ClassIdentifier outerIdent = extraClasses[i].outer != null ClassIdentifier outerIdent = extraClasses[i].outer != null
? bundle.getClassIdentifier(extraClasses[i].outer) ? (Main.getClassBundle()
.getClassIdentifier(extraClasses[i].outer))
: null; : null;
ClassIdentifier innerIdent ClassIdentifier innerIdent = Main.getClassBundle()
= bundle.getClassIdentifier(extraClasses[i].inner); .getClassIdentifier(extraClasses[i].inner);
if ((outerIdent != null && !outerIdent.isReachable()) if ((outerIdent != null && !outerIdent.isReachable())
|| (innerIdent != null && !innerIdent.isReachable())) || (innerIdent != null && !innerIdent.isReachable()))
newExtraCount--; newExtraCount--;
@ -496,10 +662,11 @@ public class ClassIdentifier extends Identifier {
int pos = 0; int pos = 0;
for (int i=0; i<extraClasses.length; i++) { for (int i=0; i<extraClasses.length; i++) {
ClassIdentifier outerIdent = extraClasses[i].outer != null ClassIdentifier outerIdent = extraClasses[i].outer != null
? bundle.getClassIdentifier(extraClasses[i].outer) ? (Main.getClassBundle()
.getClassIdentifier(extraClasses[i].outer))
: null; : null;
ClassIdentifier innerIdent ClassIdentifier innerIdent = Main.getClassBundle()
= bundle.getClassIdentifier(extraClasses[i].inner); .getClassIdentifier(extraClasses[i].inner);
if (innerIdent != null && !innerIdent.isReachable()) if (innerIdent != null && !innerIdent.isReachable())
continue; continue;
@ -534,7 +701,7 @@ public class ClassIdentifier extends Identifier {
transformInnerClasses(); transformInnerClasses();
int newFieldCount = 0, newMethodCount = 0; int newFieldCount = 0, newMethodCount = 0;
if (Obfuscator.shouldStrip) { if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
for (int i=0; i < fieldCount; i++) for (int i=0; i < fieldCount; i++)
if (identifiers[i].isReachable()) if (identifiers[i].isReachable())
newFieldCount++; newFieldCount++;
@ -551,14 +718,16 @@ public class ClassIdentifier extends Identifier {
newFieldCount = newMethodCount = 0; newFieldCount = newMethodCount = 0;
for (int i=0; i < fieldCount; i++) { for (int i=0; i < fieldCount; i++) {
if (!Obfuscator.shouldStrip || identifiers[i].isReachable()) { if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable()) {
((FieldIdentifier)identifiers[i]).doTransformations(); ((FieldIdentifier)identifiers[i]).doTransformations();
newFields[newFieldCount++] newFields[newFieldCount++]
= ((FieldIdentifier)identifiers[i]).info; = ((FieldIdentifier)identifiers[i]).info;
} }
} }
for (int i=fieldCount; i < identifiers.length; i++) { for (int i=fieldCount; i < identifiers.length; i++) {
if (!Obfuscator.shouldStrip || identifiers[i].isReachable()) { if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable()) {
((MethodIdentifier)identifiers[i]).doTransformations(); ((MethodIdentifier)identifiers[i]).doTransformations();
newMethods[newMethodCount++] newMethods[newMethodCount++]
= ((MethodIdentifier)identifiers[i]).info; = ((MethodIdentifier)identifiers[i]).info;
@ -609,6 +778,10 @@ public class ClassIdentifier extends Identifier {
return "Ljava/lang/Class;"; return "Ljava/lang/Class;";
} }
public Iterator getChilds() {
return Arrays.asList(identifiers).iterator();
}
public String toString() { public String toString() {
return "ClassIdentifier "+getFullName(); return "ClassIdentifier "+getFullName();
} }
@ -621,8 +794,8 @@ public class ClassIdentifier extends Identifier {
} }
for (int i=0; i < ifaceNames.length; i++) { for (int i=0; i < ifaceNames.length; i++) {
ClassIdentifier ifaceident ClassIdentifier ifaceident = Main.getClassBundle()
= bundle.getClassIdentifier(ifaceNames[i]); .getClassIdentifier(ifaceNames[i]);
if (ifaceident != null) { if (ifaceident != null) {
Identifier ident Identifier ident
= ifaceident.getIdentifier(fieldName, typeSig); = ifaceident.getIdentifier(fieldName, typeSig);
@ -632,8 +805,8 @@ public class ClassIdentifier extends Identifier {
} }
if (superName != null) { if (superName != null) {
ClassIdentifier superident ClassIdentifier superident = Main.getClassBundle()
= bundle.getClassIdentifier(superName); .getClassIdentifier(superName);
if (superident != null) { if (superident != null) {
Identifier ident Identifier ident
= superident.getIdentifier(fieldName, typeSig); = superident.getIdentifier(fieldName, typeSig);
@ -644,78 +817,209 @@ public class ClassIdentifier extends Identifier {
return null; return null;
} }
public static boolean containFieldAlias(ClassInfo clazz, public static boolean containsField
String fieldName, String typeSig) { (ClassInfo clazz, String name, String type, ModifierMatcher modMatch) {
FieldInfo[] finfos = clazz.getFields(); FieldInfo[] finfos = clazz.getFields();
for (int i=0; i< finfos.length; i++) { for (int i=0; i< finfos.length; i++) {
if (finfos[i].getName().equals(fieldName) if (finfos[i].getName().equals(name)
&& finfos[i].getType().startsWith(typeSig)) && finfos[i].getType().startsWith(type)
&& modMatch.matches(finfos[i].getModifiers()))
return true; return true;
} }
ClassInfo[] ifaces = clazz.getInterfaces(); ClassInfo[] ifaces = clazz.getInterfaces();
for (int i=0; i < ifaces.length; i++) { for (int i=0; i < ifaces.length; i++) {
if (containFieldAlias(ifaces[i], fieldName, typeSig)) if (containsField(ifaces[i], name, type, modMatch))
return true; return true;
} }
if (clazz.getSuperclass() != null) { if (clazz.getSuperclass() != null) {
if (containFieldAlias(clazz.getSuperclass(), if (containsField(clazz.getSuperclass(),
fieldName, typeSig)) name, type, modMatch))
return true; return true;
} }
return false; return false;
} }
public boolean containsFieldAliasDirectly(String fieldName, public static boolean containsMethod
String typeSig) { (ClassInfo clazz, String name, String type, ModifierMatcher modMatch) {
MethodInfo[] minfos = clazz.getMethods();
for (int i=0; i< minfos.length; i++) {
if (minfos[i].getName().equals(name)
&& minfos[i].getType().startsWith(type)
&& modMatch.matches(minfos[i].getModifiers()))
return true;
}
ClassInfo[] ifaces = clazz.getInterfaces();
for (int i=0; i < ifaces.length; i++) {
if (containsMethod(ifaces[i], name, type, modMatch))
return true;
}
if (clazz.getSuperclass() != null) {
if (containsMethod(clazz.getSuperclass(),
name, type, modMatch))
return true;
}
return false;
}
public boolean containsFieldAliasDirectly(String fieldName, String typeSig,
ModifierMatcher matcher) {
for (int i=0; i < fieldCount; i++) { for (int i=0; i < fieldCount; i++) {
if ((!Obfuscator.shouldStrip || identifiers[i].isReachable()) if (((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable())
&& identifiers[i].wasAliased()
&& identifiers[i].getAlias().equals(fieldName) && identifiers[i].getAlias().equals(fieldName)
&& identifiers[i].getType().startsWith(typeSig)) && identifiers[i].getType().startsWith(typeSig)
&& matcher.matches(identifiers[i]))
return true; return true;
} }
return false; return false;
} }
public boolean containFieldAlias(String fieldName, String typeSig) { public boolean containsMethodAliasDirectly(String methodName,
if (containsFieldAliasDirectly(fieldName,typeSig)) String paramType,
ModifierMatcher matcher) {
for (int i=fieldCount; i< identifiers.length; i++) {
if (((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable())
&& identifiers[i].wasAliased()
&& identifiers[i].getAlias().equals(methodName)
&& identifiers[i].getType().startsWith(paramType)
&& matcher.matches(identifiers[i]))
return true; return true;
for (int i=0; i < fieldCount; i++) { }
if ((!Obfuscator.shouldStrip || identifiers[i].isReachable()) return false;
&& identifiers[i].getAlias().equals(fieldName) }
&& identifiers[i].getType().startsWith(typeSig))
public boolean containsFieldAlias(String fieldName, String typeSig,
ModifierMatcher matcher) {
if (containsFieldAliasDirectly(fieldName, typeSig, matcher))
return true;
ModifierMatcher packMatcher = matcher.forceAccess(0, true);
ClassInfo[] ifaces = info.getInterfaces();
for (int i=0; i < ifaces.length; i++) {
ClassIdentifier ifaceident = Main.getClassBundle()
.getClassIdentifier(ifaces[i].getName());
if (ifaceident != null) {
if (ifaceident.containsFieldAlias(fieldName, typeSig,
packMatcher))
return true;
} else {
if (containsField(ifaces[i], fieldName, typeSig,
packMatcher))
return true;
}
}
if (info.getSuperclass() != null) {
ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(info.getSuperclass().getName());
if (superident != null) {
if (superident.containsFieldAlias(fieldName, typeSig,
packMatcher))
return true;
} else {
if (containsField(info.getSuperclass(),
fieldName, typeSig, packMatcher))
return true; return true;
} }
}
return false;
}
public boolean containsMethodAlias(String methodName, String typeSig,
ModifierMatcher matcher) {
if (containsMethodAliasDirectly(methodName,typeSig, matcher))
return true;
ModifierMatcher packMatcher = matcher.forceAccess(0, true);
ClassInfo[] ifaces = info.getInterfaces(); ClassInfo[] ifaces = info.getInterfaces();
for (int i=0; i < ifaces.length; i++) { for (int i=0; i < ifaces.length; i++) {
ClassIdentifier ifaceident ClassIdentifier ifaceident = Main.getClassBundle()
= bundle.getClassIdentifier(ifaces[i].getName()); .getClassIdentifier(ifaces[i].getName());
if (ifaceident != null) { if (ifaceident != null) {
if (ifaceident.containFieldAlias(fieldName, typeSig)) if (ifaceident.containsMethodAlias(methodName, typeSig,
packMatcher))
return true; return true;
} else { } else {
if (containFieldAlias(ifaces[i], fieldName, typeSig)) if (containsMethod(ifaces[i], methodName, typeSig,
packMatcher))
return true; return true;
} }
} }
if (info.getSuperclass() != null) { if (info.getSuperclass() != null) {
ClassIdentifier superident ClassIdentifier superident = Main.getClassBundle()
= bundle.getClassIdentifier(info.getSuperclass().getName()); .getClassIdentifier(info.getSuperclass().getName());
if (superident != null) { if (superident != null) {
if (superident.containFieldAlias(fieldName, typeSig)) if (superident.containsMethodAlias(methodName, typeSig,
packMatcher))
return true; return true;
} else { } else {
if (containFieldAlias(info.getSuperclass(), if (containsMethod(info.getSuperclass(),
fieldName, typeSig)) methodName, typeSig, packMatcher))
return true;
}
}
return false;
}
public boolean fieldConflicts(FieldIdentifier field, String newAlias) {
String typeSig = (Main.options & Main.OPTION_STRONGOVERLOAD) != 0
? field.getType() : "";
/* Fields are special: They are not overriden but hidden. We
* must only take care, that the reference of every
* getfield/putfield opcode points to the exact class, afterwards
* we can use doubled name as much as we want.
*/
ModifierMatcher mm = ModifierMatcher.allowAll;
if (containsFieldAliasDirectly(newAlias, typeSig, mm))
return true;
// boolean isPublic = (field.info.getModifier()
// & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0;
// if (field.info.getModifier() & Modifier.PRIVATE != 0) {
// for (Iterator i = clazz.knownSubClasses.iterator();
// i.hasNext(); ) {
// ClassIdentifier ci = (ClassIdentifier) i.next();
// if ((isPublic || ci.getParent() == getParent())
// && ci.containsFieldAliasDirectly(newAlias, typeSig, mm))
// return true;
// }
// }
return false;
}
public boolean methodConflicts(MethodIdentifier method, String newAlias) {
String paramType = method.getType();
if ((Main.options & Main.OPTION_STRONGOVERLOAD) == 0)
paramType = paramType.substring(0, paramType.indexOf(')')+1);
ModifierMatcher matcher = ModifierMatcher.allowAll;
if (containsMethodAlias(newAlias, paramType, matcher))
return true;
ModifierMatcher packMatcher = matcher.forceAccess(0, true);
if (packMatcher.matches(method)) {
for (Iterator i = knownSubClasses.iterator(); i.hasNext(); ) {
ClassIdentifier ci = (ClassIdentifier) i.next();
if (ci.containsMethodAliasDirectly(newAlias, paramType,
matcher))
return true; return true;
} }
} }
return false; return false;
} }
public static Object getMethod(ClassInfo clazz, public static Object getMethod(ClassInfo clazz,
String methodName, String paramType) { String methodName, String paramType) {
MethodInfo[] minfos = clazz.getMethods(); MethodInfo[] minfos = clazz.getMethods();
@ -741,27 +1045,18 @@ public class ClassIdentifier extends Identifier {
return null; return null;
} }
public boolean hasMethod(String methodName, String paramType) {
for (int i=fieldCount; i< identifiers.length; i++) {
if ((!Obfuscator.shouldStrip || identifiers[i].isReachable())
&& identifiers[i].getAlias().equals(methodName)
&& identifiers[i].getType().startsWith(paramType))
return true;
}
return false;
}
public Object getMethod(String methodName, String paramType) { public Object getMethod(String methodName, String paramType) {
for (int i=fieldCount; i< identifiers.length; i++) { for (int i=fieldCount; i< identifiers.length; i++) {
if ((!Obfuscator.shouldStrip || identifiers[i].isReachable()) if (((Main.stripping & Main.STRIP_UNREACH) == 0
|| identifiers[i].isReachable())
&& identifiers[i].getAlias().equals(methodName) && identifiers[i].getAlias().equals(methodName)
&& identifiers[i].getType().startsWith(paramType)) && identifiers[i].getType().startsWith(paramType))
return identifiers[i]; return identifiers[i];
} }
ClassInfo[] ifaces = info.getInterfaces(); ClassInfo[] ifaces = info.getInterfaces();
for (int i=0; i < ifaces.length; i++) { for (int i=0; i < ifaces.length; i++) {
ClassIdentifier ifaceident ClassIdentifier ifaceident = Main.getClassBundle()
= bundle.getClassIdentifier(ifaces[i].getName()); .getClassIdentifier(ifaces[i].getName());
if (ifaceident != null) { if (ifaceident != null) {
Object result = ifaceident.getMethod(methodName, paramType); Object result = ifaceident.getMethod(methodName, paramType);
if (result != null) if (result != null)
@ -774,8 +1069,8 @@ public class ClassIdentifier extends Identifier {
} }
if (info.getSuperclass() != null) { if (info.getSuperclass() != null) {
ClassIdentifier superident ClassIdentifier superident = Main.getClassBundle()
= bundle.getClassIdentifier(info.getSuperclass().getName()); .getClassIdentifier(info.getSuperclass().getName());
if (superident != null) { if (superident != null) {
Object result = superident.getMethod(methodName, paramType); Object result = superident.getMethod(methodName, paramType);
if (result != null) if (result != null)
@ -790,7 +1085,7 @@ public class ClassIdentifier extends Identifier {
return null; return null;
} }
public boolean conflicting(String newAlias, boolean strong) { public boolean conflicting(String newAlias) {
return pack.contains(newAlias); return pack.contains(newAlias, this);
} }
} }

Loading…
Cancel
Save