diff --git a/app/build.gradle b/app/build.gradle index b7d0ce2d23..4721491ff4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -147,6 +147,7 @@ dependencies { implementation libs.androidX.multidex //Multiple dex files implementation libs.room.runtime implementation libs.room.rxjava2 + testImplementation "com.github.luben:zstd-jni:1.5.6-4" ksp libs.room.compiler ksp libs.androidX.annotation @@ -189,6 +190,11 @@ dependencies { implementation libs.commons.compress + implementation "com.github.luben:zstd-jni:1.5.6-4@aar" + implementation ("com.github.stephenc.java-iso-tools:loopy-core:1.2.2") { + transitive = false + } + implementation libs.materialdialogs.core implementation libs.materialdialogs.commons diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCommonsArchiveHelperCallable.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCommonsArchiveHelperCallable.kt index 2aee2624aa..4381c4e198 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCommonsArchiveHelperCallable.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCommonsArchiveHelperCallable.kt @@ -29,7 +29,6 @@ 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 @@ -52,7 +51,7 @@ abstract class AbstractCommonsArchiveHelperCallable( @Throws(ArchiveException::class) @Suppress("LabeledExpression") public override fun addElements(elements: ArrayList) { - try { + runCatching { createFrom(FileInputStream(filePath)).use { tarInputStream -> var entry: ArchiveEntry? while (tarInputStream.nextEntry.also { entry = it } != null) { @@ -88,8 +87,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)) } } } diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/Iso9660HelperCallable.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/Iso9660HelperCallable.kt new file mode 100644 index 0000000000..87d984521b --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/Iso9660HelperCallable.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014-2023 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +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) { + val isoFile = ISO9660FileSystem(File(filePath), true) + + val fileEntries: List = + runCatching { + isoFile.entries?.let { isoFileEntries -> + isoFileEntries.runCatching { + isoFileEntries.toList().partition { entry -> + CompressedHelper.isEntryPathValid((entry as FileEntry).path) + }.let { pair -> + pair.first as List + } + }.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, + ), + ) + } + } +} diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarZstHelperCallable.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarZstHelperCallable.kt new file mode 100644 index 0000000000..4cc7dab978 --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarZstHelperCallable.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014-2021 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +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 = ZstdCompressorInputStream::class.java +} diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/CompressedHelper.java b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/CompressedHelper.java index 5d36ad0875..8ffb4d8442 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/CompressedHelper.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/CompressedHelper.java @@ -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; @@ -38,9 +39,12 @@ 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; @@ -48,6 +52,7 @@ 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; @@ -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(); @@ -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); @@ -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); @@ -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 @@ -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); } /** @@ -216,12 +240,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 (hasFileName && isGzippedTar(compressedName) || isXzippedTar(compressedName) || isLzippedTar(compressedName) - || isBzippedTar(compressedName)) { + || isBzippedTar(compressedName) + || isZstdTar(compressedName)) { return compressedName.substring(0, Utils.nthToLastCharIndex(2, compressedName, '.')); } else { return compressedName; @@ -267,6 +294,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); } @@ -283,6 +314,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(); } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/Extractor.java b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/Extractor.java index 3e1a5097a4..b60fd59e0c 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/Extractor.java +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/Extractor.java @@ -119,5 +119,9 @@ public static class BadArchiveNotice extends IOException { public BadArchiveNotice(@NonNull Throwable reason) { super(reason); } + + public BadArchiveNotice(@NonNull String reason) { + super(reason); + } } } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCommonsArchiveExtractor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCommonsArchiveExtractor.kt index d9e8e63899..7d8703736e 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCommonsArchiveExtractor.kt +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCommonsArchiveExtractor.kt @@ -51,6 +51,14 @@ abstract class AbstractCommonsArchiveExtractor( */ abstract fun createFrom(inputStream: InputStream): ArchiveInputStream + protected open val onErrorHandler: (Throwable) -> Unit = { e -> + if (e !is EmptyArchiveNotice) { + throw BadArchiveNotice(e) + } else { + throw e + } + } + @Throws(IOException::class) @Suppress("EmptyWhileBlock") override fun extractWithFilter(filter: Filter) { @@ -58,7 +66,7 @@ abstract class AbstractCommonsArchiveExtractor( val archiveEntries = ArrayList() var inputStream = createFrom(FileInputStream(filePath)) var archiveEntry: ArchiveEntry? - try { + runCatching { while (inputStream.nextEntry.also { archiveEntry = it } != null) { archiveEntry?.run { if (filter.shouldExtract(name, isDirectory)) { @@ -84,7 +92,7 @@ abstract class AbstractCommonsArchiveExtractor( } else { throw EmptyArchiveNotice() } - } finally { + }.onFailure(onErrorHandler).also { inputStream.close() } } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCompressedTarArchiveExtractor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCompressedTarArchiveExtractor.kt index 1999ed7d95..67b2d45afd 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCompressedTarArchiveExtractor.kt +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractCompressedTarArchiveExtractor.kt @@ -54,10 +54,16 @@ abstract class AbstractCompressedTarArchiveExtractor( abstract fun getCompressorInputStreamClass(): Class override fun createFrom(inputStream: InputStream): TarArchiveInputStream { - return runCatching { - TarArchiveInputStream(compressorInputStreamConstructor.newInstance(inputStream)) - }.getOrElse { - throw BadArchiveNotice(it) + if (inputStream.available() < 1) { + throw BadArchiveNotice( + "Empty input stream - no valid compressed data can be found", + ) + } else { + return runCatching { + TarArchiveInputStream(compressorInputStreamConstructor.newInstance(inputStream)) + }.getOrElse { + throw BadArchiveNotice(it) + } } } } diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractIsoExtractor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractIsoExtractor.kt new file mode 100644 index 0000000000..afbe620642 --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/AbstractIsoExtractor.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2014-2023 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.extractcontents.helpers + +import android.content.Context +import com.amaze.filemanager.R +import com.amaze.filemanager.application.AppConfig +import com.amaze.filemanager.fileoperations.utils.UpdatePosition +import com.amaze.filemanager.filesystem.FileUtil +import com.amaze.filemanager.filesystem.MakeDirectoryOperation +import com.amaze.filemanager.filesystem.compressed.CompressedHelper +import com.amaze.filemanager.filesystem.compressed.extractcontents.Extractor +import com.amaze.filemanager.filesystem.files.GenericCopyUtil +import net.didion.loopy.AbstractBlockFileSystem +import net.didion.loopy.FileEntry +import java.io.BufferedOutputStream +import java.io.File +import java.io.IOException + +abstract class AbstractIsoExtractor( + context: Context, + filePath: String, + outputPath: String, + listener: OnUpdate, + updatePosition: UpdatePosition, +) : Extractor(context, filePath, outputPath, listener, updatePosition) { + protected abstract val fileSystemImplementation: Class + + override fun extractWithFilter(filter: Filter) { + val isoFile = + fileSystemImplementation.getDeclaredConstructor( + File::class.java, + Boolean::class.java, + ).newInstance(File(filePath), true) + var totalBytes = 0L + // Quirk. AbstractBlockFileSystem.getEntries().hasNextElement() would return true even if + // it's empty or nothing, by then it's already too late but had to catch NPE on our own + val fileEntries: List = + runCatching { + isoFile.entries?.let { isoFileEntries -> + isoFileEntries.toList().partition { entry -> + CompressedHelper.isEntryPathValid((entry as FileEntry).path) + }.let { pair -> + pair.first as List + } + } ?: throw IOException("Empty archive or file is corrupt") + }.onFailure { + throw BadArchiveNotice(it) + }.getOrThrow() + + if (fileEntries.isNotEmpty()) { + totalBytes = fileEntries.sumOf { it.size.toLong() } + listener.onStart(totalBytes, fileEntries.first().name) + fileEntries.forEach { entry -> + if (!listener.isCancelled) { + listener.onUpdate(entry.name) + extractEntry(context, isoFile, entry, outputPath) + } + } + listener.onFinish() + } else { + throw EmptyArchiveNotice() + } + } + + private fun extractEntry( + context: Context, + archive: AbstractBlockFileSystem, + entry: FileEntry, + outputDir: String, + ) { + val name = + fixEntryName(entry.path).replace( + "\\\\".toRegex(), + CompressedHelper.SEPARATOR, + ) + val outputFile = File(outputDir, name) + if (!outputFile.canonicalPath.startsWith(outputDir)) { + throw IOException("Incorrect RAR FileHeader path!") + } + if (entry.isDirectory) { + MakeDirectoryOperation.mkdir(outputFile, context) + outputFile.setLastModified(entry.lastModifiedTime) + return + } + if (!outputFile.parentFile.exists()) { + MakeDirectoryOperation.mkdir(outputFile.parentFile, context) + outputFile.parentFile.setLastModified(entry.lastModifiedTime) + } + + archive.getInputStream(entry).use { inputStream -> + FileUtil.getOutputStream(outputFile, context)?.let { fileOutputStream -> + BufferedOutputStream(fileOutputStream).run { + var len: Int + val buf = ByteArray(GenericCopyUtil.DEFAULT_BUFFER_SIZE) + while (inputStream.read(buf).also { len = it } != -1) { + if (!listener.isCancelled) { + write(buf, 0, len) + updatePosition.updatePosition(len.toLong()) + } else { + break + } + } + close() + outputFile.setLastModified(entry.lastModifiedTime) + } + } ?: AppConfig.toast( + context, + context.getString( + R.string.error_archive_cannot_extract, + entry.path, + outputDir, + ), + ) + } + } +} diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/Iso9660Extractor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/Iso9660Extractor.kt new file mode 100644 index 0000000000..52cd05dc93 --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/Iso9660Extractor.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014-2023 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.extractcontents.helpers + +import android.content.Context +import com.amaze.filemanager.fileoperations.utils.UpdatePosition +import net.didion.loopy.AbstractBlockFileSystem +import net.didion.loopy.iso9660.ISO9660FileSystem + +class Iso9660Extractor( + context: Context, + filePath: String, + outputPath: String, + listener: OnUpdate, + updatePosition: UpdatePosition, +) : AbstractIsoExtractor( + context, + filePath, + outputPath, + listener, + updatePosition, + ) { + override val fileSystemImplementation: Class + get() = ISO9660FileSystem::class.java +} diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/TarZstExtractor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/TarZstExtractor.kt new file mode 100644 index 0000000000..c629d3da5e --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/TarZstExtractor.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014-2021 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.extractcontents.helpers + +import android.content.Context +import com.amaze.filemanager.fileoperations.utils.UpdatePosition +import org.apache.commons.compress.compressors.CompressorInputStream +import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream + +class TarZstExtractor( + context: Context, + filePath: String, + outputPath: String, + listener: OnUpdate, + updatePosition: UpdatePosition, +) : AbstractCompressedTarArchiveExtractor( + context, + filePath, + outputPath, + listener, + updatePosition, + ) { + override fun getCompressorInputStreamClass(): Class = ZstdCompressorInputStream::class.java +} diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/ZstdExtractor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/ZstdExtractor.kt new file mode 100644 index 0000000000..b03642547b --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/ZstdExtractor.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014-2023 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.extractcontents.helpers + +import android.content.Context +import com.amaze.filemanager.fileoperations.utils.UpdatePosition +import org.apache.commons.compress.compressors.CompressorInputStream +import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream + +class ZstdExtractor( + context: Context, + filePath: String, + outputPath: String, + listener: OnUpdate, + updatePosition: UpdatePosition, +) : AbstractCommonsCompressedFileExtractor( + context, + filePath, + outputPath, + listener, + updatePosition, + ) { + override fun getCompressorInputStreamClass(): Class { + return ZstdCompressorInputStream::class.java + } +} diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/showcontents/helpers/Iso9660Decompressor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/showcontents/helpers/Iso9660Decompressor.kt new file mode 100644 index 0000000000..4a24d0941e --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/showcontents/helpers/Iso9660Decompressor.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2014-2023 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.showcontents.helpers + +import android.content.Context +import com.amaze.filemanager.asynchronous.asynctasks.compress.CompressedHelperCallable +import com.amaze.filemanager.asynchronous.asynctasks.compress.Iso9660HelperCallable +import com.amaze.filemanager.filesystem.compressed.showcontents.Decompressor + +open class Iso9660Decompressor(context: Context) : Decompressor(context) { + override fun changePath( + path: String, + addGoBackItem: Boolean, + ): CompressedHelperCallable = Iso9660HelperCallable(filePath, path, addGoBackItem) +} diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/showcontents/helpers/TarZstDecompressor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/showcontents/helpers/TarZstDecompressor.kt new file mode 100644 index 0000000000..29c13009d2 --- /dev/null +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/showcontents/helpers/TarZstDecompressor.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014-2021 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.showcontents.helpers + +import android.content.Context +import com.amaze.filemanager.asynchronous.asynctasks.compress.TarZstHelperCallable +import com.amaze.filemanager.filesystem.compressed.showcontents.Decompressor + +class TarZstDecompressor(context: Context) : Decompressor(context) { + override fun changePath( + path: String, + addGoBackItem: Boolean, + ) = TarZstHelperCallable(context, filePath, path, addGoBackItem) +} diff --git a/app/src/main/java/com/amaze/filemanager/ui/icons/Icons.java b/app/src/main/java/com/amaze/filemanager/ui/icons/Icons.java index 9cf5861eb4..60b05f15d6 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/icons/Icons.java +++ b/app/src/main/java/com/amaze/filemanager/ui/icons/Icons.java @@ -131,7 +131,8 @@ private static void putKeys(int resId, String... mimeTypes) { "application/x-rar-compressed", "application/x-lzma", "application/x-xz", - "application/x-bzip2"); + "application/x-bzip2", + "application/zst"); putKeys(CONTACT, "text/x-vcard", "text/vcard"); putKeys(EVENTS, "text/calendar", "text/x-vcalendar"); putKeys( diff --git a/app/src/main/java/com/amaze/filemanager/ui/icons/MimeTypes.java b/app/src/main/java/com/amaze/filemanager/ui/icons/MimeTypes.java index 1f203d3c37..b49bb4cb18 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/icons/MimeTypes.java +++ b/app/src/main/java/com/amaze/filemanager/ui/icons/MimeTypes.java @@ -75,6 +75,7 @@ public final class MimeTypes { MIME_TYPES.put("xz", "application/x-xz"); MIME_TYPES.put("lzma", "application/x-lzma"); MIME_TYPES.put("Z", "application/x-compress"); + MIME_TYPES.put("zst", "application/zst"); MIME_TYPES.put("bat", "application/x-msdownload"); MIME_TYPES.put("ksh", "text/plain"); diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableArchiveTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableArchiveTest.kt index 70d34325ec..e6292b0d87 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableArchiveTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableArchiveTest.kt @@ -72,7 +72,11 @@ abstract class AbstractCompressedHelperCallableArchiveTest : open fun testSublevels() { var task = createCallable("test-archive") var result = task.call() - assertEquals("Thrown from $javaClass.name", 5, result.size.toLong()) + assertEquals( + "Thrown from $javaClass.name; Entries saw ${result.joinToString { "${it.path}\n" }}", + 5, + result.size.toLong(), + ) assertEquals("1", result[0].name) assertEntryTimestampCorrect(result[0]) assertEquals("2", result[1].name) diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt index 3d69134c85..a11b4a846c 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt @@ -30,7 +30,10 @@ import com.amaze.filemanager.shadows.ShadowMultiDex import com.amaze.filemanager.test.randomBytes import com.amaze.filemanager.test.supportedArchiveExtensions import org.apache.commons.compress.archivers.ArchiveException -import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config @@ -75,14 +78,20 @@ class CompressedHelperForBadArchiveTest { ApplicationProvider.getApplicationContext(), badArchive, ) - Assert.assertNotNull(task) + assertNotNull(task) task!! try { val result = task.changePath("", false).call() - Assert.assertNull("Thrown from ${task.javaClass}", result) + // FIXME: Quirk. ZStdCompressorInputStream behaves differently that it cannot throw + // if encountering corrupt/zero byte tar.zst archives + if (archiveType in arrayOf("tar.zst", "iso")) { + assertEquals(0, result.size) + } else { + assertNull("Thrown from ${task.javaClass}", result) + } } catch (exception: ArchiveException) { - Assert.assertNotNull(exception) - Assert.assertTrue( + assertNotNull(exception) + assertTrue( "Thrown from ${task.javaClass}: ${exception.javaClass} was thrown", ArchiveException::class.java.isAssignableFrom(exception.javaClass), ) @@ -97,6 +106,6 @@ class CompressedHelperForBadArchiveTest { * = filename without compressed extension. They won't throw exceptions, so excluded from * list */ - private val excludedArchiveTypes = listOf("tar", "rar", "bz2", "lzma", "gz", "xz") + private val excludedArchiveTypes = listOf("tar", "rar", "bz2", "lzma", "gz", "xz", "zst") } } diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/Iso9660HelperCallableTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/Iso9660HelperCallableTest.kt new file mode 100644 index 0000000000..642c80869c --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/Iso9660HelperCallableTest.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014-2023 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.asynchronous.asynctasks.compress + +import java.io.File + +class Iso9660HelperCallableTest : AbstractCompressedHelperCallableArchiveTest() { + override val archiveFileName: String + get() = "test-archive.iso" + + override fun doCreateCallable( + archive: File, + relativePath: String, + ): CompressedHelperCallable = + Iso9660HelperCallable( + archive.absolutePath, + relativePath, + false, + ) +} diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarZstHelperCallableTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarZstHelperCallableTest.kt new file mode 100644 index 0000000000..7e274e2c4d --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/TarZstHelperCallableTest.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014-2021 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.asynchronous.asynctasks.compress + +import androidx.test.core.app.ApplicationProvider +import java.io.File + +class TarZstHelperCallableTest : AbstractCompressedHelperCallableArchiveTest() { + override val archiveFileName: String + get() = "test-archive.tar.zst" + + override fun doCreateCallable( + archive: File, + relativePath: String, + ): CompressedHelperCallable = + TarZstHelperCallable( + ApplicationProvider.getApplicationContext(), + archive.absolutePath, + relativePath, + false, + ) +} diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/UnknownCompressedHelperCallableTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/UnknownCompressedHelperCallableTest.kt index 4ef3318a49..7ea8ea6abb 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/UnknownCompressedHelperCallableTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/UnknownCompressedHelperCallableTest.kt @@ -31,7 +31,7 @@ class UnknownCompressedHelperCallableTest : AbstractCompressedHelperCallableTest */ @Test fun testExtract() { - listOf("lzma", "gz", "xz", "bz2").forEach { ext -> + listOf("lzma", "gz", "xz", "bz2", "zst").forEach { ext -> doTestExtract( UnknownCompressedFileHelperCallable( File( diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt index fe071ccc28..4bb5386e3e 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt @@ -48,7 +48,6 @@ import org.awaitility.Awaitility.await import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNull -import org.junit.Assert.fail import org.junit.Before import org.junit.Ignore import org.junit.Rule @@ -446,11 +445,6 @@ class ExtractServiceTest { performTest(badArchive) ShadowLooper.idleMainLooper() await() - .conditionEvaluationListener { condition -> - if (condition.remainingTimeInMS <= 0 && !condition.isSatisfied) { - fail("Extractor unable to handle bad archive for $archiveType") - } - } .atMost(10, TimeUnit.SECONDS) .until { ShadowToast.getLatestToast() != null diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/IsoExtractorTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/IsoExtractorTest.kt new file mode 100644 index 0000000000..b654be4a63 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/IsoExtractorTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014-2021 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.extractcontents + +import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.Iso9660Extractor + +class IsoExtractorTest : AbstractArchiveExtractorTest() { + override val archiveType: String = "iso" + + override fun extractorClass(): Class = Iso9660Extractor::class.java +} diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/TarZstExtractorTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/TarZstExtractorTest.kt new file mode 100644 index 0000000000..ab4db4d40f --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/TarZstExtractorTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014-2021 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.extractcontents + +import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.TarZstExtractor + +class TarZstExtractorTest : AbstractArchiveExtractorTest() { + override val archiveType: String = "tar.zst" + + override fun extractorClass(): Class = TarZstExtractor::class.java +} diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/ZstdExtractorTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/ZstdExtractorTest.kt new file mode 100644 index 0000000000..f196d3b076 --- /dev/null +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/ZstdExtractorTest.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014-2021 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai 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 . + */ + +package com.amaze.filemanager.filesystem.compressed.extractcontents + +import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.ZstdExtractor + +class ZstdExtractorTest : AbstractCompressedFileExtractorTest() { + override fun extractorClass(): Class = ZstdExtractor::class.java + + override val archiveType: String = "zst" +} diff --git a/app/src/test/resources/test-archive.iso b/app/src/test/resources/test-archive.iso new file mode 100644 index 0000000000..525ab6ca02 Binary files /dev/null and b/app/src/test/resources/test-archive.iso differ diff --git a/app/src/test/resources/test-archive.tar.zst b/app/src/test/resources/test-archive.tar.zst new file mode 100644 index 0000000000..8dd59ecfae Binary files /dev/null and b/app/src/test/resources/test-archive.tar.zst differ diff --git a/app/src/test/resources/test-archive.txt.zst b/app/src/test/resources/test-archive.txt.zst new file mode 100644 index 0000000000..7598a59c23 Binary files /dev/null and b/app/src/test/resources/test-archive.txt.zst differ diff --git a/app/src/test/resources/test-archive.udf b/app/src/test/resources/test-archive.udf new file mode 100644 index 0000000000..f799a99d9e Binary files /dev/null and b/app/src/test/resources/test-archive.udf differ diff --git a/app/src/test/resources/test.txt.zst b/app/src/test/resources/test.txt.zst new file mode 100644 index 0000000000..7598a59c23 Binary files /dev/null and b/app/src/test/resources/test.txt.zst differ diff --git a/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperCallableTestSuite.kt b/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperCallableTestSuite.kt index e0709fc0d9..89b0f79958 100644 --- a/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperCallableTestSuite.kt +++ b/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperCallableTestSuite.kt @@ -34,6 +34,7 @@ import org.junit.runners.Suite.SuiteClasses TarLzmaHelperCallableTest::class, TarXzHelperCallableTest::class, TarXzHelperCallableTest2::class, + TarZstHelperCallableTest::class, SevenZipHelperCallableTest::class, SevenZipHelperCallableTest2::class, SevenZipHelperCallableTest3::class, diff --git a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/ExtractorTestSuite.kt b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/ExtractorTestSuite.kt index 3088d1150a..f30a926446 100644 --- a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/ExtractorTestSuite.kt +++ b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/ExtractorTestSuite.kt @@ -30,6 +30,7 @@ import org.junit.runners.Suite.SuiteClasses Bzip2ExtractorTest::class, LzmaExtractorTest::class, XzExtractorTest::class, + ZstdExtractorTest::class, TarGzExtractorTest::class, TgzExtractorTest::class, ZipExtractorTest::class, @@ -39,6 +40,7 @@ import org.junit.runners.Suite.SuiteClasses TarBzip2ExtractorTest2::class, TarLzmaExtractorTest::class, TarXzExtractorTest::class, + TarZstExtractorTest::class, SevenZipExtractorTest::class, SevenZipWithoutTimestampTest::class, PasswordProtectedRarTest::class, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bc8b19e858..fb29ec42b2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -68,6 +68,7 @@ mpAndroidChart = "v3.0.2" concurrentTrees = "2.6.1" aboutLibraries = "6.1.1" amazeTrashBin = "1.0.10" +zstdJni = "1.5.2-5" [libraries] androidX-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidXAppCompat" }