0001: /* ===========================================================================
0002: * $RCSfile: Cl.java,v $
0003: * ===========================================================================
0004: *
0005: * RetroGuard -- an obfuscation package for Java classfiles.
0006: *
0007: * Copyright (c) 1998-2006 Mark Welsh (markw@retrologic.com)
0008: *
0009: * This program can be redistributed and/or modified under the terms of the
0010: * Version 2 of the GNU General Public License as published by the Free
0011: * Software Foundation.
0012: *
0013: * This program is distributed in the hope that it will be useful,
0014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0016: * GNU General Public License for more details.
0017: *
0018: */
0019:
0020: package COM.rl.obf;
0021:
0022: import java.io.*;
0023: import java.lang.reflect.*;
0024: import java.util.*;
0025: import COM.rl.util.*;
0026: import COM.rl.obf.classfile.*;
0027:
0028: /**
0029: * Tree item representing a class or interface.
0030: *
0031: * @author Mark Welsh
0032: */
0033: public class Cl extends PkCl implements NameListUp, NameListDown {
0034: // Constants -------------------------------------------------------------
0035:
0036: // Fields ----------------------------------------------------------------
0037: private Hashtable mds = new Hashtable(); // Owns a list of methods
0038: private Hashtable mdsSpecial = new Hashtable(); // Owns a list of special methods
0039: private Hashtable fds = new Hashtable(); // Owns a list of fields
0040: private boolean isResolved = false; // Has the class been resolved already?
0041: private boolean isScanned = false; // Has the class been scanned already?
0042: private String super Class; // Our superclass name
0043: private String[] super Interfaces; // Names of implemented interfaces
0044: private boolean isInnerClass; // Is this an inner class?
0045: private Vector nameListUps = new Vector(); // NameListUp interfaces for super-class/interfaces
0046: private Vector nameListDowns = new Vector(); // NameListDown interfaces for derived class/interfaces
0047: private boolean isNoWarn = false; // Are danger-method warnings suppressed?
0048: private Vector warningList = null; // Danger-method warnings
0049:
0050: public static int nameSpace = 0;
0051: private static NameMaker methodNameMaker;
0052: private static NameMaker fieldNameMaker;
0053:
0054: // Class Methods ---------------------------------------------------------
0055:
0056: // Instance Methods ------------------------------------------------------
0057: /** Ctor. */
0058: public Cl(TreeItem parent, boolean isInnerClass, String name,
0059: String super Class, String[] super Interfaces, int access)
0060: throws Exception {
0061: super (parent, name);
0062: this .super Class = super Class;
0063: this .super Interfaces = super Interfaces;
0064: this .isInnerClass = isInnerClass;
0065: this .access = access;
0066: if (parent == null || "".equals(name)) {
0067: System.err
0068: .println("Internal error: class must have parent and name");
0069: }
0070: if (parent instanceof Cl) {
0071: sep = ClassFile.SEP_INNER;
0072: }
0073:
0074: // Do not obfuscate anonymous inner classes
0075: if (isInnerClass && name != null && name.length() > 0
0076: && Character.isDigit(name.charAt(0))) {
0077: setOutName(getInName());
0078: }
0079: }
0080:
0081: /** Is this an inner class? */
0082: public boolean isInnerClass() {
0083: return isInnerClass;
0084: }
0085:
0086: /** Suppress warnings. */
0087: public void setNoWarn() {
0088: isNoWarn = true;
0089: }
0090:
0091: /** Add class's warning. */
0092: public void setWarnings(ClassFile cf) throws Exception {
0093: if (warningList == null) {
0094: warningList = new Vector();
0095: }
0096: warningList = cf.listDangerMethods(warningList);
0097: }
0098:
0099: /** Do we have non-suppressed warnings? */
0100: public boolean hasWarnings() {
0101: return (!isNoWarn && warningList != null && warningList.size() > 0);
0102: }
0103:
0104: /** Log this class's warnings. */
0105: public void logWarnings(PrintWriter log) {
0106: if (hasWarnings()) {
0107: for (Enumeration enm = warningList.elements(); enm
0108: .hasMoreElements();) {
0109: log.println("# " + (String) enm.nextElement());
0110: }
0111: }
0112: }
0113:
0114: /** Get a method by name. */
0115: public Md getMethod(String name, String descriptor)
0116: throws Exception {
0117: return (Md) mds.get(name + descriptor);
0118: }
0119:
0120: /** Get a special method by name. */
0121: public Md getMethodSpecial(String name, String descriptor)
0122: throws Exception {
0123: return (Md) mdsSpecial.get(name + descriptor);
0124: }
0125:
0126: /** Get all methods with obfuscated name. */
0127: public Enumeration getObfMethods(String name) throws Exception {
0128: Vector mdsMatch = new Vector();
0129: for (Enumeration enm = mds.elements(); enm.hasMoreElements();) {
0130: Md md = (Md) enm.nextElement();
0131: if (name.equals(md.getOutName())) {
0132: mdsMatch.addElement(md);
0133: }
0134: }
0135: return mdsMatch.elements();
0136: }
0137:
0138: /** Get a field by name. */
0139: public Fd getField(String name) throws Exception {
0140: return (Fd) fds.get(name);
0141: }
0142:
0143: /** Get an Enumeration of methods. */
0144: public Enumeration getMethodEnum() throws Exception {
0145: return mds.elements();
0146: }
0147:
0148: /** Get an Enumeration of fields. */
0149: public Enumeration getFieldEnum() throws Exception {
0150: return fds.elements();
0151: }
0152:
0153: /** Return this Cl's superclass Cl */
0154: public Cl getSuperCl() throws Exception {
0155: if (super Class != null) {
0156: return classTree.getCl(super Class);
0157: } else {
0158: return null;
0159: }
0160: }
0161:
0162: /** Return Enumeration of this Cl's super-interfaces */
0163: public Enumeration getSuperInterfaces() throws Exception {
0164: Vector v = new Vector();
0165: if (super Interfaces != null) {
0166: for (int i = 0; i < super Interfaces.length; i++) {
0167: Cl interfaceItem = classTree.getCl(super Interfaces[i]);
0168: if (interfaceItem != null) {
0169: v.addElement(interfaceItem);
0170: }
0171: }
0172: }
0173: return v.elements();
0174: }
0175:
0176: /** Does this internal class have the specified class or interface
0177: in its super or interface chain? */
0178: protected boolean hasAsSuperInt(String queryName,
0179: boolean checkInterfaces) {
0180: try {
0181: // Special case: is this java/lang/Object?
0182: if (super Class == null)
0183: return false;
0184: // Check our parents
0185: if (super Class.equals(queryName))
0186: return true;
0187: if (checkInterfaces) {
0188: if (super Interfaces != null) {
0189: for (int i = 0; i < super Interfaces.length; i++) {
0190: if (queryName.equals(super Interfaces[i]))
0191: return true;
0192: }
0193: }
0194: }
0195: // Nothing, so recurse up through parents
0196: Cl super ClInt = classTree.getCl(super Class);
0197: if (super ClInt != null) {
0198: if (super ClInt
0199: .hasAsSuperInt(queryName, checkInterfaces))
0200: return true;
0201: } else {
0202: Class super ClExt = Class.forName(ClassFile
0203: .translate(super Class));
0204: if (super ClExt != null) {
0205: if (hasAsSuperExt(queryName, checkInterfaces,
0206: this .classTree, super ClExt))
0207: return true;
0208: }
0209: }
0210: if (checkInterfaces) {
0211: if (super Interfaces != null) {
0212: for (int i = 0; i < super Interfaces.length; i++) {
0213: Cl interClInt = classTree
0214: .getCl(super Interfaces[i]);
0215: if (interClInt != null) {
0216: if (interClInt.hasAsSuperInt(queryName,
0217: checkInterfaces))
0218: return true;
0219: } else {
0220: Class interClExt = Class.forName(ClassFile
0221: .translate(super Interfaces[i]));
0222: if (interClExt != null) {
0223: if (hasAsSuperExt(queryName,
0224: checkInterfaces,
0225: this .classTree, interClExt))
0226: return true;
0227: }
0228: }
0229: }
0230: }
0231: }
0232: } catch (Exception e) {
0233: // fall thru
0234: }
0235: return false;
0236: }
0237:
0238: /** Does this class have the specified class or interface in its super
0239: or interface chain? */
0240: protected static boolean hasAsSuperExt(String queryName,
0241: boolean checkInterfaces, ClassTree classTree, Class clExt) {
0242: try {
0243: // Special case: is this java/lang/Object?
0244: if (clExt == null
0245: || clExt.getName().equals("java.lang.Object"))
0246: return false;
0247: // Check our parents
0248: String queryNameExt = ClassFile.translate(queryName);
0249: Class super Class = clExt.getSuperclass();
0250: Class[] super Interfaces = clExt.getInterfaces();
0251: if (queryNameExt.equals(super Class.getName()))
0252: return true;
0253: if (checkInterfaces) {
0254: if (super Interfaces != null) {
0255: for (int i = 0; i < super Interfaces.length; i++) {
0256: if (queryNameExt.equals(super Interfaces[i]
0257: .getName()))
0258: return true;
0259: }
0260: }
0261: }
0262: // Nothing, so recurse up through parents
0263: Cl super ClInt = classTree.getCl(ClassFile
0264: .backTranslate(super Class.getName()));
0265: if (super ClInt != null) {
0266: if (super ClInt
0267: .hasAsSuperInt(queryName, checkInterfaces))
0268: return true;
0269: } else {
0270: Class super ClExt = super Class;
0271: if (super ClExt != null) {
0272: if (hasAsSuperExt(queryName, checkInterfaces,
0273: classTree, super ClExt))
0274: return true;
0275: }
0276: }
0277: if (checkInterfaces) {
0278: if (super Interfaces != null) {
0279: for (int i = 0; i < super Interfaces.length; i++) {
0280: Cl interClInt = classTree.getCl(ClassFile
0281: .backTranslate(super Interfaces[i]
0282: .getName()));
0283: if (interClInt != null) {
0284: if (interClInt.hasAsSuperInt(queryName,
0285: checkInterfaces))
0286: return true;
0287: } else {
0288: Class interClExt = super Interfaces[i];
0289: if (interClExt != null) {
0290: if (hasAsSuperExt(queryName,
0291: checkInterfaces, classTree,
0292: interClExt))
0293: return true;
0294: }
0295: }
0296: }
0297: }
0298: }
0299: } catch (Exception e) {
0300: // fall thru
0301: }
0302: return false;
0303: }
0304:
0305: /** Does this class have the specified class or interface in its super
0306: or interface chain? */
0307: public boolean hasAsSuperOrInterface(String queryName) {
0308: return hasAsSuperInt(queryName, true);
0309: }
0310:
0311: /** Does this class have the specified class in its super chain? */
0312: public boolean hasAsSuper(String queryName) {
0313: return hasAsSuperInt(queryName, false);
0314: }
0315:
0316: /** Add an inner class. */
0317: public Cl addClass(String name, String super Name,
0318: String[] interfaceNames, int access) throws Exception {
0319: return addClass(true, name, super Name, interfaceNames, access);
0320: }
0321:
0322: /** Add an inner class, used when copying inner classes from a placeholder. */
0323: public Cl addClass(Cl cl) throws Exception {
0324: cls.put(cl.getInName(), cl);
0325: return cl;
0326: }
0327:
0328: /** Add a placeholder class. */
0329: public Cl addPlaceholderClass(String name) throws Exception {
0330: return addPlaceholderClass(true, name);
0331: }
0332:
0333: /** Add a method. */
0334: public Md addMethod(ClassFile cf, MethodInfo methodInfo,
0335: boolean enableTrim) throws Exception {
0336: Md md = addMethod(methodInfo.isSynthetic(), methodInfo
0337: .getName(), methodInfo.getDescriptor(), methodInfo
0338: .getAccessFlags());
0339: // Construct method's reference list
0340: if (enableTrim) {
0341: md.findRefs(cf, methodInfo);
0342: }
0343: return md;
0344: }
0345:
0346: /** Add a method. */
0347: public Md addMethod(boolean isSynthetic, String name,
0348: String descriptor, int accessFlags) throws Exception {
0349: // Store <init> and <clinit> methods separately - needed only for
0350: // reference tracking ('.option trim')
0351: Md md;
0352: if (name.charAt(0) == '<') {
0353: md = getMethodSpecial(name, descriptor);
0354: if (md == null) {
0355: md = new Md(this , isSynthetic, name, descriptor,
0356: accessFlags);
0357: mdsSpecial.put(name + descriptor, md);
0358: }
0359: } else {
0360: md = getMethod(name, descriptor);
0361: if (md == null) {
0362: md = new Md(this , isSynthetic, name, descriptor,
0363: accessFlags);
0364: mds.put(name + descriptor, md);
0365: }
0366: }
0367: return md;
0368: }
0369:
0370: /** Add a field. */
0371: public Fd addField(ClassFile cf, FieldInfo fieldInfo,
0372: boolean enableTrim) throws Exception {
0373: Fd fd = addField(fieldInfo.isSynthetic(), fieldInfo.getName(),
0374: fieldInfo.getDescriptor(), fieldInfo.getAccessFlags());
0375: // Construct field's reference list
0376: if (enableTrim) {
0377: fd.findRefs(cf, fieldInfo);
0378: }
0379: return fd;
0380: }
0381:
0382: /** Add a field. */
0383: public Fd addField(boolean isSynthetic, String name,
0384: String descriptor, int access) throws Exception {
0385: Fd fd = getField(name);
0386: if (fd == null) {
0387: fd = new Fd(this , isSynthetic, name, descriptor, access);
0388: fds.put(name, fd);
0389: }
0390: return fd;
0391: }
0392:
0393: /** Prepare for resolve of a class entry by resetting flags. */
0394: public void resetResolve() throws Exception {
0395: isScanned = false;
0396: isResolved = false;
0397: nameListDowns.removeAllElements();
0398: }
0399:
0400: /** Set up reverse list of reserved names prior to resolving classes. */
0401: public void setupNameListDowns() throws Exception {
0402: // Special case: we are java/lang/Object
0403: if (super Class == null)
0404: return;
0405:
0406: // Add this class as a NameListDown to the super and each interface, if they are in the JAR
0407: Cl super ClassItem = classTree.getCl(super Class);
0408: if (super ClassItem != null) {
0409: super ClassItem.nameListDowns.addElement(this );
0410: }
0411: if (super Interfaces != null) {
0412: for (int i = 0; i < super Interfaces.length; i++) {
0413: Cl interfaceItem = classTree.getCl(super Interfaces[i]);
0414: if (interfaceItem != null) {
0415: interfaceItem.nameListDowns.addElement(this );
0416: }
0417: }
0418: }
0419: }
0420:
0421: /**
0422: * Resolve a class entry - set obfuscation permissions based on super class and interfaces.
0423: * Overload method and field names maximally.
0424: */
0425: public void resolveOptimally() throws Exception {
0426: // Already processed, then do nothing
0427: if (!isResolved) {
0428: // Get lists of method and field names in inheritance namespace
0429: Vector methods = new Vector();
0430: Vector fields = new Vector();
0431: scanNameSpaceExcept(null, methods, fields);
0432: String[] methodNames = new String[methods.size()];
0433: for (int i = 0; i < methodNames.length; i++) {
0434: methodNames[i] = (String) methods.elementAt(i);
0435: }
0436: String[] fieldNames = new String[fields.size()];
0437: for (int i = 0; i < fieldNames.length; i++) {
0438: fieldNames[i] = (String) fields.elementAt(i);
0439: }
0440:
0441: // Create new name-makers for the namespace
0442: methodNameMaker = new KeywordNameMaker(methodNames);
0443: fieldNameMaker = new KeywordNameMaker(fieldNames);
0444:
0445: // Resolve a full name space
0446: resolveNameSpaceExcept(null);
0447:
0448: // and move to next
0449: nameSpace++;
0450: }
0451: }
0452:
0453: // Get lists of method and field names in inheritance namespace
0454: private void scanNameSpaceExcept(Cl ignoreCl, Vector methods,
0455: Vector fields) throws Exception {
0456: // Special case: we are java/lang/Object
0457: if (super Class == null)
0458: return;
0459:
0460: // Traverse one step in each direction in name space, scanning
0461: if (!isScanned) {
0462: // First step up to super classes, scanning them
0463: Cl super Cl = classTree.getCl(super Class);
0464: if (super Cl != null) // internal to JAR
0465: {
0466: if (super Cl != ignoreCl) {
0467: super Cl.scanNameSpaceExcept(this , methods, fields);
0468: }
0469: } else // external to JAR
0470: {
0471: scanExtSupers(super Class, methods, fields);
0472: }
0473: if (super Interfaces != null) {
0474: for (int i = 0; i < super Interfaces.length; i++) {
0475: Cl interfaceItem = classTree
0476: .getCl(super Interfaces[i]);
0477: if (interfaceItem != null
0478: && interfaceItem != ignoreCl) {
0479: interfaceItem.scanNameSpaceExcept(this ,
0480: methods, fields);
0481: }
0482: }
0483: }
0484:
0485: // Next, scan ourself
0486: if (!isScanned) {
0487: scanThis(methods, fields);
0488:
0489: // Signal class has been scanned
0490: isScanned = true;
0491: }
0492:
0493: // Finally step down to derived classes, resolving them
0494: for (Enumeration clEnum = nameListDowns.elements(); clEnum
0495: .hasMoreElements();) {
0496: Cl cl = (Cl) clEnum.nextElement();
0497: if (cl != ignoreCl) {
0498: cl.scanNameSpaceExcept(this , methods, fields);
0499: }
0500: }
0501: }
0502: }
0503:
0504: // Get lists of method and field names in inheritance namespace
0505: private void scanExtSupers(String name, Vector methods,
0506: Vector fields) throws Exception {
0507: Class extClass = Class.forName(ClassFile.translate(name));
0508:
0509: // Get public methods and fields from supers and interfaces up the tree
0510: Method[] allPubMethods = extClass.getMethods();
0511: if (allPubMethods != null) {
0512: for (int i = 0; i < allPubMethods.length; i++) {
0513: String methodName = allPubMethods[i].getName();
0514: if (methods.indexOf(methodName) == -1) {
0515: methods.addElement(methodName);
0516: }
0517: }
0518: }
0519: Field[] allPubFields = extClass.getFields();
0520: if (allPubFields != null) {
0521: for (int i = 0; i < allPubFields.length; i++) {
0522: String fieldName = allPubFields[i].getName();
0523: if (fields.indexOf(fieldName) == -1) {
0524: fields.addElement(fieldName);
0525: }
0526: }
0527: }
0528: // Go up the super hierarchy, adding all non-public methods/fields
0529: while (extClass != null) {
0530: Method[] allClassMethods = extClass.getDeclaredMethods();
0531: if (allClassMethods != null) {
0532: for (int i = 0; i < allClassMethods.length; i++) {
0533: if (!Modifier.isPublic(allClassMethods[i]
0534: .getModifiers())) {
0535: String methodName = allClassMethods[i]
0536: .getName();
0537: if (methods.indexOf(methodName) == -1) {
0538: methods.addElement(methodName);
0539: }
0540: }
0541: }
0542: }
0543: Field[] allClassFields = extClass.getDeclaredFields();
0544: if (allClassFields != null) {
0545: for (int i = 0; i < allClassFields.length; i++) {
0546: if (!Modifier.isPublic(allClassFields[i]
0547: .getModifiers())) {
0548: String fieldName = allClassFields[i].getName();
0549: if (fields.indexOf(fieldName) == -1) {
0550: fields.addElement(fieldName);
0551: }
0552: }
0553: }
0554: }
0555: extClass = extClass.getSuperclass();
0556: }
0557: }
0558:
0559: // Add method and field names from this class to the lists
0560: private void scanThis(Vector methods, Vector fields)
0561: throws Exception {
0562: for (Enumeration mdEnum = mds.elements(); mdEnum
0563: .hasMoreElements();) {
0564: Md md = (Md) mdEnum.nextElement();
0565: if (md.isFixed()) {
0566: String name = md.getOutName();
0567: if (methods.indexOf(name) == -1) {
0568: methods.addElement(name);
0569: }
0570: }
0571: }
0572: for (Enumeration fdEnum = fds.elements(); fdEnum
0573: .hasMoreElements();) {
0574: Fd fd = (Fd) fdEnum.nextElement();
0575: if (fd.isFixed()) {
0576: String name = fd.getOutName();
0577: if (fields.indexOf(name) == -1) {
0578: fields.addElement(name);
0579: }
0580: }
0581: }
0582: }
0583:
0584: // Resolve an entire inheritance name space optimally.
0585: private void resolveNameSpaceExcept(Cl ignoreCl) throws Exception {
0586: // Special case: we are java/lang/Object
0587: if (super Class == null)
0588: return;
0589:
0590: // Traverse one step in each direction in name space, resolving
0591: if (!isResolved) {
0592: // First step up to super classes, resolving them, since we depend on them
0593: Cl super Cl = classTree.getCl(super Class);
0594: if (super Cl != null && super Cl != ignoreCl) {
0595: super Cl.resolveNameSpaceExcept(this );
0596: }
0597: if (super Interfaces != null) {
0598: for (int i = 0; i < super Interfaces.length; i++) {
0599: Cl interfaceItem = classTree
0600: .getCl(super Interfaces[i]);
0601: if (interfaceItem != null
0602: && interfaceItem != ignoreCl) {
0603: interfaceItem.resolveNameSpaceExcept(this );
0604: }
0605: }
0606: }
0607:
0608: // Next, resolve ourself
0609: if (!isResolved) {
0610: resolveThis();
0611:
0612: // Signal class has been processed
0613: isResolved = true;
0614: }
0615:
0616: // Finally step down to derived classes, resolving them
0617: for (Enumeration clEnum = nameListDowns.elements(); clEnum
0618: .hasMoreElements();) {
0619: Cl cl = (Cl) clEnum.nextElement();
0620: if (cl != ignoreCl) {
0621: cl.resolveNameSpaceExcept(this );
0622: }
0623: }
0624: }
0625: }
0626:
0627: // For each super interface and the super class, if it is outside DB, use reflection
0628: // to merge its list of public/protected methods/fields --
0629: // while for those in the DB, resolve to get the name-mapping lists
0630: private void resolveThis() throws Exception {
0631: // Special case: we are java/lang/Object
0632: if (super Class == null)
0633: return;
0634:
0635: Cl super ClassItem = classTree.getCl(super Class);
0636: nameListUps
0637: .addElement(super ClassItem != null ? (NameListUp) super ClassItem
0638: : getExtNameListUp(super Class));
0639: if (super Interfaces != null) {
0640: for (int i = 0; i < super Interfaces.length; i++) {
0641: Cl interfaceItem = classTree.getCl(super Interfaces[i]);
0642: nameListUps
0643: .addElement(interfaceItem != null ? (NameListUp) interfaceItem
0644: : getExtNameListUp(super Interfaces[i]));
0645: }
0646: }
0647:
0648: // Run through each method/field in this class checking for reservations and
0649: // obfuscating accordingly
0650: nextMethod: for (Enumeration mdEnum = mds.elements(); mdEnum
0651: .hasMoreElements();) {
0652: Md md = (Md) mdEnum.nextElement();
0653: if (!md.isFixed()) {
0654: // Check for name reservation via derived classes
0655: for (Enumeration nlEnum = nameListDowns.elements(); nlEnum
0656: .hasMoreElements();) {
0657: String theOutName = ((NameListDown) nlEnum
0658: .nextElement()).getMethodObfNameDown(this ,
0659: md.getInName(), md.getDescriptor());
0660: if (theOutName != null) {
0661: md.setOutName(theOutName);
0662: continue nextMethod;
0663: }
0664: }
0665: // Check for name reservation via super classes
0666: for (Enumeration nlEnum = nameListUps.elements(); nlEnum
0667: .hasMoreElements();) {
0668: String theOutName = ((NameListUp) nlEnum
0669: .nextElement()).getMethodOutNameUp(md
0670: .getInName(), md.getDescriptor());
0671: if (theOutName != null) {
0672: md.setOutName(theOutName);
0673: md.setIsOverride();
0674: continue nextMethod;
0675: }
0676: }
0677: // If no other restrictions, obfuscate it
0678: md.setOutName(methodNameMaker.nextName(md
0679: .getDescriptor()));
0680: }
0681: }
0682: nextField: for (Enumeration fdEnum = fds.elements(); fdEnum
0683: .hasMoreElements();) {
0684: Fd fd = (Fd) fdEnum.nextElement();
0685: if (!fd.isFixed()) {
0686: // Check for name reservation via derived classes
0687: for (Enumeration nlEnum = nameListDowns.elements(); nlEnum
0688: .hasMoreElements();) {
0689: String theOutName = ((NameListDown) nlEnum
0690: .nextElement()).getFieldObfNameDown(this ,
0691: fd.getInName());
0692: if (theOutName != null) {
0693: fd.setOutName(theOutName);
0694: continue nextField;
0695: }
0696: }
0697: // Check for name reservation via super classes
0698: for (Enumeration nlEnum = nameListUps.elements(); nlEnum
0699: .hasMoreElements();) {
0700: String super OutName = ((NameListUp) nlEnum
0701: .nextElement()).getFieldOutNameUp(fd
0702: .getInName());
0703: if (super OutName != null) {
0704: fd.setOutName(super OutName);
0705: fd.setIsOverride();
0706: continue nextField;
0707: }
0708: }
0709: // If no other restrictions, obfuscate it
0710: fd.setOutName(fieldNameMaker.nextName(null));
0711: }
0712: }
0713: }
0714:
0715: /** Get output method name from list, or null if no mapping exists. */
0716: public String getMethodOutNameUp(String name, String descriptor)
0717: throws Exception {
0718: // Check supers
0719: for (Enumeration enm = nameListUps.elements(); enm
0720: .hasMoreElements();) {
0721: String super OutName = ((NameListUp) enm.nextElement())
0722: .getMethodOutNameUp(name, descriptor);
0723: if (super OutName != null) {
0724: return super OutName;
0725: }
0726: }
0727:
0728: // Check self
0729: Md md = getMethod(name, descriptor);
0730: if (md != null && !Modifier.isPrivate(md.access)) {
0731: return md.getOutName();
0732: } else {
0733: return null;
0734: }
0735: }
0736:
0737: /** Get obfuscated method name from list, or null if no mapping exists. */
0738: public String getMethodObfNameUp(String name, String descriptor)
0739: throws Exception {
0740: // Check supers
0741: for (Enumeration enm = nameListUps.elements(); enm
0742: .hasMoreElements();) {
0743: String super ObfName = ((NameListUp) enm.nextElement())
0744: .getMethodObfNameUp(name, descriptor);
0745: if (super ObfName != null) {
0746: return super ObfName;
0747: }
0748: }
0749:
0750: // Check self
0751: Md md = getMethod(name, descriptor);
0752: if (md != null && !Modifier.isPrivate(md.access)) {
0753: return md.getObfName();
0754: } else {
0755: return null;
0756: }
0757: }
0758:
0759: /** Get output field name from list, or null if no mapping exists. */
0760: public String getFieldOutNameUp(String name) throws Exception {
0761: // Check supers
0762: for (Enumeration enm = nameListUps.elements(); enm
0763: .hasMoreElements();) {
0764: String super OutName = ((NameListUp) enm.nextElement())
0765: .getFieldOutNameUp(name);
0766: if (super OutName != null) {
0767: return super OutName;
0768: }
0769: }
0770:
0771: // Check self
0772: Fd fd = getField(name);
0773: if (fd != null && !Modifier.isPrivate(fd.access)) {
0774: return fd.getOutName();
0775: } else {
0776: return null;
0777: }
0778: }
0779:
0780: /** Get obfuscated field name from list, or null if no mapping exists. */
0781: public String getFieldObfNameUp(String name) throws Exception {
0782: // Check supers
0783: for (Enumeration enm = nameListUps.elements(); enm
0784: .hasMoreElements();) {
0785: String super ObfName = ((NameListUp) enm.nextElement())
0786: .getFieldObfNameUp(name);
0787: if (super ObfName != null) {
0788: return super ObfName;
0789: }
0790: }
0791:
0792: // Check self
0793: Fd fd = getField(name);
0794: if (fd != null && !Modifier.isPrivate(fd.access)) {
0795: return fd.getObfName();
0796: } else {
0797: return null;
0798: }
0799: }
0800:
0801: /** Is the method reserved because of its reservation down the class hierarchy? */
0802: public String getMethodObfNameDown(Cl caller, String name,
0803: String descriptor) throws Exception {
0804: // Check ourself for an explicit 'do not obfuscate'
0805: Md md = getMethod(name, descriptor);
0806: if (md != null && md.isFixed()) {
0807: return md.getOutName();
0808: }
0809:
0810: // Check our supers, except for our caller (special case if we are java/lang/Object)
0811: String theObfName = null;
0812: if (super Class != null) {
0813: Cl super ClassItem = classTree.getCl(super Class);
0814: if (super ClassItem != caller) {
0815: NameListUp nl = super ClassItem != null ? (NameListUp) super ClassItem
0816: : getExtNameListUp(super Class);
0817: theObfName = nl.getMethodObfNameUp(name, descriptor);
0818: if (theObfName != null) {
0819: return theObfName;
0820: }
0821: }
0822: if (super Interfaces != null) {
0823: for (int i = 0; i < super Interfaces.length; i++) {
0824: Cl interfaceItem = classTree
0825: .getCl(super Interfaces[i]);
0826: if (interfaceItem != caller) {
0827: NameListUp nl = interfaceItem != null ? (NameListUp) interfaceItem
0828: : getExtNameListUp(super Interfaces[i]);
0829: theObfName = nl.getMethodObfNameUp(name,
0830: descriptor);
0831: if (theObfName != null) {
0832: return theObfName;
0833: }
0834: }
0835: }
0836: }
0837: }
0838:
0839: // Check our derived classes
0840: for (Enumeration enm = nameListDowns.elements(); enm
0841: .hasMoreElements();) {
0842: theObfName = ((NameListDown) enm.nextElement())
0843: .getMethodObfNameDown(this , name, descriptor);
0844: if (theObfName != null) {
0845: return theObfName;
0846: }
0847: }
0848:
0849: // No reservation found
0850: return null;
0851: }
0852:
0853: /** Is the field reserved because of its reservation down the class hierarchy? */
0854: public String getFieldObfNameDown(Cl caller, String name)
0855: throws Exception {
0856: // Check ourself for an explicit 'do not obfuscate'
0857: Fd fd = getField(name);
0858: if (fd != null && fd.isFixed()) {
0859: return fd.getOutName();
0860: }
0861:
0862: // Check our supers, except for our caller (special case if we are java/lang/Object)
0863: String theObfName = null;
0864: if (super Class != null) {
0865: Cl super ClassItem = classTree.getCl(super Class);
0866: if (super ClassItem != caller) {
0867: NameListUp nl = super ClassItem != null ? (NameListUp) super ClassItem
0868: : getExtNameListUp(super Class);
0869: theObfName = nl.getFieldObfNameUp(name);
0870: if (theObfName != null) {
0871: return theObfName;
0872: }
0873: }
0874: if (super Interfaces != null) {
0875: for (int i = 0; i < super Interfaces.length; i++) {
0876: Cl interfaceItem = classTree
0877: .getCl(super Interfaces[i]);
0878: if (interfaceItem != caller) {
0879: NameListUp nl = interfaceItem != null ? (NameListUp) interfaceItem
0880: : getExtNameListUp(super Interfaces[i]);
0881: theObfName = nl.getFieldObfNameUp(name);
0882: if (theObfName != null) {
0883: return theObfName;
0884: }
0885: }
0886: }
0887: }
0888: }
0889:
0890: // Check our derived classes
0891: for (Enumeration enm = nameListDowns.elements(); enm
0892: .hasMoreElements();) {
0893: theObfName = ((NameListDown) enm.nextElement())
0894: .getFieldObfNameDown(this , name);
0895: if (theObfName != null) {
0896: return theObfName;
0897: }
0898: }
0899:
0900: // No reservation found
0901: return null;
0902: }
0903:
0904: // Construct, or retrieve from cache, the NameListUp object for an external class/interface
0905: private static Hashtable extNameListUpCache = new Hashtable();
0906:
0907: private NameListUp getExtNameListUp(String name) throws Exception {
0908: NameListUp nl = (NameListUp) extNameListUpCache.get(name);
0909: if (nl == null) {
0910: nl = new ExtNameListUp(name);
0911: extNameListUpCache.put(name, nl);
0912: }
0913: return nl;
0914: }
0915:
0916: // NameListUp for class/interface not in the database.
0917: class ExtNameListUp implements NameListUp {
0918: // Class's fully qualified name
0919: private Class extClass;
0920: private Method[] methods = null;
0921:
0922: // Ctor.
0923: public ExtNameListUp(String name) throws Exception {
0924: extClass = Class.forName(ClassFile.translate(name));
0925: }
0926:
0927: // Ctor.
0928: public ExtNameListUp(Class extClass) throws Exception {
0929: this .extClass = extClass;
0930: }
0931:
0932: // Get obfuscated method name from list, or null if no mapping exists.
0933: public String getMethodObfNameUp(String name, String descriptor)
0934: throws Exception {
0935: return getMethodOutNameUp(name, descriptor);
0936: }
0937:
0938: // Get obfuscated method name from list, or null if no mapping exists.
0939: public String getMethodOutNameUp(String name, String descriptor)
0940: throws Exception {
0941: // Get list of public/protected methods
0942: if (methods == null) {
0943: methods = getAllDeclaredMethods(extClass);
0944: Vector pruned = new Vector();
0945: for (int i = 0; i < methods.length; i++) {
0946: int modifiers = methods[i].getModifiers();
0947: if (!Modifier.isPrivate(modifiers)) {
0948: pruned.addElement(methods[i]);
0949: }
0950: }
0951: methods = new Method[pruned.size()];
0952: for (int i = 0; i < methods.length; i++) {
0953: methods[i] = (Method) pruned.elementAt(i);
0954: }
0955: }
0956:
0957: // Check each public/protected class method against the named one
0958: nextMethod: for (int i = 0; i < methods.length; i++) {
0959: if (name.equals(methods[i].getName())) {
0960: String[] paramAndReturnNames = ClassFile
0961: .parseDescriptor(descriptor);
0962: Class[] paramTypes = methods[i].getParameterTypes();
0963: Class returnType = methods[i].getReturnType();
0964: if (paramAndReturnNames.length == paramTypes.length + 1) {
0965: for (int j = 0; j < paramAndReturnNames.length - 1; j++) {
0966: if (!paramAndReturnNames[j]
0967: .equals(paramTypes[j].getName())) {
0968: continue nextMethod;
0969: }
0970: }
0971: String returnName = returnType.getName();
0972: if (!paramAndReturnNames[paramAndReturnNames.length - 1]
0973: .equals(returnName)) {
0974: continue nextMethod;
0975: }
0976:
0977: // We have a match, and so the derived class method name must be made to match
0978: return name;
0979: }
0980: }
0981: }
0982:
0983: // Method is not present
0984: return null;
0985: }
0986:
0987: // Get obfuscated field name from list, or null if no mapping exists.
0988: public String getFieldObfNameUp(String name) throws Exception {
0989: return getFieldOutNameUp(name);
0990: }
0991:
0992: // Get obfuscated field name from list, or null if no mapping exists.
0993: public String getFieldOutNameUp(String name) throws Exception {
0994: // Use reflection to check class for field
0995: Field field = getAllDeclaredField(extClass, name);
0996: if (field != null) {
0997: // Field must be public or protected
0998: int modifiers = field.getModifiers();
0999: if (!Modifier.isPrivate(modifiers)) {
1000: return name;
1001: }
1002: }
1003:
1004: // Field is not present
1005: return null;
1006: }
1007:
1008: // Get all methods (from supers too) regardless of access level
1009: private Method[] getAllDeclaredMethods(Class theClass) {
1010: Vector ma = new Vector();
1011: int length = 0;
1012:
1013: // Get the public methods from all supers and interfaces up the tree
1014: Method[] allPubMethods = theClass.getMethods();
1015: ma.addElement(allPubMethods);
1016: length += allPubMethods.length;
1017:
1018: // Go up the super hierarchy, getting arrays of all methods (some redundancy
1019: // here, but that's okay)
1020: while (theClass != null) {
1021: Method[] methods = theClass.getDeclaredMethods();
1022: ma.addElement(methods);
1023: length += methods.length;
1024: theClass = theClass.getSuperclass();
1025: }
1026:
1027: // Merge the arrays
1028: Method[] allMethods = new Method[length];
1029: int pos = 0;
1030: for (Enumeration enm = ma.elements(); enm.hasMoreElements();) {
1031: Method[] methods = (Method[]) enm.nextElement();
1032: System.arraycopy(methods, 0, allMethods, pos,
1033: methods.length);
1034: pos += methods.length;
1035: }
1036: return allMethods;
1037: }
1038:
1039: // Get a specified field (from supers and interfaces too) regardless of access level
1040: private Field getAllDeclaredField(Class theClass, String name) {
1041: Class origClass = theClass;
1042:
1043: // Check for field in supers
1044: while (theClass != null) {
1045: Field field = null;
1046: try {
1047: field = theClass.getDeclaredField(name);
1048: } catch (Exception e) {
1049: field = null;
1050: }
1051: if (field != null) {
1052: return field;
1053: }
1054: theClass = theClass.getSuperclass();
1055: }
1056:
1057: // Check for public field in supers and interfaces
1058: // (some redundancy here, but that's okay)
1059: try {
1060: return origClass.getField(name);
1061: } catch (Exception e) {
1062: return null;
1063: }
1064: }
1065: }
1066:
1067: /** Find and add TreeItem references. */
1068: public void findRefs(ClassFile cf) throws Exception {
1069: // Reference all <init> and <clinit> special methods
1070: for (Enumeration enm = mdsSpecial.elements(); enm
1071: .hasMoreElements();) {
1072: addRef((Md) enm.nextElement());
1073: }
1074: }
1075:
1076: /** Remove methods and fields that are marked for trim. */
1077: public void trimClassFile(ClassFile cf) throws Exception {
1078: for (int i = cf.getMethodCount() - 1; i >= 0; i--) {
1079: MethodInfo methodInfo = cf.getMethod(i);
1080: Md md = getMethod(methodInfo.getName(), methodInfo
1081: .getDescriptor());
1082: if (md != null && md.isTrimmed()) {
1083: cf.removeMethod(i);
1084: }
1085: }
1086: for (int i = cf.getFieldCount() - 1; i >= 0; i--) {
1087: FieldInfo fieldInfo = cf.getField(i);
1088: Fd fd = getField(fieldInfo.getName());
1089: if (fd != null && fd.isTrimmed()) {
1090: cf.removeField(i);
1091: }
1092: }
1093: }
1094:
1095: /** Walk class inheritance group taking action once only on each class.
1096: Must be called after setupNameListDowns() called for all classes. */
1097: public void walkGroup(TreeAction ta) throws Exception {
1098: Vector done = new Vector();
1099: walkGroup(ta, this , done);
1100: }
1101:
1102: // Walk class inheritance group taking action once only on each class.
1103: private void walkGroup(TreeAction ta, Cl cl, Vector done)
1104: throws Exception {
1105: if (!done.contains(cl)) {
1106: // Take the action and mark this class as done
1107: ta.classAction(cl);
1108: done.addElement(cl);
1109: // Traverse super class
1110: Cl super Cl = classTree.getCl(super Class);
1111: if (super Cl != null) // ignore external to JAR
1112: {
1113: walkGroup(ta, super Cl, done);
1114: }
1115: // Traverse super interfaces
1116: if (super Interfaces != null) {
1117: for (int i = 0; i < super Interfaces.length; i++) {
1118: Cl interfaceItem = classTree
1119: .getCl(super Interfaces[i]);
1120: if (interfaceItem != null) // ignore external to JAR
1121: {
1122: walkGroup(ta, interfaceItem, done);
1123: }
1124: }
1125: }
1126: // Traverse derived classes
1127: for (Enumeration clEnum = nameListDowns.elements(); clEnum
1128: .hasMoreElements();) {
1129: Cl subCl = (Cl) clEnum.nextElement();
1130: if (subCl != null) {
1131: walkGroup(ta, subCl, done);
1132: }
1133: }
1134: }
1135: }
1136: }
|