MOOOOAAAAAAR KOTLIN
Signed-off-by: androidacy-user <opensource@androidacy.com>pull/27/head
parent
3096b89e28
commit
f3bd95b251
@ -1,36 +1,39 @@
|
|||||||
package com.fox2code.mmm;
|
package com.fox2code.mmm
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@Suppress("unused")
|
||||||
public enum Constants {
|
enum class Constants {
|
||||||
;
|
;
|
||||||
public static final int MAGISK_VER_CODE_FLAT_MODULES = 19000;
|
|
||||||
public static final int MAGISK_VER_CODE_UTIL_INSTALL = 20400;
|
companion object {
|
||||||
public static final int MAGISK_VER_CODE_PATH_SUPPORT = 21000;
|
const val MAGISK_VER_CODE_FLAT_MODULES = 19000
|
||||||
public static final int MAGISK_VER_CODE_INSTALL_COMMAND = 21200;
|
const val MAGISK_VER_CODE_UTIL_INSTALL = 20400
|
||||||
public static final int MAGISK_VER_CODE_MAGISK_ZYGOTE = 24000;
|
const val MAGISK_VER_CODE_PATH_SUPPORT = 21000
|
||||||
public static final String INTENT_INSTALL_INTERNAL =
|
const val MAGISK_VER_CODE_INSTALL_COMMAND = 21200
|
||||||
BuildConfig.APPLICATION_ID + ".intent.action.INSTALL_MODULE_INTERNAL";
|
const val MAGISK_VER_CODE_MAGISK_ZYGOTE = 24000
|
||||||
public static final String INTENT_ANDROIDACY_INTERNAL =
|
const val INTENT_INSTALL_INTERNAL =
|
||||||
BuildConfig.APPLICATION_ID + ".intent.action.OPEN_ANDROIDACY_INTERNAL";
|
BuildConfig.APPLICATION_ID + ".intent.action.INSTALL_MODULE_INTERNAL"
|
||||||
public static final String EXTRA_INSTALL_PATH = "extra_install_path";
|
const val INTENT_ANDROIDACY_INTERNAL =
|
||||||
public static final String EXTRA_INSTALL_NAME = "extra_install_name";
|
BuildConfig.APPLICATION_ID + ".intent.action.OPEN_ANDROIDACY_INTERNAL"
|
||||||
public static final String EXTRA_INSTALL_CONFIG = "extra_install_config";
|
const val EXTRA_INSTALL_PATH = "extra_install_path"
|
||||||
public static final String EXTRA_INSTALL_CHECKSUM = "extra_install_checksum";
|
const val EXTRA_INSTALL_NAME = "extra_install_name"
|
||||||
public static final String EXTRA_INSTALL_MMT_REBORN = "extra_install_mmt_reborn";
|
const val EXTRA_INSTALL_CONFIG = "extra_install_config"
|
||||||
public static final String EXTRA_INSTALL_NO_EXTENSIONS = "extra_install_no_extensions";
|
const val EXTRA_INSTALL_CHECKSUM = "extra_install_checksum"
|
||||||
public static final String EXTRA_INSTALL_TEST_ROOTLESS = "extra_install_test_rootless";
|
const val EXTRA_INSTALL_MMT_REBORN = "extra_install_mmt_reborn"
|
||||||
public static final String EXTRA_ANDROIDACY_COMPAT_LEVEL = "extra_androidacy_compat_level";
|
const val EXTRA_INSTALL_NO_EXTENSIONS = "extra_install_no_extensions"
|
||||||
public static final String EXTRA_ANDROIDACY_ALLOW_INSTALL = "extra_androidacy_allow_install";
|
const val EXTRA_INSTALL_TEST_ROOTLESS = "extra_install_test_rootless"
|
||||||
public static final String EXTRA_ANDROIDACY_ACTIONBAR_TITLE = "extra_androidacy_actionbar_title";
|
const val EXTRA_ANDROIDACY_COMPAT_LEVEL = "extra_androidacy_compat_level"
|
||||||
public static final String EXTRA_ANDROIDACY_ACTIONBAR_CONFIG = "extra_androidacy_actionbar_config";
|
const val EXTRA_ANDROIDACY_ALLOW_INSTALL = "extra_androidacy_allow_install"
|
||||||
public static final String EXTRA_MARKDOWN_URL = "extra_markdown_url";
|
const val EXTRA_ANDROIDACY_ACTIONBAR_TITLE = "extra_androidacy_actionbar_title"
|
||||||
public static final String EXTRA_MARKDOWN_TITLE = "extra_markdown_title";
|
const val EXTRA_ANDROIDACY_ACTIONBAR_CONFIG = "extra_androidacy_actionbar_config"
|
||||||
public static final String EXTRA_MARKDOWN_CONFIG = "extra_markdown_config";
|
const val EXTRA_MARKDOWN_URL = "extra_markdown_url"
|
||||||
public static final String EXTRA_MARKDOWN_CHANGE_BOOT = "extra_markdown_change_boot";
|
const val EXTRA_MARKDOWN_TITLE = "extra_markdown_title"
|
||||||
public static final String EXTRA_MARKDOWN_NEEDS_RAMDISK = "extra_markdown_needs_ramdisk";
|
const val EXTRA_MARKDOWN_CONFIG = "extra_markdown_config"
|
||||||
public static final String EXTRA_MARKDOWN_MIN_MAGISK = "extra_markdown_min_magisk";
|
const val EXTRA_MARKDOWN_CHANGE_BOOT = "extra_markdown_change_boot"
|
||||||
public static final String EXTRA_MARKDOWN_MIN_API = "extra_markdown_min_api";
|
const val EXTRA_MARKDOWN_NEEDS_RAMDISK = "extra_markdown_needs_ramdisk"
|
||||||
public static final String EXTRA_MARKDOWN_MAX_API = "extra_markdown_max_api";
|
const val EXTRA_MARKDOWN_MIN_MAGISK = "extra_markdown_min_magisk"
|
||||||
public static final String EXTRA_FADE_OUT = "extra_fade_out";
|
const val EXTRA_MARKDOWN_MIN_API = "extra_markdown_min_api"
|
||||||
public static final String EXTRA_FROM_MANAGER = "extra_from_manager";
|
const val EXTRA_MARKDOWN_MAX_API = "extra_markdown_max_api"
|
||||||
|
const val EXTRA_FADE_OUT = "extra_fade_out"
|
||||||
|
const val EXTRA_FROM_MANAGER = "extra_from_manager"
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,283 +1,303 @@
|
|||||||
package com.fox2code.mmm.utils.io;
|
package com.fox2code.mmm.utils.io
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context
|
||||||
import android.database.Cursor;
|
import android.net.Uri
|
||||||
import android.net.Uri;
|
import android.os.Build
|
||||||
import android.os.Build;
|
import android.provider.OpenableColumns
|
||||||
import android.provider.OpenableColumns;
|
import android.util.Log
|
||||||
import android.util.Log;
|
import com.fox2code.mmm.MainApplication
|
||||||
|
import com.topjohnwu.superuser.io.SuFile
|
||||||
|
import com.topjohnwu.superuser.io.SuFileInputStream
|
||||||
|
import com.topjohnwu.superuser.io.SuFileOutputStream
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipFile
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.util.Objects
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
/** @noinspection ResultOfMethodCallIgnored
|
||||||
import androidx.annotation.Nullable;
|
*/
|
||||||
|
enum class Files {
|
||||||
import com.fox2code.mmm.MainApplication;
|
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
|
||||||
import com.topjohnwu.superuser.io.SuFileInputStream;
|
|
||||||
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
import java.util.zip.ZipOutputStream;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/** @noinspection ResultOfMethodCallIgnored*/
|
|
||||||
public enum Files {
|
|
||||||
;
|
;
|
||||||
private static final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0;
|
|
||||||
|
companion object {
|
||||||
|
private val is64bit = Build.SUPPORTED_64_BIT_ABIS.isNotEmpty()
|
||||||
|
|
||||||
// stolen from https://stackoverflow.com/a/25005243
|
// stolen from https://stackoverflow.com/a/25005243
|
||||||
public static @NonNull String getFileName(Context context, Uri uri) {
|
@JvmStatic
|
||||||
String result = null;
|
fun getFileName(context: Context, uri: Uri): String {
|
||||||
if (Objects.equals(uri.getScheme(), "content")) {
|
var result: String? = null
|
||||||
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
if (uri.scheme == "content") {
|
||||||
|
context.contentResolver.query(uri, null, null, null, null).use { cursor ->
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
val index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
result = cursor.getString(index);
|
result = cursor.getString(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = uri.getPath();
|
result = uri.path
|
||||||
int cut = Objects.requireNonNull(result).lastIndexOf('/');
|
val cut = Objects.requireNonNull<String?>(result).lastIndexOf('/')
|
||||||
if (cut != -1) {
|
if (cut != -1) {
|
||||||
result = result.substring(cut + 1);
|
result = result!!.substring(cut + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result!!
|
||||||
}
|
}
|
||||||
|
|
||||||
// based on https://stackoverflow.com/a/63018108
|
// based on https://stackoverflow.com/a/63018108
|
||||||
public static @Nullable Long getFileSize(Context context, Uri uri) {
|
@JvmStatic
|
||||||
Long result = null;
|
fun getFileSize(context: Context, uri: Uri): Long? {
|
||||||
|
var result: Long? = null
|
||||||
try {
|
try {
|
||||||
String scheme = uri.getScheme();
|
val scheme = uri.scheme
|
||||||
if (Objects.equals(scheme, "content")) {
|
if (scheme == "content") {
|
||||||
Cursor returnCursor = context.getContentResolver().
|
val returnCursor = context.contentResolver.query(uri, null, null, null, null)
|
||||||
query(uri, null, null, null, null);
|
val sizeIndex =
|
||||||
int sizeIndex = Objects.requireNonNull(returnCursor).getColumnIndex(OpenableColumns.SIZE);
|
returnCursor?.getColumnIndex(OpenableColumns.SIZE)
|
||||||
returnCursor.moveToFirst();
|
returnCursor!!.moveToFirst()
|
||||||
|
val size = sizeIndex.let { it?.let { it1 -> returnCursor.getLong(it1) } }
|
||||||
long size = returnCursor.getLong(sizeIndex);
|
returnCursor.close()
|
||||||
returnCursor.close();
|
result = size
|
||||||
|
|
||||||
result = size;
|
|
||||||
}
|
}
|
||||||
if (Objects.equals(scheme, "file")) {
|
if (scheme == "file") {
|
||||||
result = new File(Objects.requireNonNull(uri.getPath())).length();
|
result = File(Objects.requireNonNull(uri.path)).length()
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (e: Exception) {
|
||||||
Timber.e(Log.getStackTraceString(e));
|
Timber.e(Log.getStackTraceString(e))
|
||||||
return result;
|
return null
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(File file, byte[] bytes) throws IOException {
|
@JvmStatic
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun write(file: File, bytes: ByteArray?) {
|
||||||
// make the dir if necessary
|
// make the dir if necessary
|
||||||
Objects.requireNonNull(file.getParentFile()).mkdirs();
|
Objects.requireNonNull(file.parentFile).mkdirs()
|
||||||
try (OutputStream outputStream = new FileOutputStream(file)) {
|
FileOutputStream(file).use { outputStream ->
|
||||||
outputStream.write(bytes);
|
outputStream.write(bytes)
|
||||||
outputStream.flush();
|
outputStream.flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] read(File file) throws IOException {
|
@JvmStatic
|
||||||
try (InputStream inputStream = new FileInputStream(file)) {
|
@Throws(IOException::class)
|
||||||
return readAllBytes(inputStream);
|
fun read(file: File?): ByteArray {
|
||||||
}
|
FileInputStream(file).use { inputStream -> return readAllBytes(inputStream) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeSU(File file, byte[] bytes) throws IOException {
|
@JvmStatic
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun writeSU(file: File, bytes: ByteArray?) {
|
||||||
// make the dir if necessary
|
// make the dir if necessary
|
||||||
Objects.requireNonNull(file.getParentFile()).mkdirs();
|
Objects.requireNonNull(file.parentFile).mkdirs()
|
||||||
try (OutputStream outputStream = SuFileOutputStream.open(file)) {
|
SuFileOutputStream.open(file).use { outputStream ->
|
||||||
outputStream.write(bytes);
|
outputStream.write(bytes)
|
||||||
outputStream.flush();
|
outputStream.flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] readSU(File file) throws IOException {
|
@JvmStatic
|
||||||
if (file.isFile() && file.canRead()) {
|
@Throws(IOException::class)
|
||||||
|
fun readSU(file: File): ByteArray {
|
||||||
|
if (file.isFile && file.canRead()) {
|
||||||
try { // Read as app if su not required
|
try { // Read as app if su not required
|
||||||
return read(file);
|
return read(file)
|
||||||
} catch (IOException ignored) {
|
} catch (ignored: IOException) {
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try (InputStream inputStream = SuFileInputStream.open(file)) {
|
|
||||||
return readAllBytes(inputStream);
|
|
||||||
}
|
}
|
||||||
|
SuFileInputStream.open(file).use { inputStream -> return readAllBytes(inputStream) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean existsSU(File file) {
|
@JvmStatic
|
||||||
return file.exists() || new SuFile(file.getAbsolutePath()).exists();
|
fun existsSU(file: File): Boolean {
|
||||||
|
return file.exists() || SuFile(file.absolutePath).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copy(InputStream inputStream, OutputStream outputStream) throws IOException {
|
@JvmStatic
|
||||||
int nRead;
|
@Throws(IOException::class)
|
||||||
byte[] data = new byte[16384];
|
fun copy(inputStream: InputStream, outputStream: OutputStream) {
|
||||||
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
|
var nRead: Int
|
||||||
outputStream.write(data, 0, nRead);
|
val data = ByteArray(16384)
|
||||||
|
while (inputStream.read(data, 0, data.size).also { nRead = it } != -1) {
|
||||||
|
outputStream.write(data, 0, nRead)
|
||||||
}
|
}
|
||||||
outputStream.flush();
|
outputStream.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void closeSilently(Closeable closeable) {
|
@JvmStatic
|
||||||
|
fun closeSilently(closeable: Closeable?) {
|
||||||
try {
|
try {
|
||||||
if (closeable != null) closeable.close();
|
closeable?.close()
|
||||||
} catch (IOException ignored) {
|
} catch (ignored: IOException) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteArrayOutputStream makeBuffer(long capacity) {
|
@JvmStatic
|
||||||
|
fun makeBuffer(capacity: Long): ByteArrayOutputStream {
|
||||||
// Cap buffer to 1 Gib (or 512 Mib for 32bit) to avoid memory errors
|
// Cap buffer to 1 Gib (or 512 Mib for 32bit) to avoid memory errors
|
||||||
return Files.makeBuffer((int) Math.min(capacity, is64bit ? 0x40000000 : 0x20000000));
|
return makeBuffer(
|
||||||
|
capacity.coerceAtMost((if (is64bit) 0x40000000 else 0x20000000).toLong()).toInt()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteArrayOutputStream makeBuffer(int capacity) {
|
private fun makeBuffer(capacity: Int): ByteArrayOutputStream {
|
||||||
return new ByteArrayOutputStream(Math.max(0x20, capacity)) {
|
return object : ByteArrayOutputStream(0x20.coerceAtLeast(capacity)) {
|
||||||
@NonNull
|
override fun toByteArray(): ByteArray {
|
||||||
@Override
|
return if (buf.size == count) buf else super.toByteArray()
|
||||||
public byte[] toByteArray() {
|
}
|
||||||
return this.buf.length == this.count ?
|
|
||||||
this.buf : super.toByteArray();
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] readAllBytes(InputStream inputStream) throws IOException {
|
@JvmStatic
|
||||||
ByteArrayOutputStream buffer = Files.makeBuffer(inputStream.available());
|
@Throws(IOException::class)
|
||||||
copy(inputStream, buffer);
|
fun readAllBytes(inputStream: InputStream): ByteArray {
|
||||||
return buffer.toByteArray();
|
val buffer = makeBuffer(inputStream.available())
|
||||||
|
copy(inputStream, buffer)
|
||||||
|
return buffer.toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fixJavaZipHax(byte[] bytes) {
|
@JvmStatic
|
||||||
if (bytes.length > 8 && bytes[0x6] == 0x0 && bytes[0x7] == 0x0 && bytes[0x8] == 0x8)
|
fun fixJavaZipHax(bytes: ByteArray) {
|
||||||
bytes[0x7] = 0x8; // Known hax to prevent java zip file read
|
if (bytes.size > 8 && bytes[0x6].toInt() == 0x0 && bytes[0x7].toInt() == 0x0 && bytes[0x8].toInt() == 0x8) bytes[0x7] =
|
||||||
|
0x8 // Known hax to prevent java zip file read
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void patchModuleSimple(byte[] bytes, OutputStream outputStream) throws IOException {
|
@JvmStatic
|
||||||
fixJavaZipHax(bytes);
|
@Throws(IOException::class)
|
||||||
patchModuleSimple(new ByteArrayInputStream(bytes), outputStream);
|
fun patchModuleSimple(bytes: ByteArray, outputStream: OutputStream?) {
|
||||||
|
fixJavaZipHax(bytes)
|
||||||
|
patchModuleSimple(ByteArrayInputStream(bytes), outputStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void patchModuleSimple(InputStream inputStream, OutputStream outputStream) throws IOException {
|
@Throws(IOException::class)
|
||||||
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
|
fun patchModuleSimple(inputStream: InputStream?, outputStream: OutputStream?) {
|
||||||
ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
|
val zipInputStream = ZipInputStream(inputStream)
|
||||||
int nRead;
|
val zipOutputStream = ZipOutputStream(outputStream)
|
||||||
byte[] data = new byte[16384];
|
var nRead: Int
|
||||||
ZipEntry zipEntry;
|
val data = ByteArray(16384)
|
||||||
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
var zipEntry: ZipEntry
|
||||||
String name = zipEntry.getName();
|
while (zipInputStream.nextEntry.also { zipEntry = it } != null) {
|
||||||
int i = name.indexOf('/', 1);
|
val name = zipEntry.name
|
||||||
if (i == -1) continue;
|
val i = name.indexOf('/', 1)
|
||||||
String newName = name.substring(i + 1);
|
if (i == -1) continue
|
||||||
if (newName.startsWith(".git")) continue; // Skip metadata
|
val newName = name.substring(i + 1)
|
||||||
zipOutputStream.putNextEntry(new ZipEntry(newName));
|
if (newName.startsWith(".git")) continue // Skip metadata
|
||||||
while ((nRead = zipInputStream.read(data, 0, data.length)) != -1) {
|
zipOutputStream.putNextEntry(ZipEntry(newName))
|
||||||
zipOutputStream.write(data, 0, nRead);
|
while (zipInputStream.read(data, 0, data.size).also { nRead = it } != -1) {
|
||||||
}
|
zipOutputStream.write(data, 0, nRead)
|
||||||
zipOutputStream.flush();
|
}
|
||||||
zipOutputStream.closeEntry();
|
zipOutputStream.flush()
|
||||||
zipInputStream.closeEntry();
|
zipOutputStream.closeEntry()
|
||||||
}
|
zipInputStream.closeEntry()
|
||||||
zipOutputStream.finish();
|
}
|
||||||
zipOutputStream.flush();
|
zipOutputStream.finish()
|
||||||
zipOutputStream.close();
|
zipOutputStream.flush()
|
||||||
zipInputStream.close();
|
zipOutputStream.close()
|
||||||
|
zipInputStream.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void fixSourceArchiveShit(byte[] rawModule) {
|
@JvmStatic
|
||||||
|
fun fixSourceArchiveShit(rawModule: ByteArray?) {
|
||||||
// unzip the module, check if it has just one folder within. if so, switch to the folder and zip up contents, and replace the original file with that
|
// unzip the module, check if it has just one folder within. if so, switch to the folder and zip up contents, and replace the original file with that
|
||||||
try {
|
try {
|
||||||
File tempDir = new File(MainApplication.getINSTANCE().getCacheDir(), "temp");
|
val tempDir = File(MainApplication.getINSTANCE().cacheDir, "temp")
|
||||||
if (tempDir.exists()) {
|
if (tempDir.exists()) {
|
||||||
FileUtils.deleteDirectory(tempDir);
|
FileUtils.deleteDirectory(tempDir)
|
||||||
}
|
}
|
||||||
if (!tempDir.mkdirs()) {
|
if (!tempDir.mkdirs()) {
|
||||||
throw new IOException("Unable to create temp dir");
|
throw IOException("Unable to create temp dir")
|
||||||
}
|
}
|
||||||
File tempFile = new File(tempDir, "module.zip");
|
val tempFile = File(tempDir, "module.zip")
|
||||||
Files.write(tempFile, rawModule);
|
write(tempFile, rawModule)
|
||||||
File tempUnzipDir = new File(tempDir, "unzip");
|
val tempUnzipDir = File(tempDir, "unzip")
|
||||||
if (!tempUnzipDir.mkdirs()) {
|
if (!tempUnzipDir.mkdirs()) {
|
||||||
throw new IOException("Unable to create temp unzip dir");
|
throw IOException("Unable to create temp unzip dir")
|
||||||
}
|
}
|
||||||
// unzip
|
// unzip
|
||||||
Timber.d("Unzipping module to %s", tempUnzipDir.getAbsolutePath());
|
Timber.d("Unzipping module to %s", tempUnzipDir.absolutePath)
|
||||||
try (ZipFile zipFile = new ZipFile(tempFile)) {
|
try {
|
||||||
Enumeration<ZipArchiveEntry> files = zipFile.getEntries();
|
ZipFile(tempFile).use { zipFile ->
|
||||||
|
var files = zipFile.entries
|
||||||
// check if there is only one folder in the top level
|
// check if there is only one folder in the top level
|
||||||
int folderCount = 0;
|
var folderCount = 0
|
||||||
while (files.hasMoreElements()) {
|
while (files.hasMoreElements()) {
|
||||||
ZipArchiveEntry entry = files.nextElement();
|
val entry = files.nextElement()
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory) {
|
||||||
folderCount++;
|
folderCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (folderCount == 1) {
|
if (folderCount == 1) {
|
||||||
files = zipFile.getEntries();
|
files = zipFile.entries
|
||||||
while (files.hasMoreElements()) {
|
while (files.hasMoreElements()) {
|
||||||
ZipArchiveEntry entry = files.nextElement();
|
val entry = files.nextElement()
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory) {
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
File file = new File(tempUnzipDir, entry.getName());
|
val file = File(tempUnzipDir, entry.name)
|
||||||
if (!Objects.requireNonNull(file.getParentFile()).exists()) {
|
if (!Objects.requireNonNull(file.parentFile).exists()) {
|
||||||
if (!file.getParentFile().mkdirs()) {
|
if (!file.parentFile?.mkdirs()!!) {
|
||||||
throw new IOException("Unable to create parent dir");
|
throw IOException("Unable to create parent dir")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(file)) {
|
ZipArchiveOutputStream(file).use { zipArchiveOutputStream ->
|
||||||
zipArchiveOutputStream.putArchiveEntry(entry);
|
zipArchiveOutputStream.putArchiveEntry(entry)
|
||||||
try (InputStream inputStream = zipFile.getInputStream(entry)) {
|
zipFile.getInputStream(entry).use { inputStream ->
|
||||||
copy(inputStream, zipArchiveOutputStream);
|
copy(
|
||||||
|
inputStream,
|
||||||
|
zipArchiveOutputStream
|
||||||
|
)
|
||||||
}
|
}
|
||||||
zipArchiveOutputStream.closeArchiveEntry();
|
zipArchiveOutputStream.closeArchiveEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// zip up the contents of the folder but not the folder itself
|
// zip up the contents of the folder but not the folder itself
|
||||||
File[] filesInFolder = Objects.requireNonNull(tempUnzipDir.listFiles());
|
val filesInFolder = Objects.requireNonNull(tempUnzipDir.listFiles())
|
||||||
// create a new zip file
|
// create a new zip file
|
||||||
try (ZipArchiveOutputStream archive = new ZipArchiveOutputStream(new FileOutputStream("new.zip"))) {
|
try {
|
||||||
for (File files2 : filesInFolder) {
|
ZipArchiveOutputStream(FileOutputStream("new.zip")).use { archive ->
|
||||||
|
for (files2 in filesInFolder) {
|
||||||
// create a new ZipArchiveEntry and add it to the ZipArchiveOutputStream
|
// create a new ZipArchiveEntry and add it to the ZipArchiveOutputStream
|
||||||
ZipArchiveEntry entry = new ZipArchiveEntry(files2, files2.getName());
|
val entry = ZipArchiveEntry(files2, files2.name)
|
||||||
archive.putArchiveEntry(entry);
|
archive.putArchiveEntry(entry)
|
||||||
try (InputStream input = new FileInputStream(files2)) {
|
FileInputStream(files2).use { input ->
|
||||||
copy(input, archive);
|
copy(
|
||||||
|
input,
|
||||||
|
archive
|
||||||
|
)
|
||||||
|
}
|
||||||
|
archive.closeArchiveEntry()
|
||||||
}
|
}
|
||||||
archive.closeArchiveEntry();
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (e: IOException) {
|
||||||
Timber.e(e, "Unable to zip up module");
|
Timber.e(e, "Unable to zip up module")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.d("Module does not have a single folder in the top level, skipping");
|
Timber.d("Module does not have a single folder in the top level, skipping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Timber.e(e, "Unable to unzip module")
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (e: IOException) {
|
||||||
Timber.e(e, "Unable to unzip module");
|
Timber.e(e, "Unable to create temp dir")
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
Timber.e(e, "Unable to create temp dir");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue