package codechicken.obfuscator;
import com.google.common.base.Function;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.commons.RemappingClassAdapter;
import org.objectweb.asm.tree.ClassNode;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintStream;
import java.text.DecimalFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class ObfuscationRun implements ILogStreams {
public final ObfDirection obfDir;
public final ObfuscationMap obf;
public final ObfRemapper obfMapper;
public final ConstantObfuscator cstMappper;
public File[] mappings;
public Map<String, String> config;
private PrintStream out = System.out;
private PrintStream err = System.err;
private PrintStream quietStream = new PrintStream(DummyOutputStream.instance);
private boolean verbose;
private boolean quiet;
public boolean clean;
private long startTime;
private boolean finished;
public ObfuscationRun(boolean obfuscate, File[] mappings, Map<String, String> config) {
obfDir = new ObfDirection().setObfuscate(obfuscate);
this.mappings = mappings;
this.config = config;
obf = new ObfuscationMap().setLog(this);
obfMapper = new ObfRemapper(obf, obfDir);
cstMappper = new ConstantObfuscator(obfMapper, config.get("classConstantCalls").split(","), config.get("descConstantCalls").split(","));
}
public ObfuscationRun setClean() {
clean = true;
return this;
}
public ObfuscationRun setVerbose() {
verbose = true;
return this;
}
public ObfuscationRun setQuiet() {
quiet = true;
return this;
}
public ObfuscationRun setOut(PrintStream p) {
out = p;
return this;
}
public PrintStream out() {
return quiet ? quietStream : out;
}
public PrintStream fine() {
return verbose ? out : quietStream;
}
public ObfuscationRun setErr(PrintStream p) {
err = p;
return this;
}
public PrintStream err() {
return quiet ? quietStream : err;
}
public ObfuscationRun setSearge() {
obfDir.setSearge(true);
return this;
}
public ObfuscationRun setSeargeConstants() {
obfDir.setSeargeConstants(true);
return this;
}
public void start() {
startTime = System.currentTimeMillis();
}
public static Map<String, String> fillDefaults(Map<String, String> config) {
if (!config.containsKey("excludedPackages")) {
config.put("excludedPackages", "java/;sun/;javax/;scala/;" + "argo/;org/lwjgl/;org/objectweb/;org/bouncycastle/;com/google/");
}
if (!config.containsKey("ignore")) {
config.put("ignore", ".");
}
if (!config.containsKey("classConstantCalls")) {
config.put("classConstantCalls", "codechicken/lib/asm/ObfMapping.<init>(Ljava/lang/String;)V," +
"codechicken/lib/asm/ObfMapping.subclass(Ljava/lang/String;)Lcodechicken/lib/asm/ObfMapping;," +
"codechicken/lib/asm/ObfMapping.<init>(Lcodechicken/lib/asm/ObfMapping;Ljava/lang/String;)V");
}
if (!config.containsKey("descConstantCalls")) {
config.put("descConstantCalls", "codechicken/lib/asm/ObfMapping.<init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
"org/objectweb/asm/MethodVisitor.visitFieldInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
"org/objectweb/asm/tree/MethodNode.visitFieldInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
"org/objectweb/asm/MethodVisitor.visitMethodInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
"org/objectweb/asm/tree/MethodNode.visitMethodInsn(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
"org/objectweb/asm/tree/MethodInsnNode.<init>(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V," +
"org/objectweb/asm/tree/FieldInsnNode.<init>(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
}
return config;
}
public static void processLines(File file, Function<String, Void> function) {
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
function.apply(line);
}
reader.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void processFiles(File dir, Function<File, Void> function, boolean recursive) {
for (File file : dir.listFiles()) {
if (file.isDirectory() && recursive) {
processFiles(file, function, recursive);
} else {
function.apply(file);
}
}
}
public static void deleteDir(File directory, boolean remove) {
if (!directory.exists()) {
if (!remove) {
directory.mkdirs();
}
return;
}
for (File file : directory.listFiles()) {
if (file.isDirectory()) {
deleteDir(file, true);
} else {
if (!file.delete()) {
throw new RuntimeException("Delete Failed: " + file);
}
}
}
if (remove) {
if (!directory.delete()) {
throw new RuntimeException("Delete Failed: " + directory);
}
}
}
public static File[] parseConfDir(File confDir) {
File srgDir = new File(confDir, "conf");
if (!srgDir.exists()) {
srgDir = confDir;
}
File srgs = new File(srgDir, "packaged.srg");
if (!srgs.exists()) {
srgs = new File(srgDir, "joined.srg");
}
if (!srgs.exists()) {
throw new RuntimeException("Could not find packaged.srg or joined.srg");
}
File mapDir = new File(confDir, "mappings");
if (!mapDir.exists()) {
mapDir = confDir;
}
File methods = new File(mapDir, "methods.csv");
if (!methods.exists()) {
throw new RuntimeException("Could not find methods.csv");
}
File fields = new File(mapDir, "fields.csv");
if (!fields.exists()) {
throw new RuntimeException("Could not find fields.csv");
}
return new File[] { srgs, methods, fields };
}
public long startTime() {
return startTime;
}
public void remap(ClassNode cnode, ClassVisitor cv) {
cstMappper.transform(cnode);
cnode.accept(new RemappingClassAdapter(cv, obfMapper));
}
public static List<String> getParents(ClassNode cnode) {
List<String> parents = new LinkedList<String>();
if (cnode.superName != null) {
parents.add(cnode.superName);
}
for (String s_interface : cnode.interfaces) {
parents.add(s_interface);
}
return parents;
}
public void finish(boolean errored) {
long millis = System.currentTimeMillis() - startTime;
out().println((errored ? "Errored after" : "Done in ") + new DecimalFormat("0.00").format(millis / 1000D) + "s");
finished = true;
}
public boolean finished() {
return finished;
}
public void parseMappings() {
obf.parseMappings(mappings);
}
}