Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/jode/obfuscator/ModifierMatcher.java

261 lines
7.5 KiB

/* ModifierMatcher Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import java.lang.reflect.Modifier;
public class ModifierMatcher implements IdentifierMatcher, Cloneable {
static final int PUBLIC = Modifier.PUBLIC;
static final int PROTECTED = Modifier.PROTECTED;
static final int PRIVATE = Modifier.PRIVATE;
int[] andMasks;
int[] xorMasks;
public static ModifierMatcher denyAll = new ModifierMatcher(new int[0],
new int[0]);
public static ModifierMatcher allowAll = new ModifierMatcher(0, 0);
/* Invariants:
* \forall i: ~andMasks[i] & xorMasks[i] == 0
* \forall i: entries wo. i does not imply entry nr. i
*/
private ModifierMatcher(int[] ands, int[] xors) {
andMasks = ands;
xorMasks = xors;
}
public ModifierMatcher(int and, int xor) {
andMasks = new int[] { and };
xorMasks = new int[] { xor };
}
private static boolean implies(int and1, int xor1, int and2, int xor2) {
return ((and1 & and2) == and2 && (xor1 & and2) == xor2);
}
private boolean implies(int and, int xor) {
for (int i=0; i < andMasks.length; i++) {
if (!implies(andMasks[i], xorMasks[i], and, xor))
return false;
}
return true;
}
private boolean impliedBy(int and, int xor) {
for (int i=0; i< andMasks.length; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
return true;
}
return false;
}
private boolean implies(ModifierMatcher mm) {
for (int i=0; i < andMasks.length; i++) {
if (!mm.impliedBy(andMasks[i], xorMasks[i]))
return false;
}
return true;
}
public ModifierMatcher and(ModifierMatcher mm) {
if (implies(mm))
return this;
if (mm.implies(this))
return mm;
ModifierMatcher result = denyAll;
for (int i=0; i< andMasks.length; i++)
result = result.or(mm.and(andMasks[i], xorMasks[i]));
return result;
}
public ModifierMatcher or(ModifierMatcher mm) {
if (implies(mm))
return mm;
if (mm.implies(this))
return this;
ModifierMatcher result = this;
for (int i=0; i < mm.andMasks.length; i++)
result = result.or(mm.andMasks[i], mm.xorMasks[i]);
return result;
}
private ModifierMatcher and(int and, int xor) {
if (this.implies(and, xor))
return this;
int newCount = 0;
next_i:
for (int i=0; i < andMasks.length; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
continue next_i;
for (int j=0; j < andMasks.length; j++) {
if (j != i
&& implies(and | andMasks[j], xor | xorMasks[j],
andMasks[i], xorMasks[i]))
continue next_i;
}
newCount++;
}
if (newCount == 0)
return new ModifierMatcher(and, xor);
int[] ands = new int[newCount];
int[] xors = new int[newCount];
int index = 0;
next_i:
for (int i=0; i < newCount; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
continue next_i;
for (int j=0; j < andMasks.length; j++) {
if (j != i
&& implies(and | andMasks[j], xor | xorMasks[j],
andMasks[i], xorMasks[i]))
continue next_i;
}
ands[index] = andMasks[i] | and;
xors[index] = xorMasks[i] | xor;
index++;
}
return new ModifierMatcher(ands, xors);
}
private ModifierMatcher or(int and, int xor) {
int matchIndex = -1;
if (this == denyAll)
return new ModifierMatcher(and, xor);
for (int i=0; i< andMasks.length; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
return this;
if (implies(andMasks[i], xorMasks[i], and, xor)) {
matchIndex = i;
break;
}
}
int[] ands, xors;
if (matchIndex == -1) {
matchIndex = andMasks.length;
ands = new int[matchIndex+1];
xors = new int[matchIndex+1];
System.arraycopy(andMasks, 0, ands, 0, matchIndex);
System.arraycopy(xorMasks, 0, xors, 0, matchIndex);
} else {
ands = (int[]) andMasks.clone();
xors = (int[]) xorMasks.clone();
}
ands[matchIndex] = and;
xors[matchIndex] = xor;
return new ModifierMatcher(ands, xors);
}
/**
* Creates a new ModifierMatcher, that matches only modifiers, we
* also match and also forces the access rights, to be accessModif
* (or less restrictive).
* @param accessModif the access modifier. Use 0 for package access,
* or Modifier.PRIVATE/PROTECTED/PUBLIC.
* @param andAbove allow to be less restrictive.
* @return a new modifier matcher that will also use the given accesses.
*/
public ModifierMatcher forceAccess(int accessModif, boolean andAbove) {
if (andAbove) {
if (accessModif == Modifier.PRIVATE)
return this;
if (accessModif == 0)
return this.and(Modifier.PRIVATE, 0);
ModifierMatcher result = this.and(Modifier.PUBLIC, PUBLIC);
if (accessModif == Modifier.PROTECTED)
return result
.or(this.and(Modifier.PROTECTED, Modifier.PROTECTED));
if (accessModif == Modifier.PUBLIC)
return result;
throw new IllegalArgumentException(""+accessModif);
} else {
if (accessModif == 0)
return this.and(Modifier.PRIVATE |
Modifier.PROTECTED | Modifier.PUBLIC, 0);
else
return this.and(accessModif, accessModif);
}
}
public ModifierMatcher forbidAccess(int accessModif, boolean andAbove) {
if (andAbove) {
if (accessModif == Modifier.PRIVATE)
// This forbids all access.
return denyAll;
if (accessModif == 0)
return this.and(Modifier.PRIVATE, Modifier.PRIVATE);
if (accessModif == Modifier.PROTECTED)
return this.and(Modifier.PROTECTED | Modifier.PUBLIC, 0);
if (accessModif == Modifier.PUBLIC)
return this.and(Modifier.PUBLIC, 0);
throw new IllegalArgumentException(""+accessModif);
} else {
if (accessModif == 0) {
return this.and(Modifier.PRIVATE, Modifier.PRIVATE)
.or(this.and(Modifier.PROTECTED, Modifier.PROTECTED))
.or(this.and(Modifier.PUBLIC, Modifier.PUBLIC));
} else
return this.and(accessModif, 0);
}
}
public final ModifierMatcher forceModifier(int modifier) {
return this.and(modifier, modifier);
}
public final ModifierMatcher forbidModifier(int modifier) {
return this.and(modifier, 0);
}
public final boolean matches(int modifiers) {
for (int i=0; i< andMasks.length; i++)
if ((modifiers & andMasks[i]) == xorMasks[i])
return true;
return false;
}
public final boolean matches(Identifier ident) {
int modifiers;
/* XXX NEW INTERFACE OR ANOTHER METHOD IN IDENTIFIER? */
if (ident instanceof ClassIdentifier)
modifiers = ((ClassIdentifier) ident).info.getModifiers();
else if (ident instanceof MethodIdentifier)
modifiers = ((MethodIdentifier) ident).info.getModifiers();
else if (ident instanceof FieldIdentifier)
modifiers = ((FieldIdentifier) ident).info.getModifiers();
else
return false;
return matches(modifiers);
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new IncompatibleClassChangeError(getClass().getName());
}
}
}