summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xAndroidManifest.xml3
-rw-r--r--build.gradle5
-rw-r--r--jni/Android.mk2
-rw-r--r--jni/Application.mk2
-rw-r--r--jni/libmspack.mk15
-rw-r--r--jni/unshield.mk14
-rw-r--r--src/pw/cloudef/rpg/Launcher.java1
-rw-r--r--src/pw/cloudef/rpg/Rtp.java133
8 files changed, 174 insertions, 1 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 19d351a..924d827 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -26,6 +26,9 @@
>
<meta-data android:name="android.app.lib_name" android:value=""/>
</activity>
+ <activity android:name=".Rtp" android:exported="true">
+ <meta-data android:name="android.app.lib_name" android:value="" />
+ </activity>
<activity android:name=".Launcher" android:exported="true">
<meta-data android:name="android.app.lib_name" android:value="" />
</activity>
diff --git a/build.gradle b/build.gradle
index cbd2455..2fcbde4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -61,4 +61,9 @@ android {
universalApk false
}
}
+ buildTypes {
+ debug {
+ jniDebuggable true
+ }
+ }
}
diff --git a/jni/Android.mk b/jni/Android.mk
index b0cbf4c..fd15b4e 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -15,6 +15,8 @@ include jni/SDL_mixer/Android.mk
LOCAL_PATH := .
include jni/SDL_mixer.vorbis.mk
include jni/boost.mk
+include jni/libmspack.mk
+include jni/unshield.mk
include jni/OpenAL.mk
include jni/SDL_sound.mk
include jni/physfs.mk
diff --git a/jni/Application.mk b/jni/Application.mk
index 91f5cd6..dd8341a 100644
--- a/jni/Application.mk
+++ b/jni/Application.mk
@@ -4,5 +4,5 @@ APP_OPTIM := release
APP_STL := c++_static
APP_CPPFLAGS := -std=c++11 -frtti -fexceptions
APP_CFLAGS := -fsigned-char -UNDEBUG
-APP_MODULES := mkxp easyrpg physfs-serve
+APP_MODULES := mkxp easyrpg physfs-serve cabextract unshield
APP_DEBUG := 1
diff --git a/jni/libmspack.mk b/jni/libmspack.mk
new file mode 100644
index 0000000..f7e53f8
--- /dev/null
+++ b/jni/libmspack.mk
@@ -0,0 +1,15 @@
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := jni/libmspack/libmspack/mspack
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
+LOCAL_MODULE := mspack
+LOCAL_SRC_FILES := $(filter-out %/debug.c, $(wildcard jni/libmspack/libmspack/mspack/*.c))
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -DVERSION=\"1.9.1\" -DHAVE_MKDIR -DHAVE_ICONV -DHAVE_UMASK -DICONV_CONST= -pie
+LOCAL_C_INCLUDES := jni/libmspack/cabextract
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
+LOCAL_MODULE := cabextract
+LOCAL_SRC_FILES := jni/libmspack/cabextract/src/cabextract.c jni/libmspack/cabextract/md5.c
+LOCAL_STATIC_LIBRARIES := mspack iconv
+include $(BUILD_SHARED_LIBRARY)
diff --git a/jni/unshield.mk b/jni/unshield.mk
new file mode 100644
index 0000000..1d1d406
--- /dev/null
+++ b/jni/unshield.mk
@@ -0,0 +1,14 @@
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -DHAVE_ICONV -DUSE_OUR_OWN_MD5 -DSIZE_FORMAT=\"%%zu\" -pie
+LOCAL_C_INCLUDES := jni/unshield
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
+LOCAL_MODULE := unshield
+LOCAL_SRC_FILES := jni/unshield/src/unshield.c $(wildcard jni/unshield/lib/*.c) jni/unshield/lib/md5/md5c.c jni/unshield/lib/convert_utf/ConvertUTF.c
+LOCAL_STATIC_LIBRARIES := iconv
+LOCAL_LDLIBS := -lz
+
+jni/unshield/lib/unshield_config.h:
+ touch $@
+
+unshield: jni/unshield/lib/unshield_config.h
+include $(BUILD_SHARED_LIBRARY)
diff --git a/src/pw/cloudef/rpg/Launcher.java b/src/pw/cloudef/rpg/Launcher.java
index ab2e9b2..1a5659d 100644
--- a/src/pw/cloudef/rpg/Launcher.java
+++ b/src/pw/cloudef/rpg/Launcher.java
@@ -52,6 +52,7 @@ public class Launcher extends Activity {
GameType type = GameType.UNKNOWN;
while (zipEntries.hasMoreElements()) {
String fname = ((ZipEntry)zipEntries.nextElement()).getName();
+ Log.d("pw.cloudef.rpg", fname);
try {
String base = fname.split(".+?/(?=[^/]+$)")[1];
String name = base.split("\\.(?=[^\\.]+$)")[0];
diff --git a/src/pw/cloudef/rpg/Rtp.java b/src/pw/cloudef/rpg/Rtp.java
new file mode 100644
index 0000000..e647cdb
--- /dev/null
+++ b/src/pw/cloudef/rpg/Rtp.java
@@ -0,0 +1,133 @@
+package pw.cloudef.rpg;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.net.Uri;
+import android.system.Os;
+import android.util.Log;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.nio.charset.Charset;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipEntry;
+import java.util.Enumeration;
+
+public class Rtp extends Activity {
+ protected String rtpDir() {
+ return getApplicationContext().getFilesDir().toPath().toString() + "/rtp";
+ }
+
+ protected String workDir() {
+ return getApplicationContext().getCacheDir().toPath().toString() + "/temp";
+ }
+
+ protected String zipPath() {
+ return workDir() + "/rtp.zip";
+ }
+
+ protected void shell(String cmd) {
+ try { Runtime.getRuntime().exec(cmd); } catch (Exception e) {}
+ }
+
+ protected void rm(String path) {
+ shell("rm -rf '" + path + "'");
+ }
+
+ protected void run(String cmd, String args, String input) {
+ shell("'" + getApplicationContext().getApplicationInfo().nativeLibraryDir + "/" + cmd + "' " + args + " '" + workDir() + "/" + input + "'");
+ }
+
+ protected boolean matches(String name, String[] wants) {
+ for (int i = 0; i < wants.length; ++i) if (name.equals(wants[i])) return true;
+ return false;
+ }
+
+ protected void unzip(File file, String[] wants, String dest) {
+ ZipFile zipFile;
+ try {
+ zipFile = new ZipFile(file, java.util.zip.ZipFile.OPEN_READ, Charset.forName("Windows-31J"));
+ } catch (Exception e) {
+ Log.d("pw.cloudef.rpg", e.toString());
+ return;
+ }
+
+ try {
+ Enumeration zipEntries = zipFile.entries();
+ while (zipEntries.hasMoreElements()) {
+ final ZipEntry entry = (ZipEntry)zipEntries.nextElement();
+ if (!matches(entry.getName(), wants)) continue;
+ InputStream input = zipFile.getInputStream(entry);
+ String base = entry.getName().split(".+?/(?=[^/]+$)")[1];
+ File out = new File(dest, base);
+ if (!out.getCanonicalPath().startsWith(dest))
+ throw new Exception("Zip path traversal detected");
+ out.mkdirs();
+ OutputStream output = new FileOutputStream(out);
+ byte[] buf = new byte[8 * 1024];
+ for (int read = 0; (read = input.read(buf)) != -1;) output.write(buf, 0, read);
+ output.close(); input.close();
+ break;
+ }
+ } catch (Exception e) {
+ Log.d("pw.cloudef.rpg", e.toString());
+ }
+
+ try { zipFile.close(); } catch (Exception e) {}
+ }
+
+ protected String rtpId() {
+ return getIntent().getExtras().getString("id");
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ try {
+ InputStream input = getContentResolver().openInputStream(getIntent().getData());
+ File file = new File(zipPath());
+ file.mkdirs();
+ OutputStream output = new FileOutputStream(file);
+ byte[] buf = new byte[8 * 1024];
+ for (int read = 0; (read = input.read(buf)) != -1;) output.write(buf, 0, read);
+ output.close(); input.close();
+ if (rtpId().equals("2000") || rtpId().equals("2003")) {
+ String prefix = (rtpId().equals("2003") ? "2003" : "");
+ // STEP 1 unzip
+ unzip(file, new String[]{prefix + "RTPセットアップ/" + rtpId() + "RTP.exe"}, workDir());
+ // STEP 2 cabextract
+ run("libcabextract.so", "-d '" + workDir() + "' -e CP932 ", rtpId() + "RTP.exe");
+ // STEP 3 unshield
+ run("libunshield.so", "-d '" + workDir() + "' -e CP932 x", "data1.cab");
+ run("libunshield.so", "-d '" + workDir() + "' -e CP932 x", "data2.cab");
+ } else if (rtpId().equals("XP")) {
+ // STEP 1 unzip
+ unzip(file, new String[]{"RPGXP_RTP103/Setup.exe"}, workDir());
+ // STEP 2 innoextract
+ run("libinnoextract.so", "-d '" + workDir() + "' -I app ", "Setup.exe");
+ // STEP 3 move to RTP dir
+ shell("mv '" + workDir() + "/app' '" + rtpDir() + "/XP'");
+ } else if (rtpId().equals("VX")) {
+ // STEP 1 unzip
+ unzip(file, new String[]{"RPGVX_RTP202/setup.exe"}, workDir());
+ // STEP 2 innoextract
+ run("libinnoextract.so", "-d '" + workDir() + "' -I app ", "setup.exe");
+ // STEP 3 move to RTP dir
+ shell("mv '" + workDir() + "/app' '" + rtpDir() + "/VX'");
+ } else if (rtpId().equals("VXAce")) {
+ // STEP 1 unzip
+ unzip(file, new String[]{"RPGVXAce_RTP100/Setup.exe", "RPGVXAce_RTP100/Setup-1.bin"}, workDir());
+ // STEP 2 innoextract
+ run("libinnoextract.so", "-d '" + workDir() + "' -I app ", "Setup.exe");
+ // STEP 3 move to RTP dir
+ shell("mv '" + workDir() + "/app' '" + rtpDir() + "/VXAce'");
+ } else {
+ throw new Exception("Unknown RTP");
+ }
+ } catch (Exception e) {
+ Log.d("pw.cloudef.rpg", e.toString());
+ }
+ // rm(workDir());
+ finishAndRemoveTask();
+ }
+}