You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
6.7 KiB
Java
192 lines
6.7 KiB
Java
package com.fox2code.mmm.utils.io;
|
|
|
|
import android.content.Context;
|
|
import android.database.Cursor;
|
|
import android.net.Uri;
|
|
import android.os.Build;
|
|
import android.provider.OpenableColumns;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.topjohnwu.superuser.io.SuFile;
|
|
import com.topjohnwu.superuser.io.SuFileInputStream;
|
|
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
|
|
|
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.zip.ZipEntry;
|
|
import java.util.zip.ZipInputStream;
|
|
import java.util.zip.ZipOutputStream;
|
|
|
|
import timber.log.Timber;
|
|
|
|
public enum Files {
|
|
;
|
|
private static final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0;
|
|
|
|
// stolen from https://stackoverflow.com/a/25005243
|
|
public static @NonNull String getFileName(Context context, Uri uri) {
|
|
String result = null;
|
|
if (uri.getScheme().equals("content")) {
|
|
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
|
if (cursor != null && cursor.moveToFirst()) {
|
|
int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
|
if (index != -1) {
|
|
result = cursor.getString(index);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (result == null) {
|
|
result = uri.getPath();
|
|
int cut = result.lastIndexOf('/');
|
|
if (cut != -1) {
|
|
result = result.substring(cut + 1);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// based on https://stackoverflow.com/a/63018108
|
|
public static @Nullable Long getFileSize(Context context, Uri uri) {
|
|
Long result = null;
|
|
try {
|
|
String scheme = uri.getScheme();
|
|
if (scheme.equals("content")) {
|
|
Cursor returnCursor = context.getContentResolver().
|
|
query(uri, null, null, null, null);
|
|
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
|
|
returnCursor.moveToFirst();
|
|
|
|
long size = returnCursor.getLong(sizeIndex);
|
|
returnCursor.close();
|
|
|
|
result = size;
|
|
}
|
|
if (scheme.equals("file")) {
|
|
result = new File(uri.getPath()).length();
|
|
}
|
|
} catch (Exception e) {
|
|
Timber.e(Log.getStackTraceString(e));
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static void write(File file, byte[] bytes) throws IOException {
|
|
try (OutputStream outputStream = new FileOutputStream(file)) {
|
|
outputStream.write(bytes);
|
|
outputStream.flush();
|
|
}
|
|
}
|
|
|
|
public static byte[] read(File file) throws IOException {
|
|
try (InputStream inputStream = new FileInputStream(file)) {
|
|
return readAllBytes(inputStream);
|
|
}
|
|
}
|
|
|
|
public static void writeSU(File file, byte[] bytes) throws IOException {
|
|
try (OutputStream outputStream = SuFileOutputStream.open(file)) {
|
|
outputStream.write(bytes);
|
|
outputStream.flush();
|
|
}
|
|
}
|
|
|
|
public static byte[] readSU(File file) throws IOException {
|
|
if (file.isFile() && file.canRead()) {
|
|
try { // Read as app if su not required
|
|
return read(file);
|
|
} catch (IOException ignored) {}
|
|
}
|
|
try (InputStream inputStream = SuFileInputStream.open(file)) {
|
|
return readAllBytes(inputStream);
|
|
}
|
|
}
|
|
|
|
public static boolean existsSU(File file) {
|
|
return file.exists() || new SuFile(file.getAbsolutePath()).exists();
|
|
}
|
|
|
|
public static void copy(InputStream inputStream,OutputStream outputStream) throws IOException {
|
|
int nRead;
|
|
byte[] data = new byte[16384];
|
|
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
|
|
outputStream.write(data, 0, nRead);
|
|
}
|
|
outputStream.flush();
|
|
}
|
|
|
|
public static void closeSilently(Closeable closeable) {
|
|
try {
|
|
if (closeable != null) closeable.close();
|
|
} catch (IOException ignored) {}
|
|
}
|
|
|
|
public static ByteArrayOutputStream makeBuffer(long capacity) {
|
|
// Cap buffer to 1 Gib (or 512 Mib for 32bit) to avoid memory errors
|
|
return Files.makeBuffer((int) Math.min(capacity, is64bit ? 0x40000000 : 0x20000000));
|
|
}
|
|
|
|
public static ByteArrayOutputStream makeBuffer(int capacity) {
|
|
return new ByteArrayOutputStream(Math.max(0x20, capacity)) {
|
|
@NonNull
|
|
@Override
|
|
public byte[] toByteArray() {
|
|
return this.buf.length == this.count ?
|
|
this.buf : super.toByteArray();
|
|
}
|
|
};
|
|
}
|
|
|
|
public static byte[] readAllBytes(InputStream inputStream) throws IOException {
|
|
ByteArrayOutputStream buffer = Files.makeBuffer(inputStream.available());
|
|
copy(inputStream, buffer);
|
|
return buffer.toByteArray();
|
|
}
|
|
|
|
public static void fixJavaZipHax(byte[] bytes) {
|
|
if (bytes.length > 8 && bytes[0x6] == 0x0 && bytes[0x7] == 0x0 && bytes[0x8] == 0x8)
|
|
bytes[0x7] = 0x8; // Known hax to prevent java zip file read
|
|
}
|
|
|
|
public static void patchModuleSimple(byte[] bytes,OutputStream outputStream) throws IOException {
|
|
fixJavaZipHax(bytes); patchModuleSimple(new ByteArrayInputStream(bytes), outputStream);
|
|
}
|
|
|
|
public static void patchModuleSimple(InputStream inputStream,OutputStream outputStream) throws IOException {
|
|
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
|
|
ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
|
|
int nRead;
|
|
byte[] data = new byte[16384];
|
|
ZipEntry zipEntry;
|
|
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
|
String name = zipEntry.getName();
|
|
int i = name.indexOf('/', 1);
|
|
if (i == -1) continue;
|
|
String newName = name.substring(i + 1);
|
|
if (newName.startsWith(".git")) continue; // Skip metadata
|
|
zipOutputStream.putNextEntry(new ZipEntry(newName));
|
|
while ((nRead = zipInputStream.read(data, 0, data.length)) != -1) {
|
|
zipOutputStream.write(data, 0, nRead);
|
|
}
|
|
zipOutputStream.flush();
|
|
zipOutputStream.closeEntry();
|
|
zipInputStream.closeEntry();
|
|
}
|
|
zipOutputStream.finish();
|
|
zipOutputStream.flush();
|
|
zipOutputStream.close();
|
|
zipInputStream.close();
|
|
}
|
|
}
|