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