Skip to content

Commit

Permalink
ISO9660 and ZStandard archive support
Browse files Browse the repository at this point in the history
Fixes #2988
Fixes #3318
  • Loading branch information
TranceLove committed Oct 20, 2023
1 parent 6783e4d commit 07a9c7b
Show file tree
Hide file tree
Showing 36 changed files with 747 additions and 38 deletions.
10 changes: 9 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ dependencies {
testImplementation "org.jsoup:jsoup:$jsoupVersion"
testImplementation "androidx.room:room-migration:$roomVersion"
testImplementation "io.mockk:mockk:$mockkVersion"
testImplementation "com.github.luben:zstd-jni:${zstdJniVersion}"
kaptTest "com.google.auto.service:auto-service:1.0-rc4"

androidTestImplementation "junit:junit:$junitVersion"//tests the app logic
Expand All @@ -170,6 +171,14 @@ dependencies {

playImplementation "com.github.junrar:junrar:$junrarVersion"

implementation "com.github.luben:zstd-jni:${zstdJniVersion}@aar"
implementation 'com.github.stephenc.java-iso-tools:loopy-core:1.2.2'

implementation "com.github.luben:zstd-jni:${zstdJniVersion}@aar"
implementation ("com.github.stephenc.java-iso-tools:loopy-core:1.2.2") {
transitive = false
}

implementation "com.afollestad.material-dialogs:core:$materialDialogsVersion"
implementation "com.afollestad.material-dialogs:commons:$materialDialogsVersion"

Expand Down Expand Up @@ -255,7 +264,6 @@ dependencies {
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module("commons-logging:commons-logging-api:1.1") with module("commons-logging:commons-logging:1.1.1")
substitute module("com.android.support:support-annotations:27.1.1") with module("com.android.support:support-annotations:27.0.2")
// These two lines are added to prevent possible class clashes between awaitility (which uses hamcrest 2.1) and junit (which uses hamcrest 1.3).
substitute module('org.hamcrest:hamcrest-core:1.3') with module("org.hamcrest:hamcrest:2.1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ import org.apache.commons.compress.archivers.ArchiveEntry
import org.apache.commons.compress.archivers.ArchiveException
import org.apache.commons.compress.archivers.ArchiveInputStream
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.lang.ref.WeakReference
import java.util.*

abstract class AbstractCommonsArchiveHelperCallable(
context: Context,
Expand All @@ -54,7 +52,7 @@ abstract class AbstractCommonsArchiveHelperCallable(
@Throws(ArchiveException::class)
@Suppress("LabeledExpression")
public override fun addElements(elements: ArrayList<CompressedObjectParcelable>) {
try {
runCatching {
createFrom(FileInputStream(filePath)).use { tarInputStream ->
var entry: ArchiveEntry?
while (tarInputStream.nextEntry.also { entry = it } != null) {
Expand Down Expand Up @@ -90,8 +88,9 @@ abstract class AbstractCommonsArchiveHelperCallable(
}
}
}
} catch (e: IOException) {
throw ArchiveException(String.format("Tarball archive %s is corrupt", filePath), e)
}.onFailure {
logger.error("Error enumerating archive entries", it)
throw ArchiveException(String.format("Tarball archive %s is corrupt", filePath))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ package com.amaze.filemanager.asynchronous.asynctasks.compress
import androidx.annotation.WorkerThread
import com.amaze.filemanager.adapters.data.CompressedObjectParcelable
import org.apache.commons.compress.archivers.ArchiveException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.*
import java.util.concurrent.Callable

Expand All @@ -31,6 +33,8 @@ abstract class CompressedHelperCallable internal constructor(
) :
Callable<ArrayList<CompressedObjectParcelable>> {

protected val logger: Logger = LoggerFactory.getLogger(javaClass)

@WorkerThread
@Throws(ArchiveException::class)
override fun call(): ArrayList<CompressedObjectParcelable> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2014-2023 Arpit Khurana <[email protected]>, Vishal Nehra <[email protected]>,
* Emmanuel Messulam<[email protected]>, Raymond Lai <airwave209gt at gmail.com> and Contributors.
*
* This file is part of Amaze File Manager.
*
* Amaze File Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.amaze.filemanager.asynchronous.asynctasks.compress

import com.amaze.filemanager.adapters.data.CompressedObjectParcelable
import com.amaze.filemanager.filesystem.compressed.CompressedHelper
import com.amaze.filemanager.filesystem.compressed.extractcontents.Extractor
import net.didion.loopy.FileEntry
import net.didion.loopy.iso9660.ISO9660FileEntry
import net.didion.loopy.iso9660.ISO9660FileSystem
import java.io.File
import java.io.IOException
import java.lang.reflect.Field

class Iso9660HelperCallable(
private val filePath: String,
private val relativePath: String,
createBackItem: Boolean
) : CompressedHelperCallable(createBackItem) {

private val SLASH = Regex("/")

// Hack. ISO9660FileEntry doesn't have getter for parentPath, we need to read it on our own
private val parentPathField: Field =
ISO9660FileEntry::class.java.getDeclaredField("parentPath").also {
it.isAccessible = true
}

override fun addElements(elements: ArrayList<CompressedObjectParcelable>) {
val isoFile = ISO9660FileSystem(File(filePath), true)

val fileEntries: List<FileEntry> = runCatching {
isoFile.entries?.let { isoFileEntries ->
isoFileEntries.runCatching {
isoFileEntries.toList().partition { entry ->
CompressedHelper.isEntryPathValid((entry as FileEntry).path)
}.let { pair ->
pair.first as List<FileEntry>
}
}.onFailure {
return
}.getOrThrow()
} ?: throw IOException("Empty archive or file is corrupt")
}.onFailure {
throw Extractor.BadArchiveNotice(it)
}.getOrThrow().filter {
it.name != "."
}

val slashCount = if (relativePath == "") {
0
} else {
SLASH.findAll("$relativePath/").count()
}

fileEntries.filter {
val parentPath = parentPathField.get(it)?.toString() ?: ""
(
if (slashCount == 0) {
parentPath == ""
} else {
parentPath == "$relativePath/"
}
)
}.forEach { entry ->
elements.add(
CompressedObjectParcelable(
entry.name,
entry.lastModifiedTime,
entry.size.toLong(),
entry.isDirectory
)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import org.apache.commons.compress.PasswordRequiredException
import org.apache.commons.compress.archivers.ArchiveException
import java.io.File
import java.io.IOException
import java.lang.UnsupportedOperationException

class SevenZipHelperCallable(
private val filePath: String,
Expand Down Expand Up @@ -58,7 +57,7 @@ class SevenZipHelperCallable(
)
val isInRelativeDir = (
name.contains(CompressedHelper.SEPARATOR) &&
name.substring(0, name.lastIndexOf(CompressedHelper.SEPARATOR))
name.substringBeforeLast(CompressedHelper.SEPARATOR)
== relativePath
)
if (isInBaseDir || isInRelativeDir) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2014-2021 Arpit Khurana <[email protected]>, Vishal Nehra <[email protected]>,
* Emmanuel Messulam<[email protected]>, Raymond Lai <airwave209gt at gmail.com> and Contributors.
*
* This file is part of Amaze File Manager.
*
* Amaze File Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.amaze.filemanager.asynchronous.asynctasks.compress

import android.content.Context
import org.apache.commons.compress.compressors.CompressorInputStream
import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream

class TarZstHelperCallable(
context: Context,
filePath: String,
relativePath: String,
goBack: Boolean
) :
AbstractCompressedTarArchiveHelperCallable(context, filePath, relativePath, goBack) {

override fun getCompressorInputStreamClass(): Class<out CompressorInputStream> =
ZstdCompressorInputStream::class.java
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.amaze.filemanager.filesystem.compressed.extractcontents.Extractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.Bzip2Extractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.GzipExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.Iso9660Extractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.LzmaExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.RarExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.SevenZipExtractor;
Expand All @@ -38,16 +39,20 @@
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.TarGzExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.TarLzmaExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.TarXzExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.TarZstExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.XzExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.ZipExtractor;
import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.ZstdExtractor;
import com.amaze.filemanager.filesystem.compressed.showcontents.Decompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.Iso9660Decompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.RarDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.SevenZipDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.TarBzip2Decompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.TarDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.TarGzDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.TarLzmaDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.TarXzDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.TarZstDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.UnknownCompressedFileDecompressor;
import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.ZipDecompressor;
import com.amaze.filemanager.utils.Utils;
Expand Down Expand Up @@ -80,10 +85,14 @@ public abstract class CompressedHelper {
public static final String fileExtension7zip = "7z";
public static final String fileExtensionTarLzma = "tar.lzma";
public static final String fileExtensionTarXz = "tar.xz";
public static final String fileExtensionTarZst = "tar.zst";
public static final String fileExtensionXz = "xz";
public static final String fileExtensionLzma = "lzma";
public static final String fileExtensionGz = "gz";
public static final String fileExtensionBzip2 = "bz2";
public static final String fileExtensionZst = "zst";

public static final String fileExtensionIso = "iso";

private static final String TAG = CompressedHelper.class.getSimpleName();

Expand Down Expand Up @@ -114,6 +123,9 @@ public static Extractor getExtractorInstance(
} else if (isLzippedTar(type)) {
extractor =
new TarLzmaExtractor(context, file.getPath(), outputPath, listener, updatePosition);
} else if (isZstdTar(type)) {
extractor =
new TarZstExtractor(context, file.getPath(), outputPath, listener, updatePosition);
} else if (is7zip(type)) {
extractor =
new SevenZipExtractor(context, file.getPath(), outputPath, listener, updatePosition);
Expand All @@ -125,6 +137,11 @@ public static Extractor getExtractorInstance(
extractor = new GzipExtractor(context, file.getPath(), outputPath, listener, updatePosition);
} else if (isBzip2(type)) {
extractor = new Bzip2Extractor(context, file.getPath(), outputPath, listener, updatePosition);
} else if (isZst(type)) {
extractor = new ZstdExtractor(context, file.getPath(), outputPath, listener, updatePosition);
} else if (isIso(type)) {
extractor =
new Iso9660Extractor(context, file.getPath(), outputPath, listener, updatePosition);
} else {
if (BuildConfig.DEBUG) {
throw new IllegalArgumentException("The compressed file has no way of opening it: " + file);
Expand Down Expand Up @@ -156,9 +173,13 @@ public static Decompressor getCompressorInstance(@NonNull Context context, @NonN
decompressor = new TarXzDecompressor(context);
} else if (isLzippedTar(type)) {
decompressor = new TarLzmaDecompressor(context);
} else if (isZstdTar(type)) {
decompressor = new TarZstDecompressor(context);
} else if (is7zip(type)) {
decompressor = new SevenZipDecompressor(context);
} else if (isXz(type) || isLzma(type) || isGzip(type) || isBzip2(type)) {
} else if (isIso(type)) {
decompressor = new Iso9660Decompressor(context);
} else if (isXz(type) || isLzma(type) || isGzip(type) || isBzip2(type) || isZst(type)) {
// These 4 types are only compressing one single file.
// Hence invoking this UnknownCompressedFileDecompressor which only returns the filename
// without the compression extension
Expand Down Expand Up @@ -190,10 +211,13 @@ public static boolean isFileExtractable(String path) {
|| isBzippedTar(type)
|| isXzippedTar(type)
|| isLzippedTar(type)
|| isZstdTar(type)
|| isBzip2(type)
|| isGzip(type)
|| isLzma(type)
|| isXz(type);
|| isXz(type)
|| isZst(type)
|| isIso(type);
}

/**
Expand All @@ -214,12 +238,15 @@ public static String getFileName(String compressedName) {
|| isGzip(compressedName)
|| isBzip2(compressedName)
|| isLzma(compressedName)
|| isXz(compressedName)) {
|| isXz(compressedName)
|| isZst(compressedName)
|| isIso(compressedName)) {
return compressedName.substring(0, compressedName.lastIndexOf("."));
} else if (isGzippedTar(compressedName)
|| isXzippedTar(compressedName)
|| isLzippedTar(compressedName)
|| isBzippedTar(compressedName)) {
|| isBzippedTar(compressedName)
|| isZstdTar(compressedName)) {
return compressedName.substring(0, Utils.nthToLastCharIndex(2, compressedName, '.'));
} else {
return compressedName;
Expand Down Expand Up @@ -265,6 +292,10 @@ private static boolean isLzippedTar(String type) {
return type.endsWith(fileExtensionTarLzma);
}

private static boolean isZstdTar(String type) {
return type.endsWith(fileExtensionTarZst);
}

private static boolean isXz(String type) {
return type.endsWith(fileExtensionXz) && !isXzippedTar(type);
}
Expand All @@ -281,6 +312,14 @@ private static boolean isBzip2(String type) {
return type.endsWith(fileExtensionBzip2) && !isBzippedTar(type);
}

private static boolean isZst(String type) {
return type.endsWith(fileExtensionZst) && !isZstdTar(type);
}

private static boolean isIso(String type) {
return type.endsWith(fileExtensionIso);
}

private static String getExtension(String path) {
return path.substring(path.indexOf('.') + 1).toLowerCase();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,9 @@ public static class BadArchiveNotice extends IOException {
public BadArchiveNotice(@NonNull Throwable reason) {
super(reason);
}

public BadArchiveNotice(@NonNull String reason) {
super(reason);
}
}
}
Loading

0 comments on commit 07a9c7b

Please sign in to comment.