package net.mcforkage.ant;
import installer.Utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import bytecode.BaseStreamingJarProcessor;
public class RunMultipleProcessorsTask extends Task {
private File input, output;
private List<Processor> processors = new ArrayList<>();
public void setInput(File f) {input = f;}
public void setOutput(File f) {output = f;}
public static class Processor {
String procClass;
File confFile;
BaseStreamingJarProcessor instance;
public void setClass(String s) {procClass = s;}
public void setConfig(File f) {confFile = f;}
void createInstance() throws BuildException {
Class<? extends BaseStreamingJarProcessor> clazz;
try {
clazz = Class.forName(procClass).asSubclass(BaseStreamingJarProcessor.class);
} catch(ClassNotFoundException | ClassCastException e) {
throw new BuildException("Class not found, or not a streaming JAR processor: " + procClass);
}
try {
instance = clazz.getConstructor().newInstance();
} catch(Exception e) {
throw new BuildException(e);
}
if(instance.hasConfig()) {
if(confFile == null) throw new BuildException("Config not specified for "+procClass);
try (FileReader fr = new FileReader(confFile)) {
instance.loadConfig(fr);
} catch(Exception e) {
throw new BuildException("Failed to load "+confFile+": "+e, e);
}
} else {
if(confFile != null) throw new BuildException(procClass+" does not use a config, but one was specified");
}
}
}
public void addProcessor(Processor p) {
processors.add(p);
}
@Override
public void execute() throws BuildException {
if(input == null) throw new BuildException("Input not set");
if(output == null) throw new BuildException("Output not set");
for(Processor p : processors)
p.createInstance();
try {
try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(input))) {
try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(output))) {
ZipEntry ze;
while((ze = zipIn.getNextEntry()) != null) {
zipOut.putNextEntry(new ZipEntry(ze.getName()));
if(!ze.getName().endsWith(".class")) {
Utils.copyStream(zipIn, zipOut);
} else {
byte[] bytes = Utils.readStream(zipIn);
zipIn.closeEntry();
for(Processor p : processors) {
ClassWriter cw = new ClassWriter(0);
new ClassReader(bytes).accept(p.instance.createClassVisitor(cw), 0);
bytes = cw.toByteArray();
}
zipOut.write(bytes);
}
zipIn.closeEntry();
zipOut.closeEntry();
}
}
}
} catch(Exception e) {
throw new BuildException(e);
}
}
}