Skip to content

Commit

Permalink
feat: add Dex v41 resource support for installer
Browse files Browse the repository at this point in the history
  • Loading branch information
Hamza417 committed Dec 28, 2024
1 parent d6d01d5 commit 0c29c37
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 77 deletions.
37 changes: 15 additions & 22 deletions app/src/main/java/app/simple/inure/apk/parsers/APKParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package app.simple.inure.apk.parsers
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import androidx.annotation.Nullable
import app.simple.inure.R
import app.simple.inure.apk.utils.PackageUtils.safeApplicationInfo
import app.simple.inure.constants.Extensions.isExtrasFile
Expand All @@ -13,6 +12,7 @@ import app.simple.inure.exceptions.DexClassesNotFoundException
import app.simple.inure.models.Extra
import app.simple.inure.models.Graphic
import app.simple.inure.preferences.SearchPreferences
import app.simple.inure.util.ConditionUtils.invert
import app.simple.inure.util.FileUtils
import com.android.apksig.apk.ApkFormatException
import com.android.apksig.apk.ApkUtils
Expand Down Expand Up @@ -43,7 +43,8 @@ object APKParser {
private const val MIPS = "mips"
private const val x86 = "x86"
private const val x86_64 = "x86_64"
private const val ANDROID_MANIFEST = "AndroidManifest.xml"

const val ANDROID_MANIFEST = "AndroidManifest.xml"

/**
* Fetch the install location of an APK file
Expand Down Expand Up @@ -433,39 +434,31 @@ object APKParser {
val records: MutableList<CentralDirectoryRecord> = ArrayList(expectedCdRecordCount)

for (i in 0 until expectedCdRecordCount) {
val record: CentralDirectoryRecord = CentralDirectoryRecord.getRecord(buffer)

/**
* ZIP entry ending with '/' is a directory entry. We are not interested in
* directory entries.
* ZIP entry ending with '/' is a directory entry.
*/
if (record.name.endsWith("/")) {
continue
} else {
records.add(record)
CentralDirectoryRecord.getRecord(buffer).let {
if (it.name.endsWith("/").invert()) {
records.add(it)
}
}
}



return records
}

@Throws(IOException::class, ApkFormatException::class, ZipFormatException::class)
private fun extractAndroidManifest(records: List<CentralDirectoryRecord>, logicalHeaderFileSection: DataSource): ByteBuffer {
val androidManifestCentralDirectoryRecord: CentralDirectoryRecord = findCentralDirectoryRecord(records)
val androidManifestRecord = records.find { it.name == ANDROID_MANIFEST }
?: throw ApkFormatException("$ANDROID_MANIFEST not found in APK's Central Directory")
return ByteBuffer.wrap(LocalFileRecord.getUncompressedData(
logicalHeaderFileSection, androidManifestCentralDirectoryRecord, logicalHeaderFileSection.size()))
}

@Nullable
private fun findCentralDirectoryRecord(records: List<CentralDirectoryRecord>): CentralDirectoryRecord? {
for (record in records) {
if (ANDROID_MANIFEST == record.name) {
return record
}
}
val uncompressedData = LocalFileRecord.getUncompressedData(
logicalHeaderFileSection, androidManifestRecord, logicalHeaderFileSection.size()
)

return null
return ByteBuffer.wrap(uncompressedData)
}

private fun Long.checkSizeOrThis(): Long {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,24 @@
package app.simple.inure.viewmodels.installer

import android.app.Application
import android.graphics.Color
import android.text.Spannable
import android.text.SpannableString
import android.text.Spanned
import android.text.style.ForegroundColorSpan
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import app.simple.inure.apk.parsers.ApkManifestFetcher
import app.simple.inure.apk.decoders.XMLDecoder
import app.simple.inure.apk.parsers.APKParser
import app.simple.inure.extensions.viewmodels.WrappedViewModel
import app.simple.inure.preferences.AppearancePreferences
import app.simple.inure.util.XMLUtils
import app.simple.inure.util.XMLUtils.formatXML
import app.simple.inure.util.XMLUtils.getPrettyXML
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.dongliu.apk.parser.ApkFile
import java.io.File
import java.util.regex.Matcher
import java.util.regex.Pattern
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.zip.ZipException

class InstallerManifestViewModel(application: Application, private val file: File) : WrappedViewModel(application) {

private val quotations: Pattern = Pattern.compile("\"([^\"]*)\"", Pattern.MULTILINE)

@Suppress("RegExpDuplicateAlternationBranch")
private val tags = Pattern.compile("" /*Only for indentation */ +
"<\\w+\\.+\\S+" + // <xml.yml.zml>
"|<\\w+\\.+\\S+" + // <xml.yml.zml...nthml
"|</\\w+.+>" + // </xml.yml.zml>
"|</\\w+-+\\S+>" + // </xml-yml>
"|<\\w+-+\\S+" + // <xml-yml-zml...nthml
"|</\\w+>" + // </xml>
"|</\\w+" + // </xml
"|<\\w+/>" + // <xml/>
"|<\\w+>" + // <xml>
"|<\\w+" + // <xml
"|<.\\w+" + // <?xml
"|\\?>" + // ?>
"|/>", // />
Pattern.MULTILINE or Pattern.CASE_INSENSITIVE)

private val spanned: MutableLiveData<Spanned> by lazy {
MutableLiveData<Spanned>().also {
getSpannedXml()
Expand All @@ -54,34 +32,18 @@ class InstallerManifestViewModel(application: Application, private val file: Fil
private fun getSpannedXml() {
viewModelScope.launch(Dispatchers.IO) {
kotlin.runCatching {
val formattedContent: SpannableString

val code: String = kotlin.runCatching {
ApkFile(file).use {
it.manifestXml
}
}.getOrElse {
/**
* Alternate engine for parsing manifest
*/
XMLUtils.getProperXml(ApkManifestFetcher.getManifestXmlFromFile(file)!!)!!
}

formattedContent = SpannableString(code)
val matcher: Matcher = tags.matcher(code)
while (matcher.find()) {
formattedContent.setSpan(ForegroundColorSpan(Color.parseColor("#2980B9")), matcher.start(),
matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}

matcher.usePattern(quotations)
while (matcher.find()) {
formattedContent.setSpan(ForegroundColorSpan(AppearancePreferences.getAccentColor()),
matcher.start(), matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
val code: String = try {
XMLDecoder(file)
.decode(APKParser.ANDROID_MANIFEST)
} catch (e: ZipException) {
val byteBuffer: ByteBuffer = APKParser
.getManifestByteBuffer(file)
.order(ByteOrder.LITTLE_ENDIAN)

XMLDecoder.decode(byteBuffer)
}

spanned.postValue(formattedContent)
spanned.postValue(code.formatXML().getPrettyXML())
}.getOrElse {
it.printStackTrace()
}
Expand Down

0 comments on commit 0c29c37

Please sign in to comment.