package net.zhuoweizhang.mcpelauncher;
import java.io.*;
import dalvik.system.DexClassLoader;
import org.mozilla.javascript.*;
public class ScriptTranslationCache {
public static final String SCRIPT_DEX_DIR = "dex";
public static final String SCRIPT_ODEX_DIR = "odex";
public static final String CLASS_PACKAGE = "modpe.";
public static Script get(android.content.Context context, File file) throws IOException {
//does the cached file exist?
File dexFile = getDexFile(context, file);
if (!dexFile.exists() || dexFile.lastModified() < file.lastModified()) {
dexScript(context, file);
}
//load the dex
File odexDir = context.getDir(SCRIPT_ODEX_DIR, 0);
DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), odexDir.getAbsolutePath(),
null, ScriptTranslationCache.class.getClassLoader());
try {
Class<? extends Script> scriptClass = (Class<? extends Script>) classLoader.loadClass(CLASS_PACKAGE + getClassName(file));
Script script = scriptClass.newInstance();
return script;
} catch (ClassNotFoundException cnf) {
throw new RuntimeException(cnf);
} catch (InstantiationException in) {
throw new RuntimeException(in);
} catch (IllegalAccessException in) {
//impossible; the constructor should not be private
throw new RuntimeException(in);
}
}
private static String getClassName(File f) {
String name = f.getName();
String nojs = name.substring(0, name.length() - 3);
String mainClassName = getClassName(nojs);
return mainClassName;
}
/**
* Verify that class file names are legal Java identifiers. Substitute
* illegal characters with underscores, and prepend the name with an
* underscore if the file name does not begin with a JavaLetter.
*/
private static String getClassName(String name) {
char[] s = new char[name.length()+1];
char c;
int j = 0;
if (!Character.isJavaIdentifierStart(name.charAt(0))) {
s[j++] = '_';
}
for (int i=0; i < name.length(); i++, j++) {
c = name.charAt(i);
if ( Character.isJavaIdentifierPart(c) ) {
s[j] = c;
} else {
s[j] = '_';
}
}
return (new String(s)).trim();
}
private static File getDexFile(android.content.Context context, File file) {
File dexFileDir = context.getDir(SCRIPT_DEX_DIR, 0);
return new File(dexFileDir, file.getName() + ".dex");
}
private static void dexScript(android.content.Context context, File file) {
TranslateThread parseRunner = new TranslateThread(context, file);
Thread t = new Thread(Thread.currentThread().getThreadGroup(), parseRunner,
"BlockLauncher parse thread", 256*1024);
t.start();
try {
t.join(); //block on this thread
} catch (InterruptedException ie) {
//shouldn't happen
}
if (parseRunner.error != null) {
RuntimeException back;
if (parseRunner.error instanceof RuntimeException) {
back = (RuntimeException) parseRunner.error;
} else {
back = new RuntimeException(parseRunner.error);
}
throw back; //Thursdays
}
}
private static void dexScriptImpl(android.content.Context context, File file) throws IOException {
}
private static class TranslateThread implements Runnable {
private android.content.Context context;
private File file;
public Exception error;
public TranslateThread(android.content.Context context, File file) {
this.context = context;
this.file = file;
}
public void run() {
try {
dexScriptImpl(context, file);
} catch (Exception e) {
e.printStackTrace();
error = e;
}
}
}
}