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