Files
Brainstorm/Obfuscation/src/com/de22/obfuscation/BaseMangler.java
2014-05-30 10:31:51 -07:00

1610 lines
65 KiB
Java

/*
* Copyright (c) 2008,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.de22.obfuscation;
import com.common.comparison.Comparator;
import com.common.debug.Debug;
import com.common.util.IList;
import com.common.util.LiteList;
import com.de22.javabytecode.CodeAttribute;
import com.de22.javabytecode.Constant;
import com.de22.javabytecode.Field;
import com.de22.javabytecode.Interface;
import com.de22.javabytecode.Method;
import com.de22.javabytecode.Type;
import com.de22.javabytecode.attribute.*;
import com.de22.javabytecode.attribute.Code.CodeException;
import com.de22.javabytecode.constant.*;
public abstract class BaseMangler {
protected static final int UTF8_CONSTANT_TYPE_TEXT = 0;
protected static final int UTF8_CONSTANT_TYPE_TYPE = 1;
protected static final int UTF8_CONSTANT_TYPE_DESCRIPTOR = 2;
protected static final int UTF8_CONSTANT_TYPE_NAME = 3;
protected static final int TYPE_CLASS = 0;
protected static final int TYPE_METHOD = 1;
protected static final int TYPE_FIELD = 2;
protected static final int TYPE_CLASS_TEXT = 3;
protected class TypeMetadata {
/** Whether the type is not changeable. */
private boolean isImmutable = false;
/** The class file data. */
private Type type = null;
/** The type's metadata which is modifyable and can then be told to apply the changes to the type. */
private ConstantCollection constantCollection = null;
/** The name of the type: com/test/ClassName$InnerClassName */
private String name = null;
/**
* TypeMetadata constructor.
* @param metadata The type metadata.
* @param isImmutable Whether the metadata is for a class that either is never mangled, or has already been mangled. This is only false if the type is going to be mangled.
*/
public TypeMetadata(Type type, boolean isImmutable) {
this.isImmutable = isImmutable;
this.type = type;
if(!isImmutable) {
constantCollection = new ConstantCollection(type);
}//if//
this.name = ((ConstantUtf8) type.getConstant(((ConstantType) type.getConstant(type.getThisReference())).getNameIndex())).getValue().replace('.', '/');
}//TypeMetadata//
/**
* Whether this type is not going to be changed during the mangling.
* @return Whether the type is unchangable.
*/
public boolean isImmutable() {
return isImmutable;
}//isImmutable()//
/**
* Gets the type data.
* @return The type.
*/
public Type getType() {
return type;
}//getType()//
/**
* Gets the metadata for the constants defined in the type.
* @return The constant metadata collection.
*/
public ConstantCollection getConstantCollection() {
return constantCollection;
}//getConstantCollection()//
/**
* Gets the type name.
* @return The name of the class (com/test/ClassName$InnerClassName).
*/
public String getName() {
return name;
}//getName()//
}//TypeMetadata//
/**
* Maintains modifyable metadata on the type which can be later rolled back into the type.
*/
protected class ConstantCollection {
/** The zero based indexed collection of ConstantMetadata instances. Double size constants only take one space in this collection. */
private LiteList constantMetadata = null;
/** The FieldMetadata instances. */
private LiteList fieldMetadata = null;
/** The MethodMetadata instances. */
private LiteList methodMetadata = null;
/** The InterfaceMetadata instances. */
private LiteList interfaceMetadata = null;
/** the type metadata for this class. */
private ClassMetadata thisType = null;
/** The type metadata for the super class. */
private ClassMetadata superType = null;
/** The type that the constants were pulled from and will be generated to. */
private Type type = null;
/** CodeAttributeMetadata instances for all code attributes in the type. The code attributes are descriptions attached to the type, fields, and methods. They must be tracked because they reference constants in the pool. */
private LiteList codeAttributeMetadata = new LiteList(50, 100);
/** ExceptionMetadata instances for all exceptions defined in code attributes. */
private LiteList exceptionMetadata = new LiteList(50, 100);
public ConstantCollection(Type type) {
LiteList constantsByOriginalIndex = new LiteList(type.getContantCount());
interfaceMetadata = new LiteList(type.getInterfaceCount());
fieldMetadata = new LiteList(type.getFieldCount());
methodMetadata = new LiteList(type.getMethodCount());
constantsByOriginalIndex.add(null);
constantMetadata = new LiteList(type.getContantCount());
this.type = type;
//Create the constant metadata.//
for(int index = 1; index <= type.getContantCount(); index++) {
Constant constant = type.getConstant((short) index);
ConstantMetadata metadata = null;
if(constant instanceof ConstantUtf8) {
metadata = new Utf8ConstantMetadata(type, (ConstantUtf8) constant);
}//if//
else if(constant instanceof ConstantNameAndType) {
metadata = new NameAndTypeConstantMetadata(type, (ConstantNameAndType) constant);
}//else if//
else if(constant instanceof ConstantFieldRef) {
metadata = new FieldRefConstantMetadata(type, (ConstantFieldRef) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantInterfaceMethodRef) {
metadata = new InterfaceMethodRefConstantMetadata(type, (ConstantInterfaceMethodRef) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantMethodRef) {
metadata = new MethodRefConstantMetadata(type, (ConstantMethodRef) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantString) {
metadata = new StringConstantMetadata(type, (ConstantString) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantType) {
metadata = new TypeConstantMetadata(type, (ConstantType) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantDouble) {
metadata = new DoubleConstantMetadata(type, (ConstantDouble) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantFloat) {
metadata = new FloatConstantMetadata(type, (ConstantFloat) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantInteger) {
metadata = new IntegerConstantMetadata(type, (ConstantInteger) constant);
metadata.fixedIndex = index;
}//else if//
else if(constant instanceof ConstantLong) {
metadata = new LongConstantMetadata(type, (ConstantLong) constant);
metadata.fixedIndex = index;
}//else if//
else {
throw new RuntimeException("Unexpected constant type: " + constant.getClass().getName());
}//else//
constantMetadata.add(metadata);
constantsByOriginalIndex.add(metadata);
if(metadata.isDoubleSize()) {
constantsByOriginalIndex.add(null);
index++;
}//if//
}//for//
//Initialize the constant metadata.//
for(int index = 1; index <= type.getContantCount(); index++) {
Constant constant = type.getConstant((short) index);
ConstantMetadata metadata = (ConstantMetadata) constantsByOriginalIndex.get(index);
metadata.initialize(constantsByOriginalIndex, constant);
if(metadata.isDoubleSize()) {
index++;
}//if//
}//for//
//Collect the class's code attributes.//
for(int attributeIndex = 1; attributeIndex <= type.getAttributeCount(); attributeIndex++) {
CodeAttribute nextAttribute = type.getAttribute((short) attributeIndex);
if(nextAttribute instanceof ExceptionIndexes || nextAttribute instanceof InnerClasses || nextAttribute instanceof LineNumberTable || nextAttribute instanceof Synthetic) {
if(nextAttribute instanceof InnerClasses) {
codeAttributeMetadata.add(new InnerClassesMetadata(type, constantsByOriginalIndex, (InnerClasses) nextAttribute));
}//if//
else {
codeAttributeMetadata.add(new CodeAttributeMetadata(type, constantsByOriginalIndex, nextAttribute));
}//else//
}//if//
else if(nextAttribute instanceof SourceFile) {
codeAttributeMetadata.add(new SourceFileMetadata(type, constantsByOriginalIndex, (SourceFile) nextAttribute));
}//else if//
else {
type.removeAttribute((short) attributeIndex);
attributeIndex--;
}//else//
}//for//
//Collect field metadata.//
for(int index = 1; index <= type.getFieldCount(); index++) {
Field field = type.getField((short) index);
fieldMetadata.add(new FieldMetadata(type, constantsByOriginalIndex, field));
//Collect the field's code attributes.//
for(int attributeIndex = 1; attributeIndex <= field.getAttributeCount(); attributeIndex++) {
CodeAttribute nextAttribute = field.getAttribute((short) attributeIndex);
if(nextAttribute instanceof Code || nextAttribute instanceof ConstantValue || nextAttribute instanceof ExceptionIndexes || nextAttribute instanceof InnerClasses || nextAttribute instanceof LineNumberTable || nextAttribute instanceof Synthetic) {
if(nextAttribute instanceof InnerClasses) {
codeAttributeMetadata.add(new InnerClassesMetadata(type, constantsByOriginalIndex, (InnerClasses) nextAttribute));
}//if//
else if(nextAttribute instanceof ConstantValue) {
codeAttributeMetadata.add(new ConstantValueMetadata(type, constantsByOriginalIndex, (ConstantValue) nextAttribute));
}//else if//
else if(nextAttribute instanceof Code) {
Code code = (Code) nextAttribute;
//The Code attribute can its self contain attributes.//
for(int codeAttributeIndex = 1; codeAttributeIndex <= code.getAttributeCount(); codeAttributeIndex++) {
CodeAttribute codeNextAttribute = code.getAttribute((short) codeAttributeIndex);
if(codeNextAttribute instanceof LineNumberTable/* || codeNextAttribute instanceof Synthetic*/) {
codeAttributeMetadata.add(new CodeAttributeMetadata(type, constantsByOriginalIndex, codeNextAttribute));
}//if//
else {
code.removeAttribute((short) codeAttributeIndex);
codeAttributeIndex--;
}//else//
}//for//
//Setup exception metadata for each exception block in the code.//
for(int exceptionIndex = 0; exceptionIndex < code.getExceptionCount(); exceptionIndex++) {
CodeException nextException = code.getException(exceptionIndex);
exceptionMetadata.add(new ExceptionMetadata(type, constantsByOriginalIndex, nextException));
}//for//
codeAttributeMetadata.add(new CodeAttributeMetadata(type, constantsByOriginalIndex, nextAttribute));
}//else if//
else {
codeAttributeMetadata.add(new CodeAttributeMetadata(type, constantsByOriginalIndex, nextAttribute));
}//else//
}//if//
else {
field.removeAttribute((short) attributeIndex);
attributeIndex--;
}//else//
}//for//
}//for//
//Collect method metadata.//
for(int index = 1; index <= type.getMethodCount(); index++) {
Method method = type.getMethod((short) index);
methodMetadata.add(new MethodMetadata(type, constantsByOriginalIndex, method));
//Collect the method's code attributes.//
for(int attributeIndex = 1; attributeIndex <= method.getAttributeCount(); attributeIndex++) {
CodeAttribute nextAttribute = method.getAttribute((short) attributeIndex);
if(nextAttribute instanceof Code || nextAttribute instanceof ExceptionIndexes || nextAttribute instanceof InnerClasses || nextAttribute instanceof LineNumberTable || nextAttribute instanceof Synthetic) {
if(nextAttribute instanceof InnerClasses) {
codeAttributeMetadata.add(new InnerClassesMetadata(type, constantsByOriginalIndex, (InnerClasses) nextAttribute));
}//if//
else if(nextAttribute instanceof Code) {
Code code = (Code) nextAttribute;
//The Code attribute can its self contain attributes.//
for(int codeAttributeIndex = 1; codeAttributeIndex <= code.getAttributeCount(); codeAttributeIndex++) {
CodeAttribute codeNextAttribute = code.getAttribute((short) codeAttributeIndex);
if(codeNextAttribute instanceof LineNumberTable/* || codeNextAttribute instanceof Synthetic*/) {
codeAttributeMetadata.add(new CodeAttributeMetadata(type, constantsByOriginalIndex, codeNextAttribute));
}//if//
else {
code.removeAttribute((short) codeAttributeIndex);
codeAttributeIndex--;
}//else//
}//for//
//Setup exception metadata for each exception block in the code.//
for(int exceptionIndex = 0; exceptionIndex < code.getExceptionCount(); exceptionIndex++) {
CodeException nextException = code.getException(exceptionIndex);
exceptionMetadata.add(new ExceptionMetadata(type, constantsByOriginalIndex, nextException));
}//for//
codeAttributeMetadata.add(new CodeAttributeMetadata(type, constantsByOriginalIndex, nextAttribute));
}//else if//
else {
codeAttributeMetadata.add(new CodeAttributeMetadata(type, constantsByOriginalIndex, nextAttribute));
}//else//
}//if//
else {
method.removeAttribute((short) attributeIndex);
attributeIndex--;
}//else//
}//for//
}//for//
//Collect interface metadata.//
for(int index = 1; index <= type.getInterfaceCount(); index++) {
Interface inter = type.getInterface((short) index);
interfaceMetadata.add(new InterfaceMetadata(type, constantsByOriginalIndex, inter));
}//for//
//Collect this metadata.//
thisType = new ClassMetadata(type, constantsByOriginalIndex, false);
//Collect super metadata.//
superType = new ClassMetadata(type, constantsByOriginalIndex, true);
}//ConstantCollection()//
/**
* Gets the constant metadata.
* @return The metadata for the constants and related data.
*/
public IList getConstantMetadata() {
return constantMetadata;
}//getConstantMetadata()//
/**
* Gets the class metadata for the type the metadata describes.
* @return This class's metadata.
*/
public ClassMetadata getThisType() {
return thisType;
}//getThisType()//
/**
* Adds a constant metadata to the collection.
* @param constant The constant to be added.
*/
public void addConstant(ConstantMetadata constant) {
constantMetadata.add(constant);
}//addConstant()//
/**
* Gets the constant at the given index.
* @param index The zero based index of the constant to be retreived.
* @return The constant metadata.
*/
public ConstantMetadata getConstant(int index) {
return (ConstantMetadata) constantMetadata.get(index);
}//getConstant()//
/**
* Initializes the references from the constants to the things referencing them (constants, fields, methods, etc).
*/
public void initializeConstantReferences() {
for(int index = 0; index < constantMetadata.getSize(); index++) {
ConstantMetadata metadata = (ConstantMetadata) constantMetadata.get(index);
metadata.clearReferencingMetadata();
}//for//
for(int index = 0; index < constantMetadata.getSize(); index++) {
Metadata metadata = (Metadata) constantMetadata.get(index);
metadata.setupReferencedMetadata();
}//for//
for(int index = 0; index < fieldMetadata.getSize(); index++) {
Metadata metadata = (Metadata) fieldMetadata.get(index);
metadata.setupReferencedMetadata();
}//for//
for(int index = 0; index < methodMetadata.getSize(); index++) {
Metadata metadata = (Metadata) methodMetadata.get(index);
metadata.setupReferencedMetadata();
}//for//
for(int index = 0; index < interfaceMetadata.getSize(); index++) {
Metadata metadata = (Metadata) interfaceMetadata.get(index);
metadata.setupReferencedMetadata();
}//for//
for(int index = 0; index < codeAttributeMetadata.getSize(); index++) {
CodeAttributeMetadata next = (CodeAttributeMetadata) codeAttributeMetadata.get(index);
next.setupReferencedMetadata();
}//for//
thisType.setupReferencedMetadata();
superType.setupReferencedMetadata();
}//initializeConstantReferences()//
/**
* Applies the constants to the type.
* Ensures that duplicate and unreferenced constants are removed.
*/
public void applyConstants() {
boolean hasDuplicates = true;
LiteList tempConstantMetadata;
LiteList allMetadata = new LiteList(constantMetadata.getSize() + fieldMetadata.getSize() + methodMetadata.getSize() + interfaceMetadata.getSize() + 2);
allMetadata.addAll(constantMetadata);
allMetadata.addAll(fieldMetadata);
allMetadata.addAll(methodMetadata);
allMetadata.addAll(interfaceMetadata);
allMetadata.add(thisType);
allMetadata.add(superType);
allMetadata.addAll(codeAttributeMetadata);
allMetadata.addAll(exceptionMetadata);
//Clear any reference collections.//
for(int index = 0; index < constantMetadata.getSize(); index++) {
ConstantMetadata metadata = (ConstantMetadata) constantMetadata.get(index);
metadata.clearReferencingMetadata();
}//for//
//Initialize the reference collections.//
for(int index = 0; index < allMetadata.getSize(); index++) {
Metadata metadata = (Metadata) allMetadata.get(index);
metadata.setupReferencedMetadata();
}//for//
//Remove duplicate constants.//
while(hasDuplicates) {
hasDuplicates = false;
for(int outerIndex = 0; outerIndex < constantMetadata.getSize(); outerIndex++) {
ConstantMetadata outer = (ConstantMetadata) constantMetadata.get(outerIndex);
for(int innerIndex = outerIndex + 1; innerIndex < constantMetadata.getSize(); innerIndex++) {
ConstantMetadata inner = (ConstantMetadata) constantMetadata.get(innerIndex);
if(outer.equals(inner)) {
hasDuplicates = true;
//Replace the referencing constants to replace the duplicate with the first occurance.//
for(int index = 0; index < inner.getReferencingMetadata().getSize(); index++) {
if(index != innerIndex && index != outerIndex) {
Metadata metadata = (Metadata) inner.getReferencingMetadata().get(index);
metadata.replace(inner, outer);
}//if//
}//for//
inner.transferReferencingConstants(outer);
constantMetadata.remove(innerIndex);
innerIndex--;
}//if//
}//for//
}//for//
}//while//
//Remove unused constants.//
for(int index = 0; index < constantMetadata.getSize(); index++) {
ConstantMetadata constant = (ConstantMetadata) constantMetadata.get(index);
if(constant.isUnused()) {
constantMetadata.remove(index);
index--;
}//if//
}//for//
tempConstantMetadata = new LiteList(constantMetadata.getSize() + 1, 20);
// if(thisType.type.originalValue.equals("com/foundation/view/builder/IVmlBuilder")) {
// Debug.log("");
// }
//Place constants in the temporary constant metadata collection that do have fixed indices.//
for(int index = 0; index < constantMetadata.getSize(); index++) {
ConstantMetadata constant = (ConstantMetadata) constantMetadata.get(index);
if(constant.fixedIndex != 0) {
tempConstantMetadata.set(constant.fixedIndex, constant);
}//if//
}//for//
//Place constants in the temporary constant metadata collection that don't have fixed indices.//
for(int index = 0, lastEmptyIndex = 0; index < constantMetadata.getSize(); index++) {
ConstantMetadata constant = (ConstantMetadata) constantMetadata.get(index);
if(constant.fixedIndex == 0) {
ConstantMetadata next;
//Find the next empty index in the temporary constant metadata collection.//
do {
next = tempConstantMetadata.getSize() > ++lastEmptyIndex ? (ConstantMetadata) tempConstantMetadata.get(lastEmptyIndex) : null;
if(next != null && next.isDoubleSize()) {
lastEmptyIndex++;
}//if//
} while(next != null);
//Place the constant in the next empty space in the temporary constant metadata collection.//
tempConstantMetadata.set(lastEmptyIndex, constant);
if(constant.isDoubleSize()) {
lastEmptyIndex++;
}//if//
}//if//
}//for//
//Fill any holes (might happen in very rare cases where code attributes were removed and they weren't enough floating constants after the code attribute name to fill the void).//
for(int index = 1; index < tempConstantMetadata.getSize(); index++) {
ConstantMetadata next = (ConstantMetadata) tempConstantMetadata.get(index);
if(next == null) {
tempConstantMetadata.set(index, new Utf8ConstantMetadata(type, ""));
}//if//
else if(next.isDoubleSize()) {
index++;
}//else if//
}//for//
//Swap the items.//
constantMetadata.replaceAll(tempConstantMetadata);
//Index constants.//
for(int index = 1; index < constantMetadata.getSize(); index++) {
ConstantMetadata constant = (ConstantMetadata) constantMetadata.get(index);
constant.index = index;
if(constant.isDoubleSize()) {
index++;
}//if//
}//for//
//Remove type's constants.//
type.removeAllConstants();
//Refresh the collection of all metadata as some have potentially been removed.//
allMetadata.removeAll();
allMetadata.addAll(fieldMetadata);
allMetadata.addAll(methodMetadata);
allMetadata.addAll(interfaceMetadata);
allMetadata.add(thisType);
allMetadata.add(superType);
allMetadata.addAll(codeAttributeMetadata);
allMetadata.addAll(exceptionMetadata);
allMetadata.addAll(constantMetadata);
//Add constants to the type.//
//Update the field, method, interface, super, and this constant references.//
for(int index = 0; index < allMetadata.getSize(); index++) {
Metadata metadata = (Metadata) allMetadata.get(index);
//Ignore the holes in the constant metadata collection - some constants are double width and as such leave a hole in the collection (bad Sun Microsystems).//
if(metadata != null) {
metadata.applyChanges();
}//if//
}//for//
}//applyConstants()//
}//ConstantCollection//
/**
* The base class for field, method, interface, type, and constant metadata.
*/
protected static abstract class Metadata {
private Type type = null;
public Metadata(Type type) {
this.type = type;
}//Metadata()//
public Type getType() {
return type;
}//getType()//
public void setupReferencedMetadata() {
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
}//replace()//
public abstract void applyChanges();
}//Metadata//
/**
* Describes a single exception handler in a code attribute and tracks its constant references.
*/
protected static class ExceptionMetadata extends Metadata {
private CodeException codeException = null;
public TypeConstantMetadata type = null;
public ExceptionMetadata(Type type, IList constantsByOriginalIndex, CodeException codeException) {
super(type);
this.codeException = codeException;
//Not exactly sure why the catch type can be zero.. I suspect it is due to a synchronization block, but it would take some research time. An example is readType() in AbstractObjectInputStream.//
if(codeException.catchType != 0) {
this.type = (TypeConstantMetadata) constantsByOriginalIndex.get(codeException.catchType);
}//if//
}//CodeAttributeMetadata()//
public void setupReferencedMetadata() {
if(type != null) {
type.addReferencingMetadata(this);
}//if//
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(type == replaced) {
type = (TypeConstantMetadata) replacement;
}//if//
}//replace()//
public void applyChanges() {
if(type != null) {
codeException.catchType = (short) type.getIndex();
}//if//
}//applyChanges()//
}//ExceptionMetadata//
/**
* Describes a single code attribute and tracks its constant references.
*/
protected static class CodeAttributeMetadata extends Metadata {
private CodeAttribute codeAttribute = null;
public Utf8ConstantMetadata name = null;
public CodeAttributeMetadata(Type type, IList constantsByOriginalIndex, CodeAttribute codeAttribute) {
super(type);
this.codeAttribute = codeAttribute;
name = (Utf8ConstantMetadata) constantsByOriginalIndex.get(codeAttribute.getNameIndex());
}//CodeAttributeMetadata()//
public void setupReferencedMetadata() {
name.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(name == replaced) {
name = (Utf8ConstantMetadata) replacement;
}//if//
}//replace()//
public void applyChanges() {
codeAttribute.setNameIndex((short) name.getIndex());
}//applyChanges()//
}//CodeAttributeMetadata//
/**
* Describes a reference to a constant used to initialize a field's value.
*/
protected class SourceFileMetadata extends CodeAttributeMetadata {
private SourceFile sourceFile = null;
public Utf8ConstantMetadata value = null;
private boolean mangle = true;
public SourceFileMetadata(Type type, IList constantsByOriginalIndex, SourceFile sourceFile) {
super(type, constantsByOriginalIndex, sourceFile);
this.sourceFile = sourceFile;
value = (Utf8ConstantMetadata) constantsByOriginalIndex.get(sourceFile.getSourceFileIndex());
}//SourceFileMetadata()//
public void setupReferencedMetadata() {
super.setupReferencedMetadata();
value.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
super.replace(replaced, replacement);
if(value == replaced) {
mangle = false;
value = (Utf8ConstantMetadata) replacement;
}//if//
}//replace()//
public void applyChanges() {
super.applyChanges();
if(mangle && mangleSourceFileNames) {
value.value = "na";
}//if//
sourceFile.setSourceFileIndex((short) value.getIndex());
}//applyChanges()//
}//ConstantValueMetadata//
/**
* Describes a reference to a constant used to initialize a field's value.
*/
protected static class ConstantValueMetadata extends CodeAttributeMetadata {
private ConstantValue constantValue = null;
public ConstantMetadata value = null;
public ConstantValueMetadata(Type type, IList constantsByOriginalIndex, ConstantValue constantValue) {
super(type, constantsByOriginalIndex, constantValue);
this.constantValue = constantValue;
value = (ConstantMetadata) constantsByOriginalIndex.get(constantValue.getConstantIndex());
}//ConstantValueMetadata()//
public void setupReferencedMetadata() {
super.setupReferencedMetadata();
value.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
super.replace(replaced, replacement);
if(value == replaced) {
value = (ConstantMetadata) replacement;
}//if//
}//replace()//
public void applyChanges() {
super.applyChanges();
constantValue.setConstantIndex((short) value.getIndex());
}//applyChanges()//
}//ConstantValueMetadata//
/**
* Describes a single code attribute and trackes its constant references.
*/
protected static class InnerClassesMetadata extends CodeAttributeMetadata {
private InnerClasses innerClasses = null;
public Utf8ConstantMetadata[] innerClassNames = null;
public TypeConstantMetadata[] innerClassInfos = null;
public TypeConstantMetadata[] outerClassInfos = null;
public InnerClassesMetadata(Type type, IList constantsByOriginalIndex, InnerClasses innerClasses) {
super(type, constantsByOriginalIndex, innerClasses);
this.innerClasses = innerClasses;
this.innerClassNames = new Utf8ConstantMetadata[innerClasses.getInnerClassesCount()];
this.innerClassInfos = new TypeConstantMetadata[innerClasses.getInnerClassesCount()];
this.outerClassInfos = new TypeConstantMetadata[innerClasses.getInnerClassesCount()];
for(int index = 0; index < innerClasses.getInnerClassesCount(); index++) {
InnerClasses.InnerClass next = innerClasses.getInnerClass(index);
innerClassNames[index] = next.innerNameIndex != 0 ? (Utf8ConstantMetadata) constantsByOriginalIndex.get(next.innerNameIndex) : null;
innerClassInfos[index] = (TypeConstantMetadata) constantsByOriginalIndex.get(next.innerClassInfo);
outerClassInfos[index] = next.outerClassInfo != 0 ? (TypeConstantMetadata) constantsByOriginalIndex.get(next.outerClassInfo) : null;
}//for//
}//InnerClassesMetadata()//
/**
* Gets the index of the inner class referencing the given metadata.
* @param referencedMetadata The metadata referenced by this inner classes object.
* @return The index of the inner class referening the metadata.
*/
public int getInnerClassIndex(Metadata referencedMetadata) {
int result = -1;
if(referencedMetadata instanceof Utf8ConstantMetadata) {
for(int index = 0; result == -1 && index < innerClassNames.length; index++) {
if(innerClassNames[index] == referencedMetadata) {
result = index;
}//if//
}//for//
}//if//
else if(referencedMetadata instanceof TypeConstantMetadata) {
for(int index = 0; result == -1 && index < innerClassInfos.length; index++) {
if(innerClassInfos[index] == referencedMetadata || outerClassInfos[index] == referencedMetadata) {
result = index;
}//if//
}//for//
}//else if//
else {
throw new RuntimeException();
}//else//
return result;
}//getInnerClassIndex()//
public void setupReferencedMetadata() {
super.setupReferencedMetadata();
for(int index = 0; index < innerClassNames.length; index++) {
if(innerClassNames[index] != null) {
innerClassNames[index].addReferencingMetadata(this);
}//if//
}//for//
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
super.replace(replaced, replacement);
for(int index = 0; index < innerClassNames.length; index++) {
if(innerClassNames[index] == replaced) {
innerClassNames[index] = (Utf8ConstantMetadata) replacement;
}//if//
if(innerClassInfos[index] == replaced) {
innerClassInfos[index] = (TypeConstantMetadata) replacement;
}//if//
if(outerClassInfos[index] == replaced) {
outerClassInfos[index] = (TypeConstantMetadata) replacement;
}//if//
}//for//
}//replace()//
public void applyChanges() {
super.applyChanges();
for(int index = 0; index < innerClassNames.length; index++) {
InnerClasses.InnerClass next = innerClasses.getInnerClass(index);
if(innerClassNames[index] != null) {
next.innerNameIndex = (short) innerClassNames[index].getIndex();
}//if//
next.innerClassInfo = (short) innerClassInfos[index].getIndex();
if(outerClassInfos[index] != null) {
next.outerClassInfo = (short) outerClassInfos[index].getIndex();
}//if//
}//for//
}//applyChanges()//
}//InnerClassesMetadata//
/**
* Metadata for a field defined by the type (versus a field reference in the constant pool that references a field defined by some other type).
*/
protected static class FieldMetadata extends Metadata {
public Utf8ConstantMetadata name = null;
public Utf8ConstantMetadata descriptor = null;
public String originalName = null;
public String originalDescriptor = null;
private Field field = null;
public FieldMetadata(Type type, IList constantsByOriginalIndex, Field field) {
super(type);
this.field = field;
name = (Utf8ConstantMetadata) constantsByOriginalIndex.get(field.getFieldNameIndex());
descriptor = (Utf8ConstantMetadata) constantsByOriginalIndex.get(field.getDescriptorIndex());
originalName = name.value;
originalDescriptor = descriptor.value;
}//FieldMetadata()//
public void setupReferencedMetadata() {
name.addReferencingMetadata(this);
descriptor.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(name == replaced) {
name = (Utf8ConstantMetadata) replacement;
}//if//
else if(descriptor == replaced) {
descriptor = (Utf8ConstantMetadata) replacement;
}//else if//
}//replace()//
public final void applyChanges() {
field.setFieldNameIndex((short) name.getIndex());
field.setDescriptorIndex((short) descriptor.getIndex());
}//applyChanges()//
public String toString() {
return descriptor.value + " " + name.value + (Comparator.equals(name.value, originalName) && Comparator.equals(originalDescriptor, descriptor.value) ? "" : " {" + originalName + " " + originalDescriptor + "}");
}//toString()//
}//FieldMetadata//
/**
* Metadata for a method defined by the type (versus a method reference in the constant pool that references a method defined by some other type).
*/
protected static class MethodMetadata extends Metadata {
public Utf8ConstantMetadata name = null;
public Utf8ConstantMetadata descriptor = null;
public String originalDescriptor = null;
private Method method = null;
public MethodMetadata(Type type, IList constantsByOriginalIndex, Method method) {
super(type);
this.method = method;
name = (Utf8ConstantMetadata) constantsByOriginalIndex.get(method.getNameIndex());
descriptor = (Utf8ConstantMetadata) constantsByOriginalIndex.get(method.getDescriptorIndex());
originalDescriptor = descriptor.value;
}//MethodMetadata()//
public void setupReferencedMetadata() {
name.addReferencingMetadata(this);
descriptor.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(name == replaced) {
name = (Utf8ConstantMetadata) replacement;
}//if//
else if(descriptor == replaced) {
descriptor = (Utf8ConstantMetadata) replacement;
}//else if//
}//replace()//
public final void applyChanges() {
method.setNameIndex((short) name.getIndex());
method.setDescriptorIndex((short) descriptor.getIndex());
}//applyChanges()//
public String toString() {
return name.value + descriptor.value + (Comparator.equals(originalDescriptor, descriptor.value) ? "" : " {" + name + originalDescriptor + "}");
}//toString()//
}//MethodMetadata//
/**
* Metadata for an interface implemented by the type.
*/
protected static class InterfaceMetadata extends Metadata {
public TypeConstantMetadata type = null;
private Interface inter = null;
public InterfaceMetadata(Type type, IList constantsByOriginalIndex, Interface inter) {
super(type);
this.inter = inter;
this.type = (TypeConstantMetadata) constantsByOriginalIndex.get(inter.getClassIndex());
}//InterfaceMetadata()//
public void setupReferencedMetadata() {
type.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(type == replaced) {
type = (TypeConstantMetadata) replacement;
}//if//
}//replace()//
public final void applyChanges() {
inter.setClassIndex((short) type.getIndex());
}//applyChanges()//
}//InterfaceMetadata//
/**
* Metadata for an interface implemented by the type.
*/
protected static class ClassMetadata extends Metadata {
public TypeConstantMetadata type = null;
private boolean isSuper = false;
public ClassMetadata(Type type, IList constantsByOriginalIndex, boolean isSuper) {
super(type);
this.type = (TypeConstantMetadata) constantsByOriginalIndex.get(isSuper ? type.getParentReference() : type.getThisReference());
this.isSuper = isSuper;
}//ClassMetadata()//
public void setupReferencedMetadata() {
type.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(type == replaced) {
type = (TypeConstantMetadata) replacement;
}//if//
}//replace()//
public final void applyChanges() {
if(isSuper) {
getType().setParentReference((short) type.getIndex());
}//if//
else {
getType().setThisReference((short) type.getIndex());
}//else//
}//applyChanges()//
}//ClassMetadata//
/**
* The base class for the constant metadata classes.
*/
protected static abstract class ConstantMetadata extends Metadata {
/** The one based index of the constant - initialized after all the constants have been cleaned up and ordered. */
protected int index = 0;
protected int fixedIndex = 0;
/** Contains Metadata instances. Used exclusively by ConstantCollection to figure out which constants are not referenced, and to update referencing metadata when duplicates are found. */
private LiteList referencingMetadata = new LiteList(10, 20);
public ConstantMetadata(Type type) {
super(type);
}//ConstantMetadata()//
public abstract void createConstant();
public void initialize(IList constantsByOriginalIndex, Constant constant) {
}//initialize()//
public boolean isDoubleSize() {
return false;
}//isDoubleSize()//
/**
* Gets the one based index of the constant metadata.
* @return The one based index, valid only after the constant collection updates the indicies.
*/
public int getIndex() {
return index;
}//getIndex()//
public void clearReferencingMetadata() {
referencingMetadata.removeAll();
}//clearReferencingMetadata()//
protected final void addReferencingMetadata(Metadata referencingMetadata) {
this.referencingMetadata.add(referencingMetadata);
}//addReferencingConstant()//
public final void transferReferencingConstants(ConstantMetadata targetConstant) {
targetConstant.referencingMetadata.addAll(referencingMetadata);
referencingMetadata.removeAll();
}//transferReferencingConstants()//
public final LiteList getReferencingMetadata() {
return referencingMetadata;
}//getReferencingConstants()//
public boolean isUnused() {
return false;
}//isUnused()//
public final void applyChanges() {
createConstant();
}//applyChanges()//
}//ConstantMetadata//
/**
* The UTF8 constant metadata.
*/
protected static class Utf8ConstantMetadata extends ConstantMetadata {
public String originalValue = null;
public String value = null;
public Utf8ConstantMetadata(Type type, ConstantUtf8 constant) {
super(type);
this.originalValue = this.value = constant.getValue();
}//Utf8ConstantMetadata()//
public Utf8ConstantMetadata(Type type, String value) {
super(type);
this.originalValue = null;
this.value = value;
}//Utf8ConstantMetadata()//
/**
* Tests whether the value has been mangled yet.
* @return Whether the value represented by this UTF8 metadata has been previously mangled.
*/
public boolean isMangled() {
return originalValue != value;
}//isMangled()//
public void createConstant() {
getType().addConstant(new ConstantUtf8(getType(), value), true);
}//createConstant()//
public boolean equals(Object object) {
return object instanceof Utf8ConstantMetadata && Comparator.equals(((Utf8ConstantMetadata) object).value, value);
}//equals()//
public boolean isUnused() {
//If the code references this UTF8, it will be through a StringConstant.//
boolean result = true;
for(int index = 0; result && index < getReferencingMetadata().getSize(); index++) {
Metadata next = (Metadata) getReferencingMetadata().get(index);
result = next instanceof NameAndTypeConstantMetadata && ((NameAndTypeConstantMetadata) next).isUnused();
}//for//
return result;
}//isUnused()//
public String toString() {
return value;
}//toString()//
}//Utf8ConstantMetadata//
/**
* The string constant metadata.
*/
protected static class StringConstantMetadata extends ConstantMetadata {
public Utf8ConstantMetadata utf8 = null;
public StringConstantMetadata(Type type, ConstantString constant) {
super(type);
}//StringConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantString(getType(), (short) utf8.getIndex()), true);
}//createConstant()//
public void initialize(IList constantsByOriginalIndex, Constant constant) {
utf8 = (Utf8ConstantMetadata) constantsByOriginalIndex.get(((ConstantString) constant).getStringIndex());
}//initialize()//
public boolean equals(Object object) {
return object instanceof StringConstantMetadata && ((StringConstantMetadata) object).utf8 == utf8;
}//equals()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(utf8 == replaced) {
utf8 = (Utf8ConstantMetadata) replacement;
}//if//
}//replace()//
public void setupReferencedMetadata() {
utf8.addReferencingMetadata(this);
}//setupReferencedMetadata()//
}//StringConstantMetadata//
/**
* The type constant metadata.
*/
protected static class TypeConstantMetadata extends ConstantMetadata {
public Utf8ConstantMetadata name = null;
public String originalValue = null;
public TypeConstantMetadata(Type type, ConstantType constant) {
super(type);
}//TypeConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantType(getType(), (short) name.getIndex()), true);
}//createConstant()//
public void initialize(IList constantsByOriginalIndex, Constant constant) {
name = (Utf8ConstantMetadata) constantsByOriginalIndex.get(((ConstantType) constant).getNameIndex());
originalValue = name.value;
}//initialize()//
public boolean equals(Object object) {
return object instanceof TypeConstantMetadata && ((TypeConstantMetadata) object).name == name;
}//equals()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(name == replaced) {
name = (Utf8ConstantMetadata) replacement;
}//if//
}//replace()//
public void setupReferencedMetadata() {
name.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public String toString() {
return name.value + (Comparator.equals(name.value, originalValue) ? "" : " {" + originalValue + "}");
}//toString()//
}//TypeConstantMetadata//
/**
* The name and type constant metadata.
*/
protected static class NameAndTypeConstantMetadata extends ConstantMetadata {
public Utf8ConstantMetadata name = null;
public Utf8ConstantMetadata descriptor = null;
public String originalName = null;
public String originalDescriptor = null;
public NameAndTypeConstantMetadata(Type type, ConstantNameAndType constant) {
super(type);
}//NameAndTypeConstantMetadata()//
public NameAndTypeConstantMetadata(Type type, Utf8ConstantMetadata name, Utf8ConstantMetadata descriptor) {
super(type);
this.name = name;
this.originalName = name.value;
this.descriptor = descriptor;
this.originalDescriptor = descriptor.value;
}//NameAndTypeConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantNameAndType(getType(), (short) name.getIndex(), (short) descriptor.getIndex()), true);
}//createConstant()//
public void initialize(IList constantsByOriginalIndex, Constant constant) {
name = (Utf8ConstantMetadata) constantsByOriginalIndex.get(((ConstantNameAndType) constant).getNameIndex());
descriptor = (Utf8ConstantMetadata) constantsByOriginalIndex.get(((ConstantNameAndType) constant).getDescriptorIndex());
originalDescriptor = descriptor.value;
originalName = name.value;
}//initialize()//
public boolean equals(Object object) {
return object instanceof NameAndTypeConstantMetadata && ((NameAndTypeConstantMetadata) object).name == name && ((NameAndTypeConstantMetadata) object).descriptor == descriptor;
}//equals()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(name == replaced) {
name = (Utf8ConstantMetadata) replacement;
}//if//
else if(descriptor == replaced) {
descriptor = (Utf8ConstantMetadata) replacement;
}//else if//
}//replace()//
public void setupReferencedMetadata() {
name.addReferencingMetadata(this);
descriptor.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public boolean isUnused() {
//Not referenced by code, just other constants.//
return getReferencingMetadata().getSize() == 0;
}//isUnused()//
public String toString() {
if(descriptor.value.charAt(0) == '(') {
return name.value + descriptor.value + (Comparator.equals(name.value, originalName) && Comparator.equals(descriptor.value, originalDescriptor) ? "" : " [" + originalName + originalDescriptor + "]");
}//if//
else {
return descriptor.value + " " + name.value + (Comparator.equals(name.value, originalName) && Comparator.equals(descriptor.value, originalDescriptor) ? "" : " [" + originalDescriptor + " " + originalName + "]");
}//else//
}//toString()//
}//NameAndTypeConstantMetadata//
/**
* The method reference constant metadata.
*/
protected static class MethodRefConstantMetadata extends ConstantMetadata {
public TypeConstantMetadata type = null;
public NameAndTypeConstantMetadata nameAndType = null;
public NameAndTypeConstantMetadata originalNameAndType = null;
public MethodRefConstantMetadata(Type type, ConstantMethodRef constant) {
super(type);
}//MethodRefConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantMethodRef(getType(), (short) type.getIndex(), (short) nameAndType.getIndex()), true);
}//createConstant()//
public void initialize(IList constantsByOriginalIndex, Constant constant) {
type = (TypeConstantMetadata) constantsByOriginalIndex.get(((ConstantMethodRef) constant).getClassIndex());
nameAndType = (NameAndTypeConstantMetadata) constantsByOriginalIndex.get(((ConstantMethodRef) constant).getNameAndTypeIndex());
originalNameAndType = nameAndType;
}//initialize()//
public boolean equals(Object object) {
return object instanceof MethodRefConstantMetadata && ((MethodRefConstantMetadata) object).type == type && ((MethodRefConstantMetadata) object).nameAndType == nameAndType;
}//equals()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(type == replaced) {
type = (TypeConstantMetadata) replacement;
}//if//
else if(nameAndType == replaced) {
nameAndType = (NameAndTypeConstantMetadata) replacement;
}//else if//
}//replace()//
public void setupReferencedMetadata() {
type.addReferencingMetadata(this);
nameAndType.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public String toString() {
return type.name.value + "." + nameAndType.name.value + nameAndType.descriptor.value + (Comparator.equals(type.name.value, type.originalValue) && Comparator.equals(originalNameAndType.originalName, nameAndType.name.value) && Comparator.equals(originalNameAndType.originalDescriptor, nameAndType.descriptor.value) ? "" : " {" + type.originalValue + "." + originalNameAndType.originalName + originalNameAndType.originalDescriptor + "}");
}//toString()//
}//MethodRefConstantMetadata//
/**
* The interface method reference constant metadata.
*/
protected static class InterfaceMethodRefConstantMetadata extends ConstantMetadata {
public TypeConstantMetadata type = null;
public NameAndTypeConstantMetadata nameAndType = null;
public NameAndTypeConstantMetadata originalNameAndType = null;
public InterfaceMethodRefConstantMetadata(Type type, ConstantInterfaceMethodRef constant) {
super(type);
}//InterfaceMethodRefConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantInterfaceMethodRef(getType(), (short) type.getIndex(), (short) nameAndType.getIndex()), true);
}//createConstant()//
public void initialize(IList constantsByOriginalIndex, Constant constant) {
type = (TypeConstantMetadata) constantsByOriginalIndex.get(((ConstantInterfaceMethodRef) constant).getClassIndex());
nameAndType = (NameAndTypeConstantMetadata) constantsByOriginalIndex.get(((ConstantInterfaceMethodRef) constant).getNameAndTypeIndex());
originalNameAndType = nameAndType;
}//initialize()//
public boolean equals(Object object) {
return object instanceof InterfaceMethodRefConstantMetadata && ((InterfaceMethodRefConstantMetadata) object).type == type && ((InterfaceMethodRefConstantMetadata) object).nameAndType == nameAndType;
}//equals()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(type == replaced) {
type = (TypeConstantMetadata) replacement;
}//if//
else if(nameAndType == replaced) {
nameAndType = (NameAndTypeConstantMetadata) replacement;
}//else if//
}//replace()//
public void setupReferencedMetadata() {
type.addReferencingMetadata(this);
nameAndType.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public String toString() {
return type.name.value + "." + nameAndType.name.value + nameAndType.descriptor.value + (Comparator.equals(type.name.value, type.originalValue) && Comparator.equals(originalNameAndType.originalName, nameAndType.name.value) && Comparator.equals(originalNameAndType.originalDescriptor, nameAndType.descriptor.value) ? "" : " [" + type.originalValue + "." + originalNameAndType.originalName + originalNameAndType.originalDescriptor + "]");
}//toString()//
}//InterfaceMethodRefConstantMetadata//
/**
* The field reference constant metadata.
*/
protected static class FieldRefConstantMetadata extends ConstantMetadata {
public TypeConstantMetadata type = null;
public NameAndTypeConstantMetadata nameAndType = null;
public NameAndTypeConstantMetadata originalNameAndType = null;
public FieldRefConstantMetadata(Type type, ConstantFieldRef constant) {
super(type);
}//FieldRefConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantFieldRef(getType(), (short) type.getIndex(), (short) nameAndType.getIndex()), true);
}//createConstant()//
public void initialize(IList constantsByOriginalIndex, Constant constant) {
type = (TypeConstantMetadata) constantsByOriginalIndex.get(((ConstantFieldRef) constant).getClassIndex());
nameAndType = (NameAndTypeConstantMetadata) constantsByOriginalIndex.get(((ConstantFieldRef) constant).getNameAndTypeIndex());
originalNameAndType = nameAndType;
}//initialize()//
public boolean equals(Object object) {
return object instanceof FieldRefConstantMetadata && ((FieldRefConstantMetadata) object).type == type && ((FieldRefConstantMetadata) object).nameAndType == nameAndType;
}//equals()//
public void replace(ConstantMetadata replaced, ConstantMetadata replacement) {
if(type == replaced) {
type = (TypeConstantMetadata) replacement;
}//if//
else if(nameAndType == replaced) {
nameAndType = (NameAndTypeConstantMetadata) replacement;
}//else if//
}//replace()//
public void setupReferencedMetadata() {
type.addReferencingMetadata(this);
nameAndType.addReferencingMetadata(this);
}//setupReferencedMetadata()//
public String toString() {
return type.name.value + "." + nameAndType.name.value + " (" + nameAndType.descriptor.value + ")" + (Comparator.equals(type.name.value, type.originalValue) && Comparator.equals(originalNameAndType.originalName, nameAndType.name.value) && Comparator.equals(originalNameAndType.originalDescriptor, nameAndType.descriptor.value) ? "" : " {" + type.originalValue + "." + originalNameAndType.originalName + " (" + originalNameAndType.originalDescriptor + ")}");
}//toString()//
}//FieldRefConstantMetadata//
/**
* The integer constant metadata.
*/
protected static class IntegerConstantMetadata extends ConstantMetadata {
public int value = 0;
public IntegerConstantMetadata(Type type, ConstantInteger constant) {
super(type);
value = constant.getValue();
}//IntegerConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantInteger(getType(), value), true);
}//createConstant()//
public boolean equals(Object object) {
return object instanceof IntegerConstantMetadata && ((IntegerConstantMetadata) object).value == value;
}//equals()//
}//IntegerConstantMetadata//
/**
* The long constant metadata.
*/
protected static class LongConstantMetadata extends ConstantMetadata {
public long value = 0;
public LongConstantMetadata(Type type, ConstantLong constant) {
super(type);
value = constant.getValue();
}//LongConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantLong(getType(), value), true);
}//createConstant()//
public boolean equals(Object object) {
return object instanceof LongConstantMetadata && ((LongConstantMetadata) object).value == value;
}//equals()//
public boolean isDoubleSize() {
return true;
}//isDoubleSize()//
}//LongConstantMetadata//
/**
* The float constant metadata.
*/
protected static class FloatConstantMetadata extends ConstantMetadata {
public float value = 0;
public FloatConstantMetadata(Type type, ConstantFloat constant) {
super(type);
value = constant.getValue();
}//FloatConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantFloat(getType(), value), true);
}//createConstant()//
public boolean equals(Object object) {
return object instanceof FloatConstantMetadata && ((FloatConstantMetadata) object).value == value;
}//equals()//
}//FloatConstantMetadata//
/**
* The double constant metadata.
*/
protected static class DoubleConstantMetadata extends ConstantMetadata {
public double value = 0;
public DoubleConstantMetadata(Type type, ConstantDouble constant) {
super(type);
value = constant.getValue();
}//DoubleConstantMetadata()//
public void createConstant() {
getType().addConstant(new ConstantDouble(getType(), value), true);
}//createConstant()//
public boolean equals(Object object) {
return object instanceof DoubleConstantMetadata && ((DoubleConstantMetadata) object).value == value;
}//equals()//
public boolean isDoubleSize() {
return true;
}//isDoubleSize()//
}//DoubleConstantMetadata//
/** The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match. */
private IList excludedPackages = null;
/** The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded. */
private IList includedPackages = null;
/** Whether to mangle the source file names (replace with na). */
private boolean mangleSourceFileNames = false;
/**
* BaseMangler constructor.
* @param excludedPackages The collection of excluded package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. Exclusions will be tested first and all sub-metadata will be considered to match.
* @param includedPackages The collection of included package names (java.lang.String instances). A '/' must be used as separators between the package names, and it should not end with a '/' or an astrix. All sub-metadata will be considered included unless explicitly excluded.
* @param mangleSourceFileNames Whether to mangle the source file names (replace with na).
*/
public BaseMangler(IList excludedPackages, IList includedPackages, boolean mangleSourceFileNames) {
this.excludedPackages = excludedPackages;
this.includedPackages = includedPackages;
this.mangleSourceFileNames = mangleSourceFileNames;
}//BaseMangler()//
/**
* Attempts to match the qualified class name to the metadata that need mangling.
* @param name The qualified class name to test. Must be in the form: "com.test.ClassName$InnerClassName".
* @param metadata The package metadata used to determine if a type name should be mangled.
* @return Whether the class name should be mangled.
*/
protected boolean matches(String name) {
return MangleSupport.matches(name, excludedPackages, includedPackages);
}//matches()//
/**
* Mangles the constant containing a class name in the form com/test/TestClass$InnerTestClass or [Lcom/test/TestClass$InnerTestClass;.
* @param constant The UTF8 constant containing a class name.
* @return The mangled class name.
*/
protected String mangleClassName(Utf8ConstantMetadata constant) {
String name = constant.value;
String result = name;
String prefix = null;
if(name.charAt(name.length() - 1) == ';') {
prefix = name.substring(0, name.indexOf('L') + 1);
name = name.substring(prefix.length(), name.length() - 1);
}//if//
if(matches(name)) {
String mangledName = mangleClassName(name);
createMapping(name, mangledName, TYPE_CLASS);
name = mangledName;
result = prefix != null ? prefix + name + ';' : name;
}//if//
return result;
}//mangleClassName()//
/**
* Mangles the constant containing a method signature in the form (Lcom/company/ClassName$InnerClassName;)Ljava.lang.Object;.
* @param type The type containing the constant (used for debugging).
* @param constant The UTF8 constant containing a method signature.
* @return The mangled signature.
*/
protected String mangleSignature(Type type, Utf8ConstantMetadata constant) {
String signature = constant.value;
StringBuffer output = null;
int beginIndex = signature.indexOf('L');
int endIndex = -1;
int lastAppendIndex = 0;
//Extract each class name by searching for 'L' and then ';', replace those that require it.//
while(beginIndex != -1) {
endIndex = signature.indexOf(';', beginIndex);
if(endIndex != -1) {
String name = signature.substring(beginIndex + 1, endIndex);
if(matches(name)) {
String mangledName;
if(output == null) {
output = new StringBuffer(signature.length() + 20);
output.append(signature.substring(0, beginIndex + 1));
}//if//
else {
output.append(signature.substring(lastAppendIndex, beginIndex + 1));
}//else//
mangledName = mangleClassName(name);
createMapping(name, mangledName, TYPE_CLASS);
output.append(mangledName);
lastAppendIndex = endIndex;
}//if//
beginIndex = signature.indexOf('L', endIndex);
}//if//
else {
Debug.log(new RuntimeException("Error found in the signature: " + signature + " defined in the class: " + getConstantUtf8(type, type.getConstant(type.getThisReference())).getValue()));
beginIndex = -1;
output = null;
}//else//
}//while//
if(output != null) {
output.append(signature.substring(lastAppendIndex));
signature = output.toString();
}//if//
return signature;
}//mangleSignature()//
/**
* Looks at the text constant (ie: one not referenced as a type name, signature, attribute name, method name, or by a name and type) to see if it contains a qualified class name as used when calling MyClass.class or Class.forName("MyClass").
* Ignores anything that is not exclusively a dot & dollar sign delimited class reference.
* @param constant The constant potentially containing a fully qualified class reference.
* @return The mangled text.
*/
protected String mangleText(Utf8ConstantMetadata constant) {
//Unfortunately we need to detect a class name using dot notation here because MyType.class resolves to a call to Class.forName("MyType") when compiled. So "MyType" is a ConstantString reference to a ConstantUtf8, and it must be mangled.//
String value = constant.value;
boolean isClassName = true;
//Check to see if the string is a dot separated class name.//
for(int index = 0; isClassName && index < value.length(); index++) {
char next = value.charAt(index);
isClassName = index == 0 ? Character.isJavaIdentifierStart(next) : index == value.length() - 1 ? Character.isJavaIdentifierPart(next) : next == '.' || next == '$' || Character.isJavaIdentifierPart(next);
}//for//
//If it is class name material and it has at least one dot in the name.//
if(isClassName && value.indexOf('.') != -1) {
String className = value.replace('.', '/');
if(matches(className)) {
String mangledValue = mangleClassName(className);
createMapping(className, mangledValue, TYPE_CLASS_TEXT);
value = mangledValue;
}//if//
}//if//
return value;
}//mangleText()//
/**
* Mangles the given class name.
* <p><b>Warning: This method does not call createMapping(String, String, int). The caller MUST call this method to create the reverse mapping.</b></p>
* @param name The name of the class to be mangled. (com/test/ClassName$InnerClassName)
* @return The managled name.
*/
protected String mangleClassName(String name) {
return MangleSupport.mangleClassName(name);
}//mangleClassName()//
/**
* Adds the name/mangledName pair to any maps provided by the mangler.
* @param name The unmangled name.
* @param mangledName The mangled name.
* @param type The name's context.
*/
protected abstract void createMapping(String name, String mangledName, int type);
/**
* Mangles the given field name.
* @param name The name of the class to be mangled.
* @return The managled name.
*/
protected String mangleFieldName(String name) {
return hashString48(name, (byte) 15);
}//mangleFieldName()//
/**
* Mangles the given method name.
* @param name The name of the method to be mangled.
* @return The managled name.
*/
protected String mangleMethodName(String name) {
return hashString64(name, (byte) 14);
}//mangleMethodName()//
/**
* Hashes the given text into a 60 bit value and a 4 bit prefix.
* @param name The text to be hashed.
* @param firstFourBits The first four bits to use in the hashed value (corresponds to the first hex character in the result).
* @return The hex hash value.
*/
protected String hashString64(String text, byte firstFourBits) {
return MangleSupport.hashString64(text, firstFourBits);
}//hashString64()//
/**
* Hashes the given text into a 44 bit value and a 4 bit prefix.
* @param name The text to be hashed.
* @param firstFourBits The first four bits to use in the hashed value (corresponds to the first hex character in the result).
* @return The hex hash value.
*/
protected String hashString48(String text, byte firstFourBits) {
long number = (((long) text.length()) << 16);
int firstBitPosition = 44;
//Set the highest four bits.//
number |= ((long) (firstFourBits & 0xFF)) << 44;
for(int index = 0; index < text.length(); index++) {
long next = (long) (text.charAt(index) & 0xFFFF);
if(firstBitPosition - 16 >= 0) {
number ^= (next << (firstBitPosition - 16));
}//if//
else {
long wrappedBits = next;
int wrappedBitCount = 16 - firstBitPosition;
//Kill the lower N bits that must be wrapped to the top of the long value.//
next >>= wrappedBitCount;
//Kill the top bits that won't be wrapped to the top of the long value.//
wrappedBits <<= (64 - wrappedBitCount);
//Shift the wrapped bits to appear at the top of the 48 bits of the long (after the first four bits).//
wrappedBits >>>= 20;
//Apply the wrapped & unwrapped bits.//
number ^= (next | wrappedBits);
}//else//
firstBitPosition -= 16;
if(firstBitPosition < 0) {
firstBitPosition += 44;
}//if//
}//for//
return Long.toHexString(number);
}//hashString48()//
/**
* Hashes the given text into a 28 bit value and a 4 bit prefix.
* @param name The text to be hashed.
* @param firstFourBits The first four bits to use in the hashed value (corresponds to the first hex character in the result).
* @return The hex hash value.
*/
protected String hashString32(String text, byte firstFourBits) {
int number = text.length();
int firstBitPosition = 28;
//Set the highest four bits.//
number |= ((int) (firstFourBits & 0xFF)) << 28;
for(int index = 0; index < text.length(); index++) {
int next = (int) (text.charAt(index) & 0xFFFF);
if(firstBitPosition - 16 >= 0) {
number ^= (next << (firstBitPosition - 16));
}//if//
else {
int wrappedBits = next;
int wrappedBitCount = 16 - firstBitPosition;
//Kill the lower N bits that must be wrapped to the top of the long value.//
next >>= wrappedBitCount;
//Kill the top bits that won't be wrapped to the top of the long value.//
wrappedBits <<= (32 - wrappedBitCount);
//Shift the wrapped bits to appear at the top of the long (after the first four bits).//
wrappedBits >>>= 4;
//Apply the wrapped & unwrapped bits.//
number ^= (next | wrappedBits);
}//else//
firstBitPosition -= 16;
if(firstBitPosition < 0) {
firstBitPosition += 28;
}//if//
}//for//
return Integer.toHexString(number);
}//hashString32()//
/**
* Gets the ConstantUtf8 for the given constant reference.
* @param type The type defining the constant.
* @param constant The constant reference.
* @return The actual constant value container.
*/
protected static ConstantUtf8 getConstantUtf8(Type type, Constant constant) {
ConstantUtf8 result = null;
if(constant instanceof ConstantNameAndType) {
constant = type.getConstant(((ConstantNameAndType) constant).getNameIndex());
}//if//
if(constant instanceof ConstantType) {
constant = type.getConstant(((ConstantType) constant).getNameIndex());
}//if//
if(constant instanceof ConstantString) {
constant = type.getConstant(((ConstantString) constant).getStringIndex());
}//if//
if(constant instanceof ConstantUtf8) {
result = (ConstantUtf8) constant;
}//if//
return result;
}//getConstantUtf8()//
}//BaseMangler//