diff --git a/app/build.gradle b/app/build.gradle index 136028fe7..fda05d598 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -243,12 +243,6 @@ dependencies { //apache implementation('org.apache.commons:commons-text:1.10.0') - //noinspection GradleDependency,1.23.0对安卓支持不好 - implementation 'org.apache.commons:commons-compress:1.22' - implementation 'org.tukaani:xz:1.9' - - //RAR - implementation 'com.github.junrar:junrar:7.5.5' //MarkDown def markwonVersion = "4.6.2" diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 6e8824f20..9ef96f462 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -4,8 +4,6 @@ import android.net.Uri import androidx.annotation.Keep import cn.hutool.core.codec.Base64 import cn.hutool.core.util.HexUtil -import com.github.junrar.Archive -import com.github.junrar.rarfile.FileHeader import com.github.liuyueyi.quick.transfer.ChineseUtils import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst.dateFormat @@ -23,13 +21,11 @@ import io.legado.app.model.Debug import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.QueryTTF import io.legado.app.utils.* +import io.legado.app.utils.compress.LibArchiveUtils import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking import okio.use -import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry -import org.apache.commons.compress.archivers.sevenz.SevenZFile -import org.apache.commons.compress.utils.SeekableInMemoryByteChannel import org.jsoup.Connection import org.jsoup.Jsoup import splitties.init.appCtx @@ -699,18 +695,9 @@ interface JsExtensions : JsEncodeUtils { HexUtil.decodeHex(url) } - val bos = ByteArrayOutputStream() - Archive(ByteArrayInputStream(bytes)).use { archive -> - var entry: FileHeader - while (archive.nextFileHeader().also { entry = it } != null) { - if (entry.fileName.equals(path)) { - archive.getInputStream(entry).use { it.copyTo(bos) } - return bos.toByteArray() - } - } + return ByteArrayInputStream(bytes).use { + LibArchiveUtils.getByteArrayContent(it, path) } - log("getRarContent 未发现内容") - return null } /** @@ -726,18 +713,9 @@ interface JsExtensions : JsEncodeUtils { HexUtil.decodeHex(url) } - val bos = ByteArrayOutputStream() - SevenZFile(SeekableInMemoryByteChannel(bytes)).use { sevenZFile -> - var entry: SevenZArchiveEntry - while (sevenZFile.nextEntry.also { entry = it } != null) { - if (entry.name.equals(path)) { - sevenZFile.getInputStream(entry).use { it.copyTo(bos) } - return bos.toByteArray() - } - } + return ByteArrayInputStream(bytes).use { + LibArchiveUtils.getByteArrayContent(it, path) } - log("get7zContent 未发现内容") - return null } diff --git a/app/src/main/java/io/legado/app/utils/compress/LibArchiveUtils.kt b/app/src/main/java/io/legado/app/utils/compress/LibArchiveUtils.kt index 6f7bd9c90..3eede4120 100644 --- a/app/src/main/java/io/legado/app/utils/compress/LibArchiveUtils.kt +++ b/app/src/main/java/io/legado/app/utils/compress/LibArchiveUtils.kt @@ -10,6 +10,7 @@ import io.legado.app.lib.icu4j.CharsetDetector import me.zhanghai.android.libarchive.Archive import me.zhanghai.android.libarchive.ArchiveEntry import me.zhanghai.android.libarchive.ArchiveException +import splitties.init.appCtx import java.io.File import java.io.FileDescriptor import java.io.IOException @@ -23,6 +24,7 @@ import java.nio.charset.StandardCharsets object LibArchiveUtils { + val cachePath = File(appCtx.cacheDir, "archive") @Throws(ArchiveException::class) fun openArchive( @@ -60,15 +62,12 @@ object LibArchiveUtils { Archive.readOpen1(archive) successful = true return archive - - } finally { if (!successful) { Archive.free(archive) } } - } @@ -135,7 +134,6 @@ object LibArchiveUtils { } } - } @@ -216,7 +214,7 @@ object LibArchiveUtils { fun unArchive( pfd: ParcelFileDescriptor, destDir: File, - filter: ((String) -> Boolean)? + filter: ((String) -> Boolean)? = null ): List { return unArchive(openArchive(pfd), destDir, filter) } @@ -288,6 +286,46 @@ object LibArchiveUtils { return getFilesName(openArchive(pfd), filter) } + fun getByteArrayContent(inputStream: InputStream, path: String): ByteArray? { + val archive = openArchive(inputStream) + try { + var entry = Archive.readNextHeader(archive) + while (entry != 0L) { + val entryName = + getEntryString(ArchiveEntry.pathnameUtf8(entry), ArchiveEntry.pathname(entry)) + ?: continue + + val entryStat = ArchiveEntry.stat(entry) + + //判断是否是文件夹 + if (S_ISDIR(entryStat.stMode)) { + entry = Archive.readNextHeader(archive) + continue + } + + if (entryName == path) { + cachePath.mkdirs() + val entryFile = File(cachePath, entry.toString()) + entryFile.delete() + entryFile.createNewFile() + entryFile.setReadable(true) + entryFile.setExecutable(true) + ParcelFileDescriptor.open(entryFile, ParcelFileDescriptor.MODE_WRITE_ONLY).use { + Archive.readDataIntoFd(archive, it.fd) + } + val bytes = entryFile.readBytes() + entryFile.delete() + return bytes + } + + entry = Archive.readNextHeader(archive) + + } + } finally { + Archive.free(archive) + } + return null + } @Throws(SecurityException::class) private fun getFilesName( @@ -320,13 +358,11 @@ object LibArchiveUtils { entry = Archive.readNextHeader(archive) - } } finally { Archive.free(archive) } - return fileNames } @@ -344,5 +380,4 @@ object LibArchiveUtils { } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/compress/RarUtils.kt b/app/src/main/java/io/legado/app/utils/compress/RarUtils.kt deleted file mode 100644 index cf69d598b..000000000 --- a/app/src/main/java/io/legado/app/utils/compress/RarUtils.kt +++ /dev/null @@ -1,129 +0,0 @@ -package io.legado.app.utils.compress - -import com.github.junrar.Archive -import com.github.junrar.rarfile.FileHeader -import java.io.ByteArrayInputStream -import java.io.File -import java.io.FileOutputStream -import java.io.InputStream - -@Suppress("unused", "MemberVisibilityCanBePrivate") -object RarUtils { - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(inputStream: InputStream, path: String, filter: ((String) -> Boolean)? = null): List { - return unRarToPath(inputStream, File(path), filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(byteArray: ByteArray, path: String, filter: ((String) -> Boolean)? = null): List { - return unRarToPath(byteArray, File(path), filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(zipPath: String, path: String, filter: ((String) -> Boolean)? = null): List { - return unRarToPath(zipPath, File(path), filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(file: File, path: String, filter: ((String) -> Boolean)? = null): List { - return unRarToPath(file, File(path), filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(inputStream: InputStream, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return Archive(inputStream).use { - unRarToPath(it, destDir, filter) - } - } - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(byteArray: ByteArray, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return Archive(ByteArrayInputStream(byteArray)).use { - unRarToPath(it, destDir, filter) - } - } - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(filePath: String, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return Archive(File(filePath)).use { - unRarToPath(it, destDir, filter) - } - } - - @Throws(NullPointerException::class, SecurityException::class) - fun unRarToPath(file: File, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return Archive(file).use { - unRarToPath(it, destDir, filter) - } - } - - @Throws(NullPointerException::class, SecurityException::class) - private fun unRarToPath( - archive: Archive, - destDir: File?, - filter: ((String) -> Boolean)? = null - ): List { - destDir ?: throw NullPointerException("解决路径不能为空") - val files = arrayListOf() - var entry: FileHeader? - while (archive.nextFileHeader().also { entry = it } != null) { - val entryName = entry!!.fileName - val entryFile = File(destDir, entryName) - if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath)) { - throw SecurityException("压缩文件只能解压到指定路径") - } - if (entry!!.isDirectory) { - if (!entryFile.exists()) { - entryFile.mkdirs() - } - continue - } - if (entryFile.parentFile?.exists() != true) { - entryFile.parentFile?.mkdirs() - } - if (filter != null && !filter.invoke(entryName)) continue - if (!entryFile.exists()) { - entryFile.createNewFile() - entryFile.setReadable(true) - entryFile.setExecutable(true) - } - FileOutputStream(entryFile).use { - archive.getInputStream(entry).copyTo(it) - files.add(entryFile) - } - } - return files - } - - - /* 遍历目录获取所有文件名 */ - @Throws(NullPointerException::class, SecurityException::class) - fun getFilesName( - inputStream: InputStream, - filter: ((String) -> Boolean)? = null - ): List { - return Archive(inputStream).use { - getFilesName(it, filter) - } - } - - @Throws(NullPointerException::class, SecurityException::class) - private fun getFilesName( - archive: Archive, - filter: ((String) -> Boolean)? = null - ): List { - val fileNames = mutableListOf() - var entry: FileHeader? - while (archive.nextFileHeader().also { entry = it } != null) { - if (entry!!.isDirectory) { - continue - } - val fileName = entry!!.fileName - if (filter != null && filter.invoke(fileName)) - fileNames.add(fileName) - } - return fileNames - } - -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/compress/SevenZipUtils.kt b/app/src/main/java/io/legado/app/utils/compress/SevenZipUtils.kt deleted file mode 100644 index 76bdad68b..000000000 --- a/app/src/main/java/io/legado/app/utils/compress/SevenZipUtils.kt +++ /dev/null @@ -1,133 +0,0 @@ -package io.legado.app.utils.compress - -import android.annotation.SuppressLint -import android.os.ParcelFileDescriptor -import io.legado.app.utils.ParcelFileDescriptorChannel -import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry -import org.apache.commons.compress.archivers.sevenz.SevenZFile -import org.apache.commons.compress.utils.SeekableInMemoryByteChannel -import java.io.File -import java.io.FileOutputStream -import java.io.InputStream -import java.nio.channels.FileChannel - -@Suppress("unused", "MemberVisibilityCanBePrivate") -object SevenZipUtils { - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(inputStream: InputStream, path: String, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(inputStream, File(path), filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(byteArray: ByteArray, path: String, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(byteArray, File(path),filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(pfd: ParcelFileDescriptor, path: String, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(pfd, File(path), filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(fileChannel: FileChannel, path: String, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(fileChannel, File(path), filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(inputStream: InputStream, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(SevenZFile(SeekableInMemoryByteChannel(inputStream.readBytes())), destDir, filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(byteArray: ByteArray, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(SevenZFile(SeekableInMemoryByteChannel(byteArray)), destDir, filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(pfd: ParcelFileDescriptor, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(SevenZFile(ParcelFileDescriptorChannel(pfd)), destDir, filter) - } - - @SuppressLint("NewApi") - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(fileChannel: FileChannel, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(SevenZFile(fileChannel), destDir, filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(file: File, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(SevenZFile(file), destDir, filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - fun un7zToPath(filePath: String, destDir: File?, filter: ((String) -> Boolean)? = null): List { - return un7zToPath(SevenZFile(File(filePath)), destDir, filter) - } - - @Throws(NullPointerException::class, SecurityException::class) - private fun un7zToPath(sevenZFile: SevenZFile, destDir: File?, filter: ((String) -> Boolean)? = null): List { - destDir ?: throw NullPointerException("解决路径不能为空") - val files = arrayListOf() - var entry: SevenZArchiveEntry? - while (sevenZFile.nextEntry.also { entry = it } != null) { - val entryName = entry!!.name - val entryFile = File(destDir, entryName) - if (!entryFile.canonicalPath.startsWith(destDir.canonicalPath)) { - throw SecurityException("压缩文件只能解压到指定路径") - } - if (entry!!.isDirectory) { - if (!entryFile.exists()) { - entryFile.mkdirs() - } - continue - } - if (entryFile.parentFile?.exists() != true) { - entryFile.parentFile?.mkdirs() - } - if (filter != null && !filter.invoke(entryName)) continue - if (!entryFile.exists()) { - entryFile.createNewFile() - entryFile.setReadable(true) - entryFile.setExecutable(true) - } - FileOutputStream(entryFile).use { - sevenZFile.getInputStream(entry).copyTo(it) - files.add(entryFile) - } - } - return files - } - - /* 遍历目录获取所有文件名 */ - @Throws(NullPointerException::class, SecurityException::class) - fun getFilesName( - inputStream: InputStream, - filter: ((String) -> Boolean)? = null - ): List { - return getFilesName( - SevenZFile(SeekableInMemoryByteChannel(inputStream.readBytes())), - filter - ) - } - - @Throws(NullPointerException::class, SecurityException::class) - private fun getFilesName( - sevenZFile: SevenZFile, - filter: ((String) -> Boolean)? = null - ): List { - val fileNames = mutableListOf() - var entry: SevenZArchiveEntry? - while (sevenZFile.nextEntry.also { entry = it } != null) { - if (entry!!.isDirectory) { - continue - } - val fileName = entry!!.name - if (filter != null && filter.invoke(fileName)) - fileNames.add(fileName) - } - return fileNames - } - - -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/compress/ZipUtils.kt b/app/src/main/java/io/legado/app/utils/compress/ZipUtils.kt index 3bddccc39..152421c9e 100644 --- a/app/src/main/java/io/legado/app/utils/compress/ZipUtils.kt +++ b/app/src/main/java/io/legado/app/utils/compress/ZipUtils.kt @@ -1,14 +1,10 @@ package io.legado.app.utils.compress import android.annotation.SuppressLint -import android.os.Build -import androidx.annotation.RequiresApi import io.legado.app.utils.DebugLog import io.legado.app.utils.printOnDebug import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.withContext -import org.apache.commons.compress.archivers.ArchiveEntry -import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream import java.io.* import java.util.zip.* @@ -215,14 +211,8 @@ object ZipUtils { path: String, filter: ((String) -> Boolean)? = null ): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - ZipArchiveInputStream(inputStream).use { - unZipToPath(it, File(path), filter) - } - } else { - ZipInputStream(inputStream).use { - unZipToPath(it, File(path), filter) - } + return ZipInputStream(inputStream).use { + unZipToPath(it, File(path), filter) } } @@ -232,56 +222,11 @@ object ZipUtils { dir: File, filter: ((String) -> Boolean)? = null ): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - ZipArchiveInputStream(inputStream).use { - unZipToPath(it, dir, filter) - } - } else { - ZipInputStream(inputStream).use { - unZipToPath(it, dir, filter) - } + return ZipInputStream(inputStream).use { + unZipToPath(it, dir, filter) } } - @RequiresApi(Build.VERSION_CODES.N) - @Throws(SecurityException::class) - private fun unZipToPath( - zipInputStream: ZipArchiveInputStream, - dir: File, - filter: ((String) -> Boolean)? = null - ): List { - val files = arrayListOf() - var entry: ArchiveEntry? - while (zipInputStream.nextEntry.also { entry = it } != null) { - val entryName = entry!!.name - val entryFile = File(dir, entryName) - if (!entryFile.canonicalPath.startsWith(dir.canonicalPath)) { - throw SecurityException("压缩文件只能解压到指定路径") - } - if (entry!!.isDirectory) { - if (!entryFile.exists()) { - entryFile.mkdirs() - } - continue - } - if (entryFile.parentFile?.exists() != true) { - entryFile.parentFile?.mkdirs() - } - if (filter != null && !filter.invoke(entryName)) continue - if (!entryFile.exists()) { - entryFile.createNewFile() - entryFile.setReadable(true) - entryFile.setExecutable(true) - } - FileOutputStream(entryFile).use { - zipInputStream.copyTo(it) - files.add(entryFile) - } - } - return files - } - - @Throws(SecurityException::class) private fun unZipToPath( zipInputStream: ZipInputStream, @@ -325,36 +270,11 @@ object ZipUtils { inputStream: InputStream, filter: ((String) -> Boolean)? = null ): List { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - ZipArchiveInputStream(inputStream).use { - getFilesName(it, filter) - } - } else { - ZipInputStream(inputStream).use { - getFilesName(it, filter) - } + return ZipInputStream(inputStream).use { + getFilesName(it, filter) } } - @RequiresApi(Build.VERSION_CODES.N) - @Throws(SecurityException::class) - private fun getFilesName( - zipInputStream: ZipArchiveInputStream, - filter: ((String) -> Boolean)? = null - ): List { - val fileNames = mutableListOf() - var entry: ArchiveEntry? - while (zipInputStream.nextEntry.also { entry = it } != null) { - if (entry!!.isDirectory) { - continue - } - val fileName = entry!!.name - if (filter != null && filter.invoke(fileName)) - fileNames.add(fileName) - } - return fileNames - } - @Throws(SecurityException::class) private fun getFilesName( zipInputStream: ZipInputStream,