This commit is contained in:
kunfei 2023-09-20 16:46:54 +08:00
parent a71200762b
commit e8dc579c8c
6 changed files with 54 additions and 389 deletions

View File

@ -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"

View File

@ -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
}

View File

@ -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<File> {
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 {
}
}

View File

@ -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<File> {
return unRarToPath(inputStream, File(path), filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun unRarToPath(byteArray: ByteArray, path: String, filter: ((String) -> Boolean)? = null): List<File> {
return unRarToPath(byteArray, File(path), filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun unRarToPath(zipPath: String, path: String, filter: ((String) -> Boolean)? = null): List<File> {
return unRarToPath(zipPath, File(path), filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun unRarToPath(file: File, path: String, filter: ((String) -> Boolean)? = null): List<File> {
return unRarToPath(file, File(path), filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun unRarToPath(inputStream: InputStream, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
return Archive(inputStream).use {
unRarToPath(it, destDir, filter)
}
}
@Throws(NullPointerException::class, SecurityException::class)
fun unRarToPath(byteArray: ByteArray, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
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<File> {
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<File> {
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<File> {
destDir ?: throw NullPointerException("解决路径不能为空")
val files = arrayListOf<File>()
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<String> {
return Archive(inputStream).use {
getFilesName(it, filter)
}
}
@Throws(NullPointerException::class, SecurityException::class)
private fun getFilesName(
archive: Archive,
filter: ((String) -> Boolean)? = null
): List<String> {
val fileNames = mutableListOf<String>()
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
}
}

View File

@ -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<File> {
return un7zToPath(inputStream, File(path), filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(byteArray: ByteArray, path: String, filter: ((String) -> Boolean)? = null): List<File> {
return un7zToPath(byteArray, File(path),filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(pfd: ParcelFileDescriptor, path: String, filter: ((String) -> Boolean)? = null): List<File> {
return un7zToPath(pfd, File(path), filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(fileChannel: FileChannel, path: String, filter: ((String) -> Boolean)? = null): List<File> {
return un7zToPath(fileChannel, File(path), filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(inputStream: InputStream, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
return un7zToPath(SevenZFile(SeekableInMemoryByteChannel(inputStream.readBytes())), destDir, filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(byteArray: ByteArray, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
return un7zToPath(SevenZFile(SeekableInMemoryByteChannel(byteArray)), destDir, filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(pfd: ParcelFileDescriptor, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
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<File> {
return un7zToPath(SevenZFile(fileChannel), destDir, filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(file: File, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
return un7zToPath(SevenZFile(file), destDir, filter)
}
@Throws(NullPointerException::class, SecurityException::class)
fun un7zToPath(filePath: String, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
return un7zToPath(SevenZFile(File(filePath)), destDir, filter)
}
@Throws(NullPointerException::class, SecurityException::class)
private fun un7zToPath(sevenZFile: SevenZFile, destDir: File?, filter: ((String) -> Boolean)? = null): List<File> {
destDir ?: throw NullPointerException("解决路径不能为空")
val files = arrayListOf<File>()
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<String> {
return getFilesName(
SevenZFile(SeekableInMemoryByteChannel(inputStream.readBytes())),
filter
)
}
@Throws(NullPointerException::class, SecurityException::class)
private fun getFilesName(
sevenZFile: SevenZFile,
filter: ((String) -> Boolean)? = null
): List<String> {
val fileNames = mutableListOf<String>()
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
}
}

View File

@ -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<File> {
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<File> {
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<File> {
val files = arrayListOf<File>()
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<String> {
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<String> {
val fileNames = mutableListOf<String>()
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,