package net.ptnkjke.jbeditor.logic;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.ptnkjke.jbeditor.Configutation;
import net.ptnkjke.jbeditor.utils.Utils;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.lingala.zip4j.core.ZipFile;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
/**
* CORE
*/
public class Core {
public static Core INSTANCE = new Core();
/**
* key= ClassName, value = byte class represent
*/
private Map<String, byte[]> classMap = new HashMap<String, byte[]>();
/**
* is .jar file loaded or simple .class file?
*/
private boolean isJarFileLoaded = false;
/**
* Original .jar byte-contant for saving change in new jar
*/
private byte[] originalJar;
/**
* Read file
*
* @param inPath
*/
public void read(String inPath) {
// Clear Class Map
classMap.clear();
File file = new File(inPath);
if (file.getName().contains(".jar")) {
readJar(file);
isJarFileLoaded = true;
} else if (file.getName().contains(".class")) {
readClassFile(file);
isJarFileLoaded = false;
}
}
/**
* Read .jar file
*/
private void readJar(File jarFile) {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(jarFile);
} catch (ZipException e) {
e.printStackTrace();
}
List<FileHeader> fileHeaderList = null;
try {
fileHeaderList = zipFile.getFileHeaders();
} catch (ZipException e) {
e.printStackTrace();
}
for (FileHeader fh : fileHeaderList) {
String fileName = fh.getFileName();
if (fileName.contains(".class")) {
JavaClass javaClass = null;
try {
javaClass = new ClassParser(zipFile.getInputStream(fh), fileName).parse();
} catch (IOException e) {
e.printStackTrace();
} catch (ZipException e) {
e.printStackTrace();
}
classMap.put(fileName.replace("/", ".").replace(".class", ""), javaClass.getBytes());
}
}
try {
FileInputStream inputStream = new FileInputStream(jarFile);
this.originalJar = Utils.readAllFromInputStream(inputStream);
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Read .class file
*/
private void readClassFile(File classFile) {
try {
JavaClass javaClass = new ClassParser(classFile.getAbsolutePath()).parse();
classMap.put(javaClass.getClassName(), javaClass.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* SaveAll
*/
public void save() {
if (isJarFileLoaded) {
saveJar();
} else {
saveClassFile();
}
}
/**
* Save .jar file
*/
private void saveJar() {
File workDir = new File(Configutation.workDir, Utils.getRandomName());
workDir.mkdirs();
// CreateTmpFile
File tFile = new File(workDir, Utils.getRandomName() + ".jar");
try {
tFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(tFile);
outputStream.write(originalJar);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// CreateZipFile
ZipFile zipFile = null;
try {
zipFile = new ZipFile(tFile);
} catch (ZipException e) {
e.printStackTrace();
}
workDir = new File(workDir, "classes");
// UpdateAllClassFile
for (Map.Entry<String, byte[]> entry : classMap.entrySet()) {
String className = entry.getKey();
byte[] content = entry.getValue();
className = className.replace(".", "/");
String path = className + ".class";
File f = new File(workDir, path);
f.getParentFile().mkdirs();
try {
outputStream = new FileOutputStream(f);
outputStream.write(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
File[] allPackages = workDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isDirectory();
}
});
File[] allFiles = workDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isFile();
}
});
for (File f : allPackages) {
try {
zipFile.addFolder(f, new ZipParameters());
} catch (ZipException e) {
e.printStackTrace();
}
}
for (File f : allFiles) {
try {
zipFile.addFile(f, new ZipParameters());
} catch (ZipException e) {
e.printStackTrace();
}
}
}
/**
* Save .class file
*/
private void saveClassFile() {
File workDir = new File(Configutation.workDir, Utils.getRandomName());
for (Map.Entry<String, byte[]> entry : classMap.entrySet()) {
String className = entry.getKey();
byte[] content = entry.getValue();
className = className.replace(".", "/");
String path = className.replace(".", "/") + ".class";
File f = new File(workDir, path);
f.getParentFile().mkdirs();
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(f);
outputStream.write(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public byte[] getOriginalJar() {
return originalJar;
}
public void setOriginalJar(byte[] originalJar) {
this.originalJar = originalJar;
}
public boolean isJarFileLoaded() {
return isJarFileLoaded;
}
public void setJarFileLoaded(boolean isJarFileLoaded) {
this.isJarFileLoaded = isJarFileLoaded;
}
public Map<String, byte[]> getClassMap() {
return classMap;
}
public void setClassMap(Map<String, byte[]> classMap) {
this.classMap = classMap;
}
}