mirror of
https://github.com/gedoor/legado.git
synced 2025-08-10 00:52:30 +00:00
@@ -232,6 +232,7 @@ dependencies {
|
||||
//apache
|
||||
implementation('org.apache.commons:commons-text:1.10.0')
|
||||
implementation 'org.apache.commons:commons-compress:1.22'
|
||||
implementation 'org.tukaani:xz:1.9'
|
||||
|
||||
//RAR
|
||||
implementation 'com.github.junrar:junrar:7.5.4'
|
||||
|
||||
@@ -4,6 +4,8 @@ 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 io.legado.app.constant.AppConst
|
||||
import io.legado.app.constant.AppConst.dateFormat
|
||||
import io.legado.app.constant.AppLog
|
||||
@@ -21,6 +23,10 @@ import io.legado.app.utils.*
|
||||
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
|
||||
@@ -312,21 +318,21 @@ interface JsExtensions : JsEncodeUtils {
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
|
||||
/* Str转ByteArray */
|
||||
fun strToBytes(str: String): ByteArray {
|
||||
return str.toByteArray(charset("UTF-8"))
|
||||
}
|
||||
|
||||
|
||||
fun strToBytes(str: String, charset: String): ByteArray {
|
||||
return str.toByteArray(charset(charset))
|
||||
}
|
||||
|
||||
|
||||
/* ByteArray转Str */
|
||||
fun bytesToStr(bytes: ByteArray): String {
|
||||
return String(bytes, charset("UTF-8"))
|
||||
}
|
||||
|
||||
|
||||
fun bytesToStr(bytes: ByteArray, charset: String): String {
|
||||
return String(bytes, charset(charset))
|
||||
}
|
||||
@@ -337,7 +343,7 @@ interface JsExtensions : JsEncodeUtils {
|
||||
fun base64Decode(str: String?): String {
|
||||
return Base64.decodeStr(str)
|
||||
}
|
||||
|
||||
|
||||
fun base64Decode(str: String?, charset: String): String {
|
||||
return Base64.decodeStr(str, charset(charset))
|
||||
}
|
||||
@@ -481,7 +487,7 @@ interface JsExtensions : JsEncodeUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* js实现压缩文件解压
|
||||
* js实现Zip压缩文件解压
|
||||
* @param zipPath 相对路径
|
||||
* @return 相对路径
|
||||
*/
|
||||
@@ -497,6 +503,71 @@ interface JsExtensions : JsEncodeUtils {
|
||||
FileUtils.delete(zipFile.absolutePath)
|
||||
return unzipPath.substring(FileUtils.getCachePath().length)
|
||||
}
|
||||
/**
|
||||
* js实现7Zip压缩文件解压
|
||||
* @param zipPath 相对路径
|
||||
* @return 相对路径
|
||||
*/
|
||||
fun un7zFile(zipPath: String): String {
|
||||
if (zipPath.isEmpty()) return ""
|
||||
val unzipPath = FileUtils.getPath(
|
||||
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
|
||||
FileUtils.getNameExcludeExtension(zipPath)
|
||||
)
|
||||
val unzipFolder = File(unzipPath).createFolderReplace()
|
||||
val zipFile = getFile(zipPath)
|
||||
SevenZipUtils.un7zToPath(zipFile, unzipFolder)
|
||||
FileUtils.delete(zipFile.absolutePath)
|
||||
return unzipPath.substring(FileUtils.getCachePath().length)
|
||||
}
|
||||
/**
|
||||
* js实现Rar压缩文件解压
|
||||
* @param zipPath 相对路径
|
||||
* @return 相对路径
|
||||
*/
|
||||
fun unrarFile(zipPath: String): String {
|
||||
if (zipPath.isEmpty()) return ""
|
||||
val unzipPath = FileUtils.getPath(
|
||||
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
|
||||
FileUtils.getNameExcludeExtension(zipPath)
|
||||
)
|
||||
val unzipFolder = File(unzipPath).createFolderReplace()
|
||||
val zipFile = getFile(zipPath)
|
||||
RarUtils.unRarToPath(zipFile, unzipFolder)
|
||||
FileUtils.delete(zipFile.absolutePath)
|
||||
return unzipPath.substring(FileUtils.getCachePath().length)
|
||||
}
|
||||
/**
|
||||
* js实现压缩文件解压
|
||||
* @param zipPath 相对路径
|
||||
* @return 相对路径
|
||||
*/
|
||||
fun unArchiveFile(zipPath: String): String {
|
||||
if (zipPath.isEmpty()) return ""
|
||||
val unzipPath = FileUtils.getPath(
|
||||
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
|
||||
FileUtils.getNameExcludeExtension(zipPath)
|
||||
)
|
||||
val unzipFolder = File(unzipPath).createFolderReplace()
|
||||
val zipFile = getFile(zipPath)
|
||||
when {
|
||||
zipPath.endsWith(".zip", ignoreCase = true) -> {
|
||||
ZipUtils.unzipFile(zipFile, unzipFolder)
|
||||
}
|
||||
zipPath.endsWith(".rar", ignoreCase = true) -> {
|
||||
RarUtils.unRarToPath(zipFile, unzipFolder)
|
||||
}
|
||||
|
||||
zipPath.endsWith(".7z", ignoreCase = true) -> {
|
||||
SevenZipUtils.un7zToPath(zipFile, unzipFolder)
|
||||
}
|
||||
else -> {
|
||||
log("自动解压未识别类型${zipPath}")
|
||||
}
|
||||
}
|
||||
FileUtils.delete(zipFile.absolutePath)
|
||||
return unzipPath.substring(FileUtils.getCachePath().length)
|
||||
}
|
||||
|
||||
/**
|
||||
* js实现文件夹内所有文本文件读取
|
||||
@@ -538,6 +609,40 @@ interface JsExtensions : JsEncodeUtils {
|
||||
return String(byteArray, Charset.forName(charsetName))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络zip文件里面的数据
|
||||
* @param url zip文件的链接或十六进制字符串
|
||||
* @param path 所需获取文件在zip内的路径
|
||||
* @return zip指定文件的数据
|
||||
*/
|
||||
fun getRarStringContent(url: String, path: String): String {
|
||||
val byteArray = getRarByteArrayContent(url, path) ?: return ""
|
||||
val charsetName = EncodingDetect.getEncode(byteArray)
|
||||
return String(byteArray, Charset.forName(charsetName))
|
||||
}
|
||||
|
||||
fun getRarStringContent(url: String, path: String, charsetName: String): String {
|
||||
val byteArray = getRarByteArrayContent(url, path) ?: return ""
|
||||
return String(byteArray, Charset.forName(charsetName))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络7zip文件里面的数据
|
||||
* @param url 7zip文件的链接或十六进制字符串
|
||||
* @param path 所需获取文件在7zip内的路径
|
||||
* @return zip指定文件的数据
|
||||
*/
|
||||
fun get7zStringContent(url: String, path: String): String {
|
||||
val byteArray = get7zByteArrayContent(url, path) ?: return ""
|
||||
val charsetName = EncodingDetect.getEncode(byteArray)
|
||||
return String(byteArray, Charset.forName(charsetName))
|
||||
}
|
||||
|
||||
fun get7zStringContent(url: String, path: String, charsetName: String): String {
|
||||
val byteArray = get7zByteArrayContent(url, path) ?: return ""
|
||||
return String(byteArray, Charset.forName(charsetName))
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络zip文件里面的数据
|
||||
* @param url zip文件的链接或十六进制字符串
|
||||
@@ -551,19 +656,75 @@ interface JsExtensions : JsEncodeUtils {
|
||||
HexUtil.decodeHex(url)
|
||||
}
|
||||
val bos = ByteArrayOutputStream()
|
||||
val zis = ZipInputStream(ByteArrayInputStream(bytes))
|
||||
var entry: ZipEntry? = zis.nextEntry
|
||||
while (entry != null) {
|
||||
if (entry.name.equals(path)) {
|
||||
zis.use { it.copyTo(bos) }
|
||||
return bos.toByteArray()
|
||||
ZipInputStream(ByteArrayInputStream(bytes)).use { zis ->
|
||||
var entry: ZipEntry
|
||||
while (zis.nextEntry.also { entry = it } != null) {
|
||||
if (entry.name.equals(path)) {
|
||||
zis.use { it.copyTo(bos) }
|
||||
return bos.toByteArray()
|
||||
}
|
||||
entry = zis.nextEntry
|
||||
}
|
||||
entry = zis.nextEntry
|
||||
}
|
||||
|
||||
log("getZipContent 未发现内容")
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络Rar文件里面的数据
|
||||
* @param url Rar文件的链接或十六进制字符串
|
||||
* @param path 所需获取文件在Rar内的路径
|
||||
* @return Rar指定文件的数据
|
||||
*/
|
||||
fun getRarByteArrayContent(url: String, path: String): ByteArray? {
|
||||
val bytes = if (url.isAbsUrl()) {
|
||||
AnalyzeUrl(url, source = getSource()).getByteArray()
|
||||
} else {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
log("getRarContent 未发现内容")
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网络7zip文件里面的数据
|
||||
* @param url 7zip文件的链接或十六进制字符串
|
||||
* @param path 所需获取文件在7zip内的路径
|
||||
* @return 7zip指定文件的数据
|
||||
*/
|
||||
fun get7zByteArrayContent(url: String, path: String): ByteArray? {
|
||||
val bytes = if (url.isAbsUrl()) {
|
||||
AnalyzeUrl(url, source = getSource()).getByteArray()
|
||||
} else {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
log("get7zContent 未发现内容")
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
//******************文件操作************************//
|
||||
|
||||
|
||||
@@ -1,17 +1,57 @@
|
||||
package io.legado.app.utils
|
||||
|
||||
import androidx.annotation.Keep
|
||||
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")
|
||||
|
||||
@Keep
|
||||
@Suppress("unused","MemberVisibilityCanBePrivate")
|
||||
object RarUtils {
|
||||
fun unRarToPath(inputStream: InputStream, path: String){
|
||||
val archive= Archive(inputStream)
|
||||
fun unRarToPath(inputStream: InputStream,path:String){
|
||||
unRarToPath(inputStream, File(path))
|
||||
}
|
||||
fun unRarToPath(byteArray: ByteArray,path:String){
|
||||
unRarToPath(byteArray, File(path))
|
||||
}
|
||||
fun unRarToPath(zipPath:String,path:String){
|
||||
unRarToPath(zipPath, File(path))
|
||||
}
|
||||
fun unRarToPath(file: File,path:String){
|
||||
unRarToPath(file, File(path))
|
||||
}
|
||||
fun unRarToPath(inputStream: InputStream, destDir: File?) {
|
||||
Archive(inputStream).use {
|
||||
unRarToPath(it, destDir)
|
||||
}
|
||||
inputStream.close()
|
||||
}
|
||||
|
||||
fun unRarToPath(byteArray: ByteArray, destDir: File?) {
|
||||
Archive(ByteArrayInputStream(byteArray)).use {
|
||||
unRarToPath(it, destDir)
|
||||
}
|
||||
}
|
||||
|
||||
fun unRarToPath(filePath:String, destDir: File?) {
|
||||
Archive(File(filePath)).use {
|
||||
unRarToPath(it, destDir)
|
||||
}
|
||||
}
|
||||
|
||||
fun unRarToPath(file: File, destDir: File?) {
|
||||
Archive(file).use {
|
||||
unRarToPath(it, destDir)
|
||||
}
|
||||
}
|
||||
|
||||
fun unRarToPath(archive: Archive, destDir: File?) {
|
||||
var entry: FileHeader
|
||||
while (archive.nextFileHeader().also { entry=it }!=null){
|
||||
val entryFile = File(path, entry.fileName)
|
||||
while (archive.nextFileHeader().also { entry = it } != null) {
|
||||
val entryFile = File(destDir, entry.fileName)
|
||||
if (entry.isDirectory) {
|
||||
if (!entryFile.exists()) {
|
||||
entryFile.mkdirs()
|
||||
@@ -31,7 +71,6 @@ object RarUtils {
|
||||
}
|
||||
|
||||
}
|
||||
inputStream.close()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package io.legado.app.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.ParcelFileDescriptor
|
||||
import androidx.annotation.Keep
|
||||
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry
|
||||
import org.apache.commons.compress.archivers.sevenz.SevenZFile
|
||||
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel
|
||||
@@ -9,30 +10,49 @@ import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.nio.channels.FileChannel
|
||||
@Suppress("unused")
|
||||
|
||||
@Keep
|
||||
@Suppress("unused","MemberVisibilityCanBePrivate")
|
||||
object SevenZipUtils {
|
||||
|
||||
|
||||
|
||||
fun un7zToPath(inputStream: InputStream, path: String){
|
||||
un7zToPath(SevenZFile(SeekableInMemoryByteChannel(inputStream.readBytes())),path)
|
||||
fun un7zToPath(inputStream: InputStream, path:String){
|
||||
un7zToPath(inputStream,File(path))
|
||||
}
|
||||
fun un7zToPath(pfd: ParcelFileDescriptor, path: String){
|
||||
un7zToPath(SevenZFile(ParcelFileDescriptorChannel(pfd)),path)
|
||||
fun un7zToPath(byteArray: ByteArray, path:String){
|
||||
un7zToPath(byteArray,File(path))
|
||||
}
|
||||
fun un7zToPath(pfd: ParcelFileDescriptor, path:String){
|
||||
un7zToPath(pfd,File(path))
|
||||
}
|
||||
fun un7zToPath(fileChannel: FileChannel, path:String){
|
||||
un7zToPath(fileChannel,File(path))
|
||||
}
|
||||
|
||||
fun un7zToPath(inputStream: InputStream, destDir: File?){
|
||||
un7zToPath(SevenZFile(SeekableInMemoryByteChannel(inputStream.readBytes())),destDir)
|
||||
}
|
||||
fun un7zToPath(byteArray: ByteArray, destDir: File?){
|
||||
un7zToPath(SevenZFile(SeekableInMemoryByteChannel(byteArray)),destDir)
|
||||
}
|
||||
fun un7zToPath(pfd: ParcelFileDescriptor, destDir: File?){
|
||||
un7zToPath(SevenZFile(ParcelFileDescriptorChannel(pfd)),destDir)
|
||||
}
|
||||
@SuppressLint("NewApi")
|
||||
fun un7zToPath(fileChannel: FileChannel, path: String){
|
||||
un7zToPath(SevenZFile(fileChannel),path)
|
||||
fun un7zToPath(fileChannel: FileChannel, destDir: File?){
|
||||
un7zToPath(SevenZFile(fileChannel),destDir)
|
||||
}
|
||||
fun un7zToPath(file: File, path: String){
|
||||
un7zToPath(SevenZFile(file),path)
|
||||
fun un7zToPath(file: File, destDir: File?){
|
||||
un7zToPath(SevenZFile(file),destDir)
|
||||
}
|
||||
fun un7zToPath(filePath: String, destDir: File?){
|
||||
un7zToPath(SevenZFile(File(filePath)),destDir)
|
||||
}
|
||||
|
||||
|
||||
fun un7zToPath(sevenZFile:SevenZFile, path: String){
|
||||
fun un7zToPath(sevenZFile:SevenZFile, destDir: File?){
|
||||
var entry: SevenZArchiveEntry
|
||||
while (sevenZFile.nextEntry.also { entry=it }!=null){
|
||||
val entryFile = File(path, entry.name)
|
||||
val entryFile = File(destDir, entry.name)
|
||||
if (entry.isDirectory) {
|
||||
if (!entryFile.exists()) {
|
||||
entryFile.mkdirs()
|
||||
|
||||
Reference in New Issue
Block a user