From 4be005617b3b8c3578cca07c5d085d12916f0d1d Mon Sep 17 00:00:00 2001 From: lclc98 Date: Thu, 30 Jun 2016 00:49:21 +1000 Subject: Json format (#2) * Added new format * Fixed bug * Updated Version --- src/cuchaz/enigma/convert/ClassIdentity.java | 473 --------------------------- 1 file changed, 473 deletions(-) delete mode 100644 src/cuchaz/enigma/convert/ClassIdentity.java (limited to 'src/cuchaz/enigma/convert/ClassIdentity.java') diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java deleted file mode 100644 index d9ed08e..0000000 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ /dev/null @@ -1,473 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javassist.CannotCompileException; -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtConstructor; -import javassist.CtField; -import javassist.CtMethod; -import javassist.bytecode.BadBytecode; -import javassist.bytecode.CodeIterator; -import javassist.bytecode.ConstPool; -import javassist.bytecode.Descriptor; -import javassist.bytecode.Opcode; -import javassist.expr.ConstructorCall; -import javassist.expr.ExprEditor; -import javassist.expr.FieldAccess; -import javassist.expr.MethodCall; -import javassist.expr.NewExpr; - -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multiset; -import com.google.common.collect.Sets; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Util; -import cuchaz.enigma.analysis.ClassImplementationsTreeNode; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.bytecode.ConstPoolEditor; -import cuchaz.enigma.bytecode.InfoType; -import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; -import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassNameReplacer; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.Signature; -import cuchaz.enigma.mapping.Type; - -public class ClassIdentity { - - private ClassEntry m_classEntry; - private SidedClassNamer m_namer; - private Multiset m_fields; - private Multiset m_methods; - private Multiset m_constructors; - private String m_staticInitializer; - private String m_extends; - private Multiset m_implements; - private Set m_stringLiterals; - private Multiset m_implementations; - private Multiset m_references; - private String m_outer; - - private final ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() { - - private Map m_classNames = Maps.newHashMap(); - - @Override - public String replace(String className) { - - // classes not in the none package can be passed through - ClassEntry classEntry = new ClassEntry(className); - if (!classEntry.getPackageName().equals(Constants.NonePackage)) { - return className; - } - - // is this class ourself? - if (className.equals(m_classEntry.getName())) { - return "CSelf"; - } - - // try the namer - if (m_namer != null) { - String newName = m_namer.getName(className); - if (newName != null) { - return newName; - } - } - - // otherwise, use local naming - if (!m_classNames.containsKey(className)) { - m_classNames.put(className, getNewClassName()); - } - return m_classNames.get(className); - } - - private String getNewClassName() { - return String.format("C%03d", m_classNames.size()); - } - }; - - public ClassIdentity(CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences) { - m_namer = namer; - - // stuff from the bytecode - - m_classEntry = EntryFactory.getClassEntry(c); - m_fields = HashMultiset.create(); - for (CtField field : c.getDeclaredFields()) { - m_fields.add(scrubType(field.getSignature())); - } - m_methods = HashMultiset.create(); - for (CtMethod method : c.getDeclaredMethods()) { - m_methods.add(scrubSignature(method.getSignature()) + "0x" + getBehaviorSignature(method)); - } - m_constructors = HashMultiset.create(); - for (CtConstructor constructor : c.getDeclaredConstructors()) { - m_constructors.add(scrubSignature(constructor.getSignature()) + "0x" + getBehaviorSignature(constructor)); - } - m_staticInitializer = ""; - if (c.getClassInitializer() != null) { - m_staticInitializer = getBehaviorSignature(c.getClassInitializer()); - } - m_extends = ""; - if (c.getClassFile().getSuperclass() != null) { - m_extends = scrubClassName(Descriptor.toJvmName(c.getClassFile().getSuperclass())); - } - m_implements = HashMultiset.create(); - for (String interfaceName : c.getClassFile().getInterfaces()) { - m_implements.add(scrubClassName(Descriptor.toJvmName(interfaceName))); - } - - m_stringLiterals = Sets.newHashSet(); - ConstPool constants = c.getClassFile().getConstPool(); - for (int i=1; i implementations = implementationsNode.children(); - while (implementations.hasMoreElements()) { - ClassImplementationsTreeNode node = implementations.nextElement(); - m_implementations.add(scrubClassName(node.getClassEntry().getName())); - } - } - - m_references = HashMultiset.create(); - if (useReferences) { - for (CtField field : c.getDeclaredFields()) { - FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); - for (EntryReference reference : index.getFieldReferences(fieldEntry)) { - addReference(reference); - } - } - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - for (EntryReference reference : index.getBehaviorReferences(behaviorEntry)) { - addReference(reference); - } - } - } - - m_outer = null; - if (m_classEntry.isInnerClass()) { - m_outer = m_classEntry.getOuterClassName(); - } - } - - private void addReference(EntryReference reference) { - if (reference.context.getSignature() != null) { - m_references.add(String.format("%s_%s", - scrubClassName(reference.context.getClassName()), - scrubSignature(reference.context.getSignature()) - )); - } else { - m_references.add(String.format("%s_", - scrubClassName(reference.context.getClassName()) - )); - } - } - - public ClassEntry getClassEntry() { - return m_classEntry; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append("class: "); - buf.append(m_classEntry.getName()); - buf.append(" "); - buf.append(hashCode()); - buf.append("\n"); - for (String field : m_fields) { - buf.append("\tfield "); - buf.append(field); - buf.append("\n"); - } - for (String method : m_methods) { - buf.append("\tmethod "); - buf.append(method); - buf.append("\n"); - } - for (String constructor : m_constructors) { - buf.append("\tconstructor "); - buf.append(constructor); - buf.append("\n"); - } - if (m_staticInitializer.length() > 0) { - buf.append("\tinitializer "); - buf.append(m_staticInitializer); - buf.append("\n"); - } - if (m_extends.length() > 0) { - buf.append("\textends "); - buf.append(m_extends); - buf.append("\n"); - } - for (String interfaceName : m_implements) { - buf.append("\timplements "); - buf.append(interfaceName); - buf.append("\n"); - } - for (String implementation : m_implementations) { - buf.append("\timplemented by "); - buf.append(implementation); - buf.append("\n"); - } - for (String reference : m_references) { - buf.append("\treference "); - buf.append(reference); - buf.append("\n"); - } - buf.append("\touter "); - buf.append(m_outer); - buf.append("\n"); - return buf.toString(); - } - - private String scrubClassName(String className) { - return m_classNameReplacer.replace(className); - } - - private String scrubType(String typeName) { - return scrubType(new Type(typeName)).toString(); - } - - private Type scrubType(Type type) { - if (type.hasClass()) { - return new Type(type, m_classNameReplacer); - } else { - return type; - } - } - - private String scrubSignature(String signature) { - return scrubSignature(new Signature(signature)).toString(); - } - - private Signature scrubSignature(Signature signature) { - return new Signature(signature, m_classNameReplacer); - } - - private boolean isClassMatchedUniquely(String className) { - return m_namer != null && m_namer.getName(Descriptor.toJvmName(className)) != null; - } - - private String getBehaviorSignature(CtBehavior behavior) { - try { - // does this method have an implementation? - if (behavior.getMethodInfo().getCodeAttribute() == null) { - return "(none)"; - } - - // compute the hash from the opcodes - ConstPool constants = behavior.getMethodInfo().getConstPool(); - final MessageDigest digest = MessageDigest.getInstance("MD5"); - CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator(); - while (iter.hasNext()) { - int pos = iter.next(); - - // update the hash with the opcode - int opcode = iter.byteAt(pos); - digest.update((byte)opcode); - - switch (opcode) { - case Opcode.LDC: { - int constIndex = iter.byteAt(pos + 1); - updateHashWithConstant(digest, constants, constIndex); - } - break; - - case Opcode.LDC_W: - case Opcode.LDC2_W: { - int constIndex = (iter.byteAt(pos + 1) << 8) | iter.byteAt(pos + 2); - updateHashWithConstant(digest, constants, constIndex); - } - break; - } - } - - // update hash with method and field accesses - behavior.instrument(new ExprEditor() { - @Override - public void edit(MethodCall call) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(call.getClassName()))); - updateHashWithString(digest, scrubSignature(call.getSignature())); - if (isClassMatchedUniquely(call.getClassName())) { - updateHashWithString(digest, call.getMethodName()); - } - } - - @Override - public void edit(FieldAccess access) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(access.getClassName()))); - updateHashWithString(digest, scrubType(access.getSignature())); - if (isClassMatchedUniquely(access.getClassName())) { - updateHashWithString(digest, access.getFieldName()); - } - } - - @Override - public void edit(ConstructorCall call) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(call.getClassName()))); - updateHashWithString(digest, scrubSignature(call.getSignature())); - } - - @Override - public void edit(NewExpr expr) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(expr.getClassName()))); - } - }); - - // convert the hash to a hex string - return toHex(digest.digest()); - } catch (BadBytecode | NoSuchAlgorithmException | CannotCompileException ex) { - throw new Error(ex); - } - } - - private void updateHashWithConstant(MessageDigest digest, ConstPool constants, int index) { - ConstPoolEditor editor = new ConstPoolEditor(constants); - ConstInfoAccessor item = editor.getItem(index); - if (item.getType() == InfoType.StringInfo) { - updateHashWithString(digest, constants.getStringInfo(index)); - } - // TODO: other constants - } - - private void updateHashWithString(MessageDigest digest, String val) { - try { - digest.update(val.getBytes("UTF8")); - } catch (UnsupportedEncodingException ex) { - throw new Error(ex); - } - } - - private String toHex(byte[] bytes) { - // function taken from: - // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java - final char[] hexArray = "0123456789ABCDEF".toCharArray(); - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - - @Override - public boolean equals(Object other) { - if (other instanceof ClassIdentity) { - return equals((ClassIdentity)other); - } - return false; - } - - public boolean equals(ClassIdentity other) { - return m_fields.equals(other.m_fields) - && m_methods.equals(other.m_methods) - && m_constructors.equals(other.m_constructors) - && m_staticInitializer.equals(other.m_staticInitializer) - && m_extends.equals(other.m_extends) - && m_implements.equals(other.m_implements) - && m_implementations.equals(other.m_implementations) - && m_references.equals(other.m_references); - } - - @Override - public int hashCode() { - List objs = Lists.newArrayList(); - objs.addAll(m_fields); - objs.addAll(m_methods); - objs.addAll(m_constructors); - objs.add(m_staticInitializer); - objs.add(m_extends); - objs.addAll(m_implements); - objs.addAll(m_implementations); - objs.addAll(m_references); - return Util.combineHashesOrdered(objs); - } - - public int getMatchScore(ClassIdentity other) { - return 2*getNumMatches(m_extends, other.m_extends) - + 2*getNumMatches(m_outer, other.m_outer) - + 2*getNumMatches(m_implements, other.m_implements) - + getNumMatches(m_stringLiterals, other.m_stringLiterals) - + getNumMatches(m_fields, other.m_fields) - + getNumMatches(m_methods, other.m_methods) - + getNumMatches(m_constructors, other.m_constructors); - } - - public int getMaxMatchScore() { - return 2 + 2 + 2*m_implements.size() + m_stringLiterals.size() + m_fields.size() + m_methods.size() + m_constructors.size(); - } - - public boolean matches(CtClass c) { - // just compare declaration counts - return m_fields.size() == c.getDeclaredFields().length - && m_methods.size() == c.getDeclaredMethods().length - && m_constructors.size() == c.getDeclaredConstructors().length; - } - - private int getNumMatches(Set a, Set b) { - int numMatches = 0; - for (String val : a) { - if (b.contains(val)) { - numMatches++; - } - } - return numMatches; - } - - private int getNumMatches(Multiset a, Multiset b) { - int numMatches = 0; - for (String val : a) { - if (b.contains(val)) { - numMatches++; - } - } - return numMatches; - } - - private int getNumMatches(String a, String b) { - if (a == null && b == null) { - return 1; - } else if (a != null && b != null && a.equals(b)) { - return 1; - } - return 0; - } -} -- cgit v1.2.3