mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-10 20:15:52 +01:00
Patch APKTool to allow repeated entry offsets to appear
This commit is contained in:
parent
23486830a9
commit
88eed24625
4
.gitignore
vendored
4
.gitignore
vendored
@ -15,6 +15,7 @@ bin/
|
||||
# Tmp Files
|
||||
*.kate-swp
|
||||
*~
|
||||
*.DS_Store
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
@ -23,3 +24,6 @@ bin/
|
||||
|
||||
# gradle/smali-patches patch smali/ into brut.apktool.smali/
|
||||
brut.apktool.smali/
|
||||
|
||||
# Patches
|
||||
*.patch
|
@ -127,6 +127,9 @@ public class Main {
|
||||
if (cli.hasOption("force-manifest")) {
|
||||
decoder.setForceDecodeManifest(ApkDecoder.FORCE_DECODE_MANIFEST_FULL);
|
||||
}
|
||||
if (cli.hasOption("manifest-only")) {
|
||||
decoder.setManifestOnly(true);
|
||||
}
|
||||
if (cli.hasOption("no-assets")) {
|
||||
decoder.setDecodeAssets(ApkDecoder.DECODE_ASSETS_NONE);
|
||||
}
|
||||
@ -294,6 +297,11 @@ public class Main {
|
||||
.desc("Decode the APK's compiled manifest, even if decoding of resources is set to \"false\".")
|
||||
.build();
|
||||
|
||||
Option manifestOnlyOption = Option.builder("mo")
|
||||
.longOpt("manifest-only")
|
||||
.desc("Only decode manifest.")
|
||||
.build();
|
||||
|
||||
Option noAssetOption = Option.builder()
|
||||
.longOpt("no-assets")
|
||||
.desc("Do not decode assets.")
|
||||
@ -431,6 +439,7 @@ public class Main {
|
||||
DecodeOptions.addOption(forceDecOption);
|
||||
DecodeOptions.addOption(noSrcOption);
|
||||
DecodeOptions.addOption(noResOption);
|
||||
DecodeOptions.addOption(manifestOnlyOption);
|
||||
|
||||
// add basic build options
|
||||
BuildOptions.addOption(outputBuiOption);
|
||||
|
@ -100,6 +100,13 @@ public class ApkDecoder {
|
||||
|
||||
LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + mApkFile.getName());
|
||||
|
||||
if (mManifestOnly) {
|
||||
setAnalysisMode(mAnalysisMode, true);
|
||||
mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable());
|
||||
writeMetaFile();
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasResources()) {
|
||||
switch (mDecodeResources) {
|
||||
case DECODE_RESOURCES_NONE:
|
||||
@ -125,7 +132,7 @@ public class ApkDecoder {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// if there's no resources.asrc, decode the manifest without looking
|
||||
// if there's no resources.arsc, decode the manifest without looking
|
||||
// up attribute references
|
||||
if (hasManifest()) {
|
||||
if (mDecodeResources == DECODE_RESOURCES_FULL
|
||||
@ -242,6 +249,10 @@ public class ApkDecoder {
|
||||
mForceDelete = forceDelete;
|
||||
}
|
||||
|
||||
public void setManifestOnly(boolean manifestOnly) {
|
||||
mManifestOnly = manifestOnly;
|
||||
}
|
||||
|
||||
public void setFrameworkTag(String tag) throws AndrolibException {
|
||||
mAndrolib.apkOptions.frameworkTag = tag;
|
||||
}
|
||||
@ -416,7 +427,7 @@ public class ApkDecoder {
|
||||
}
|
||||
|
||||
private void putFileCompressionInfo(MetaInfo meta) throws AndrolibException {
|
||||
if (!mUncompressedFiles.isEmpty()) {
|
||||
if (mUncompressedFiles != null && !mUncompressedFiles.isEmpty()) {
|
||||
meta.doNotCompress = mUncompressedFiles;
|
||||
}
|
||||
}
|
||||
@ -437,6 +448,7 @@ public class ApkDecoder {
|
||||
private short mForceDecodeManifest = FORCE_DECODE_MANIFEST_NONE;
|
||||
private short mDecodeAssets = DECODE_ASSETS_FULL;
|
||||
private boolean mForceDelete = false;
|
||||
private boolean mManifestOnly = false;
|
||||
private boolean mKeepBrokenResources = false;
|
||||
private boolean mBakDeb = true;
|
||||
private Collection<String> mUncompressedFiles;
|
||||
|
@ -223,33 +223,55 @@ public class ARSCDecoder {
|
||||
}
|
||||
|
||||
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
|
||||
HashMap<Integer, EntryData> offsetsToEntryData =
|
||||
new HashMap<Integer, EntryData>();
|
||||
|
||||
for (int offset : entryOffsets) {
|
||||
if (offset == -1 || offsetsToEntryData.containsKey(offset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
offsetsToEntryData.put(offset, readEntryData());
|
||||
}
|
||||
|
||||
for (int i = 0; i < entryOffsets.length; i++) {
|
||||
if (entryOffsets[i] != -1) {
|
||||
mMissingResSpecs[i] = false;
|
||||
mResId = (mResId & 0xffff0000) | i;
|
||||
readEntry();
|
||||
EntryData entryData = offsetsToEntryData.get(entryOffsets[i]);
|
||||
readEntry(entryData);
|
||||
}
|
||||
}
|
||||
|
||||
return mType;
|
||||
}
|
||||
|
||||
private void readEntry() throws IOException, AndrolibException {
|
||||
private class EntryData {
|
||||
public short mFlags;
|
||||
public int mSpecNamesId;
|
||||
public ResValue mValue;
|
||||
}
|
||||
|
||||
private EntryData readEntryData() throws IOException, AndrolibException {
|
||||
short size = mIn.readShort();
|
||||
if (size < 0) {
|
||||
throw new AndrolibException("Entry size is under 0 bytes.");
|
||||
}
|
||||
|
||||
short flags = mIn.readShort();
|
||||
int specNamesId = mIn.readInt();
|
||||
|
||||
// If we are here, we probably already inserted any remaining dummy resources. No need to parse
|
||||
// any resources that doesn't have type information
|
||||
if (mCountIn.getCount() == mHeader.endPosition) {
|
||||
return;
|
||||
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry();
|
||||
EntryData entryData = new EntryData();
|
||||
entryData.mFlags = flags;
|
||||
entryData.mSpecNamesId = specNamesId;
|
||||
entryData.mValue = value;
|
||||
return entryData;
|
||||
}
|
||||
|
||||
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry();
|
||||
private void readEntry(EntryData entryData) throws AndrolibException {
|
||||
short flags = entryData.mFlags;
|
||||
int specNamesId = entryData.mSpecNamesId;
|
||||
ResValue value = entryData.mValue;
|
||||
|
||||
if (mTypeSpec.isString() && value instanceof ResFileValue) {
|
||||
value = new ResStringValue(value.toString(), ((ResFileValue) value).getRawIntValue());
|
||||
|
Loading…
Reference in New Issue
Block a user