mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-14 16:24:34 -05:00
Lint
This commit is contained in:
@@ -102,6 +102,7 @@ object Extension {
|
||||
jarSavePath
|
||||
}
|
||||
}
|
||||
|
||||
apkUrl != null -> {
|
||||
installAPK {
|
||||
val apkName = Uri.parse(apkUrl).lastPathSegment!!
|
||||
@@ -112,7 +113,10 @@ object Extension {
|
||||
apkSavePath
|
||||
}
|
||||
}
|
||||
else -> throw NullPointerException("Could not find extension url for $pkgName")
|
||||
|
||||
else -> {
|
||||
throw NullPointerException("Could not find extension url for $pkgName")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +251,7 @@ object Extension {
|
||||
pkgName,
|
||||
packageInfo.versionName,
|
||||
packageInfo.versionCode,
|
||||
contentWarning
|
||||
contentWarning,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
// free up the file descriptor if exists
|
||||
@@ -270,16 +274,19 @@ object Extension {
|
||||
): String {
|
||||
val jarFile = Path(fetcher())
|
||||
|
||||
val jarZip = ZipFile.builder()
|
||||
.setPath(jarFile)
|
||||
.get()
|
||||
|
||||
val jarZip =
|
||||
ZipFile
|
||||
.builder()
|
||||
.setPath(jarFile)
|
||||
.get()
|
||||
|
||||
return jarZip.use { jarZip ->
|
||||
val manifest = jarZip.getInputStream(jarZip.getEntry("AndroidManifest.xml"))
|
||||
.use {
|
||||
AndroidManifestParser.parse(it)
|
||||
}
|
||||
val manifest =
|
||||
jarZip
|
||||
.getInputStream(jarZip.getEntry("AndroidManifest.xml"))
|
||||
.use {
|
||||
AndroidManifestParser.parse(it)
|
||||
}
|
||||
val pkgName = manifest.packageName
|
||||
|
||||
// check if we don't have the extension already installed
|
||||
@@ -316,20 +323,23 @@ object Extension {
|
||||
// throw Exception("This apk is not a signed with the official tachiyomi signature")
|
||||
// }
|
||||
|
||||
fun List<AndroidManifestParser.MetaData>.getString(name: String): String? {
|
||||
return this.find { it.name == name }?.value
|
||||
}
|
||||
fun List<AndroidManifestParser.MetaData>.getString(name: String): String? = this.find { it.name == name }?.value
|
||||
|
||||
var contentWarning = manifest.application!!.metaData.getString(METADATA_CONTENT_WARNING)
|
||||
?.toIntOrNull()
|
||||
var contentWarning =
|
||||
manifest.application!!
|
||||
.metaData
|
||||
.getString(METADATA_CONTENT_WARNING)
|
||||
?.toIntOrNull()
|
||||
if (contentWarning == null) {
|
||||
contentWarning = manifest.application.metaData.getString(METADATA_NSFW)
|
||||
contentWarning = manifest.application.metaData
|
||||
.getString(METADATA_NSFW)
|
||||
?.toIntOrNull()
|
||||
?: 0
|
||||
}
|
||||
|
||||
val sourceClass =
|
||||
manifest.application.metaData.getString(METADATA_SOURCE_CLASS)!!
|
||||
manifest.application.metaData
|
||||
.getString(METADATA_SOURCE_CLASS)!!
|
||||
.trim()
|
||||
|
||||
val className =
|
||||
@@ -364,7 +374,7 @@ object Extension {
|
||||
pkgName,
|
||||
manifest.versionName,
|
||||
manifest.versionCode!!,
|
||||
contentWarning
|
||||
contentWarning,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
// free up the file descriptor if exists
|
||||
@@ -373,7 +383,8 @@ object Extension {
|
||||
|
||||
try {
|
||||
uninstallExtension(pkgName)
|
||||
} catch (_: Exception) {}
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -409,7 +420,6 @@ object Extension {
|
||||
else -> "all"
|
||||
}
|
||||
|
||||
|
||||
// update extension info
|
||||
transaction {
|
||||
if (ExtensionTable.selectAll().where { ExtensionTable.pkgName eq pkgName }.firstOrNull() == null) {
|
||||
|
||||
@@ -22,21 +22,16 @@ object AndroidManifestParser {
|
||||
data class AndroidManifest(
|
||||
@XmlSerialName("package", "", "")
|
||||
val packageName: String,
|
||||
|
||||
@XmlSerialName("versionCode", ANDROID_NS, "android")
|
||||
val versionCode: Int? = null,
|
||||
|
||||
@XmlSerialName("versionName", ANDROID_NS, "android")
|
||||
val versionName: String? = null,
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("uses-sdk", "", "")
|
||||
val usesSdk: UsesSdk? = null,
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("uses-feature", "", "")
|
||||
val usesFeatures: List<UsesFeature> = emptyList(),
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("application", "", "")
|
||||
val application: Application? = null,
|
||||
@@ -47,7 +42,6 @@ object AndroidManifestParser {
|
||||
data class UsesSdk(
|
||||
@XmlSerialName("minSdkVersion", ANDROID_NS, "android")
|
||||
val minSdkVersion: Int? = null,
|
||||
|
||||
@XmlSerialName("targetSdkVersion", ANDROID_NS, "android")
|
||||
val targetSdkVersion: Int? = null,
|
||||
)
|
||||
@@ -64,20 +58,15 @@ object AndroidManifestParser {
|
||||
data class Application(
|
||||
@XmlSerialName("label", ANDROID_NS, "android")
|
||||
val label: String? = null,
|
||||
|
||||
@XmlSerialName("icon", ANDROID_NS, "android")
|
||||
val icon: String? = null,
|
||||
|
||||
@XmlSerialName("allowBackup", ANDROID_NS, "android")
|
||||
val allowBackup: Boolean? = null,
|
||||
|
||||
@XmlSerialName("extractNativeLibs", ANDROID_NS, "android")
|
||||
val extractNativeLibs: Boolean? = null,
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("meta-data", "", "")
|
||||
val metaData: List<MetaData> = emptyList(),
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("activity", "", "")
|
||||
val activities: List<Activity> = emptyList(),
|
||||
@@ -88,10 +77,8 @@ object AndroidManifestParser {
|
||||
data class MetaData(
|
||||
@XmlSerialName("name", ANDROID_NS, "android")
|
||||
val name: String,
|
||||
|
||||
@XmlSerialName("value", ANDROID_NS, "android")
|
||||
val value: String? = null,
|
||||
|
||||
@XmlSerialName("resource", ANDROID_NS, "android")
|
||||
val resource: String? = null,
|
||||
)
|
||||
@@ -101,13 +88,10 @@ object AndroidManifestParser {
|
||||
data class Activity(
|
||||
@XmlSerialName("name", ANDROID_NS, "android")
|
||||
val name: String,
|
||||
|
||||
@XmlSerialName("exported", ANDROID_NS, "android")
|
||||
val exported: Boolean? = null,
|
||||
|
||||
@XmlSerialName("theme", ANDROID_NS, "android")
|
||||
val theme: String? = null,
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("intent-filter", "", "")
|
||||
val intentFilters: List<IntentFilter> = emptyList(),
|
||||
@@ -119,11 +103,9 @@ object AndroidManifestParser {
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("action", "", "")
|
||||
val actions: List<Action> = emptyList(),
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("category", "", "")
|
||||
val categories: List<Category> = emptyList(),
|
||||
|
||||
@XmlElement(true)
|
||||
@XmlSerialName("data", "", "")
|
||||
val data: List<Data> = emptyList(),
|
||||
@@ -148,24 +130,22 @@ object AndroidManifestParser {
|
||||
data class Data(
|
||||
@XmlSerialName("scheme", ANDROID_NS, "android")
|
||||
val scheme: String? = null,
|
||||
|
||||
@XmlSerialName("host", ANDROID_NS, "android")
|
||||
val host: String? = null,
|
||||
|
||||
@XmlSerialName("pathPattern", ANDROID_NS, "android")
|
||||
val pathPattern: String? = null,
|
||||
)
|
||||
|
||||
private val xml = XML {
|
||||
autoPolymorphic = false
|
||||
repairNamespaces = true
|
||||
xmlDeclMode = XmlDeclMode.Minimal
|
||||
defaultPolicy {
|
||||
unknownChildHandler = UnknownChildHandler { _, _, _, _, _ -> emptyList() }
|
||||
private val xml =
|
||||
XML {
|
||||
autoPolymorphic = false
|
||||
repairNamespaces = true
|
||||
xmlDeclMode = XmlDeclMode.Minimal
|
||||
defaultPolicy {
|
||||
unknownChildHandler = UnknownChildHandler { _, _, _, _, _ -> emptyList() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalXmlUtilApi::class)
|
||||
fun parse(input: InputStream): AndroidManifest =
|
||||
xml.decodeFromReader(AndroidManifest.serializer(), KtXmlReader(input))
|
||||
fun parse(input: InputStream): AndroidManifest = xml.decodeFromReader(AndroidManifest.serializer(), KtXmlReader(input))
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ object PackageTools {
|
||||
}
|
||||
|
||||
/** A modified version of `xyz.nulldev.androidcompat.pm.InstalledPackage.info` */
|
||||
fun getPackageInfo(apkFile: Path): PackageInfo {
|
||||
return ApkParsers.getMetaInfo(apkFile.toFile()).toPackageInfo(apkFile.toFile()).apply {
|
||||
fun getPackageInfo(apkFile: Path): PackageInfo =
|
||||
ApkParsers.getMetaInfo(apkFile.toFile()).toPackageInfo(apkFile.toFile()).apply {
|
||||
val parsed = ApkFile(apkFile.toFile())
|
||||
val dbFactory = DocumentBuilderFactory.newInstance()
|
||||
val dBuilder = dbFactory.newDocumentBuilder()
|
||||
@@ -137,7 +137,6 @@ object PackageTools {
|
||||
.map { Signature(it.data) }
|
||||
.toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSignatureHash(pkgInfo: PackageInfo): String? {
|
||||
val signatures = pkgInfo.signatures
|
||||
|
||||
@@ -18,19 +18,23 @@ object ResourceArscIconParser {
|
||||
|
||||
fun extractIcon(
|
||||
jar: Path,
|
||||
iconPath: Path
|
||||
iconPath: Path,
|
||||
) {
|
||||
ZipFile.builder()
|
||||
ZipFile
|
||||
.builder()
|
||||
.setPath(jar)
|
||||
.get()
|
||||
.use { zip ->
|
||||
val packages = zip.getInputStream(zip.getEntry("resources.arsc"))
|
||||
.use { ArscParser(it.readBytes()).parse() }
|
||||
val packages =
|
||||
zip
|
||||
.getInputStream(zip.getEntry("resources.arsc"))
|
||||
.use { ArscParser(it.readBytes()).parse() }
|
||||
|
||||
val icon = packages
|
||||
.flatMap { it.iconCandidates() }
|
||||
.maxByOrNull { it.density }
|
||||
?: return
|
||||
val icon =
|
||||
packages
|
||||
.flatMap { it.iconCandidates() }
|
||||
.maxByOrNull { it.density }
|
||||
?: return
|
||||
|
||||
val entry = zip.getEntry(icon.path) ?: return
|
||||
|
||||
@@ -42,19 +46,21 @@ object ResourceArscIconParser {
|
||||
}
|
||||
}
|
||||
|
||||
fun extractIcon(
|
||||
zip: ZipFile,
|
||||
): InputStream {
|
||||
val packages = zip.getInputStream(zip.getEntry("resources.arsc"))
|
||||
.use { ArscParser(it.readBytes()).parse() }
|
||||
fun extractIcon(zip: ZipFile): InputStream {
|
||||
val packages =
|
||||
zip
|
||||
.getInputStream(zip.getEntry("resources.arsc"))
|
||||
.use { ArscParser(it.readBytes()).parse() }
|
||||
|
||||
val icon = packages
|
||||
.flatMap { it.iconCandidates() }
|
||||
.maxByOrNull { it.density }
|
||||
?: throw NullPointerException("No valid icons")
|
||||
val icon =
|
||||
packages
|
||||
.flatMap { it.iconCandidates() }
|
||||
.maxByOrNull { it.density }
|
||||
?: throw NullPointerException("No valid icons")
|
||||
|
||||
val entry = zip.getEntry(icon.path)
|
||||
?: throw NullPointerException("Icon ${icon.path} missing")
|
||||
val entry =
|
||||
zip.getEntry(icon.path)
|
||||
?: throw NullPointerException("Icon ${icon.path} missing")
|
||||
|
||||
return zip.getInputStream(entry)
|
||||
}
|
||||
@@ -76,19 +82,22 @@ object ResourceArscIconParser {
|
||||
}
|
||||
|
||||
private fun Config.density(): Int =
|
||||
ByteBuffer.wrap(id)
|
||||
ByteBuffer
|
||||
.wrap(id)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.getShort(14)
|
||||
.toInt() and 0xffff
|
||||
|
||||
private val rasterExtensions = setOf(
|
||||
"png",
|
||||
"webp",
|
||||
"jpg",
|
||||
"jpeg",
|
||||
)
|
||||
private val rasterExtensions =
|
||||
setOf(
|
||||
"png",
|
||||
"webp",
|
||||
"jpg",
|
||||
"jpeg",
|
||||
)
|
||||
|
||||
private fun isRasterImage(path: String): Boolean =
|
||||
path.substringAfterLast('.', "")
|
||||
path
|
||||
.substringAfterLast('.', "")
|
||||
.lowercase() in rasterExtensions
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile
|
||||
import pxb.android.arsc.ArscDumper
|
||||
import pxb.android.arsc.ArscParser
|
||||
import pxb.android.axml.AxmlParser
|
||||
import suwayomi.tachidesk.manga.impl.util.AndroidManifestParser
|
||||
import suwayomi.tachidesk.manga.impl.util.ResourceArscIconParser
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.test.Test
|
||||
|
||||
class JarTest {
|
||||
|
||||
@Test
|
||||
fun jarTest() {
|
||||
println(Path("./").absolutePathString())
|
||||
val jar = Path("./build/tachiyomi-all.ahottie-v1.4.3.jar")
|
||||
|
||||
val zip = ZipFile.builder()
|
||||
.setPath(jar)
|
||||
.get()
|
||||
val manifest = zip.getInputStream(zip.getEntry("AndroidManifest.xml"))
|
||||
.use {
|
||||
AndroidManifestParser.parse(it)
|
||||
}
|
||||
//
|
||||
// reader.parse()
|
||||
// println(reader.resourceTable)
|
||||
// val resourceTable = reader.resourceTable
|
||||
// println(resourceTable.stringPool)
|
||||
// //println(table.stringPool.get(1))
|
||||
// // table::class.members.forEach {
|
||||
// // if (it.name == "packageMap") {
|
||||
// // it.isAccessible = true
|
||||
// // val map = it.call(table) as Map<Short, ResourcePackage>
|
||||
// // map.forEach { short, packagz ->
|
||||
// // println(short)
|
||||
// // println(packagz.name to packagz.id)
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// val apkTranslator = ApkMetaTranslator(resourceTable, null)
|
||||
// val xmlTranslator = XmlTranslator()
|
||||
// val xmlStreamer = CompositeXmlStreamer(xmlTranslator, apkTranslator)
|
||||
// val data = zip.getInputStream(zip.getEntry("AndroidManifest.xml"))
|
||||
// .use {
|
||||
// it.readBytes()
|
||||
// }
|
||||
//
|
||||
//
|
||||
// val buffer = ByteBuffer.wrap(data)
|
||||
// val binaryXmlParser = BinaryXmlParser(buffer, resourceTable)
|
||||
// //binaryXmlParser.locale = preferredLocale
|
||||
// binaryXmlParser.xmlStreamer = xmlStreamer
|
||||
// binaryXmlParser.parse()
|
||||
// val manifestXml = xmlTranslator.xml
|
||||
// println(manifestXml)
|
||||
// val iconPaths = apkTranslator.iconPaths
|
||||
// iconPaths.forEach {
|
||||
// println(it.path)
|
||||
// }
|
||||
|
||||
// val parser = zip.getInputStream(zip.getEntry("resources.arsc"))
|
||||
// .use {
|
||||
// ArscParser(it.readBytes())
|
||||
// }
|
||||
// val parsed = parser.parse()
|
||||
// ArscDumper.dump(parsed)
|
||||
//
|
||||
// parsed.forEach {
|
||||
// print("pkg.name: ")
|
||||
// println(it.name)
|
||||
// it.types.toList().forEachIndexed { t, (i, type) ->
|
||||
// print("pkg.types.$t.type.name: ")
|
||||
// println(type.name)
|
||||
// print("pkg.types.$t.type.id: ")
|
||||
// println(type.id)
|
||||
// type.specs.forEachIndexed { y, spec ->
|
||||
// print("pkg.types.$t.type.specs.$y.id: ")
|
||||
// println(spec.id)
|
||||
// print("pkg.types.$t.type.specs.$y.name: ")
|
||||
// println(spec.name)
|
||||
// print("pkg.types.$t.type.specs.$y.flags: ")
|
||||
// println(spec.flags)
|
||||
// }
|
||||
// type.configs.forEachIndexed { y, config ->
|
||||
// print("pkg.types.$t.type.configs.$y.id: ")
|
||||
// println(config.id.toHexString(HexFormat.UpperCase))
|
||||
// print("pkg.types.$t.type.configs.$y.entryCount: ")
|
||||
// println(config.entryCount)
|
||||
// config.resources.forEach {
|
||||
// print("pkg.types.$t.type.configs.$y.resources.${it.key}.flag: ")
|
||||
// println(it.value.flag)
|
||||
// print("pkg.types.$t.type.configs.$y.resources.${it.key}.value: ")
|
||||
// println(it.value.value)
|
||||
// print("pkg.types.$t.type.configs.$y.resources.${it.key}.spec.id: ")
|
||||
// println(it.value.spec.id)
|
||||
// print("pkg.types.$t.type.configs.$y.resources.${it.key}.spec.name: ")
|
||||
// println(it.value.spec.name)
|
||||
// print("pkg.types.$t.type.configs.$y.resources.${it.key}.spec.flags: ")
|
||||
// println(it.value.spec.flags)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// val fileTest = Path("./build/icon.png")
|
||||
// ResourceArscIconParser.extractIcon(jar, fileTest)
|
||||
|
||||
println(manifest.packageName)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user