mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-01 06:34:26 +02:00
Implement resource values XML decoder
This commit is contained in:
parent
eb9d0a4651
commit
12f4d4f9d6
@ -16,36 +16,50 @@
|
||||
package com.reandroid.lib.apk;
|
||||
|
||||
import com.reandroid.lib.arsc.chunk.PackageBlock;
|
||||
import com.reandroid.lib.arsc.chunk.TableBlock;
|
||||
import com.reandroid.lib.arsc.chunk.TypeBlock;
|
||||
import com.reandroid.lib.arsc.chunk.xml.AndroidManifestBlock;
|
||||
import com.reandroid.lib.arsc.chunk.xml.ResXmlBlock;
|
||||
import com.reandroid.lib.arsc.container.SpecTypePair;
|
||||
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||
import com.reandroid.lib.arsc.value.EntryBlock;
|
||||
import com.reandroid.lib.arsc.value.ResConfig;
|
||||
import com.reandroid.lib.arsc.value.ResValueInt;
|
||||
import com.reandroid.lib.arsc.value.ValueType;
|
||||
import com.reandroid.lib.common.EntryStore;
|
||||
import com.reandroid.lib.common.Frameworks;
|
||||
import com.reandroid.lib.common.TableEntryStore;
|
||||
import com.reandroid.xml.XMLAttribute;
|
||||
import com.reandroid.xml.XMLDocument;
|
||||
import com.reandroid.xml.XMLElement;
|
||||
import com.reandroid.xml.XMLException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class ApkModuleXmlDecoder {
|
||||
public class ApkModuleXmlDecoder {
|
||||
private final ApkModule apkModule;
|
||||
private final Map<Integer, Set<ResConfig>> decodedEntries;
|
||||
public ApkModuleXmlDecoder(ApkModule apkModule){
|
||||
this.apkModule=apkModule;
|
||||
this.decodedEntries = new HashMap<>();
|
||||
}
|
||||
public void decodeTo(File outDir)
|
||||
throws IOException, XMLException {
|
||||
this.decodedEntries.clear();
|
||||
TableEntryStore entryStore=new TableEntryStore();
|
||||
entryStore.add(Frameworks.getAndroid());
|
||||
entryStore.add(apkModule.getTableBlock());
|
||||
TableBlock tableBlock=apkModule.getTableBlock();
|
||||
entryStore.add(tableBlock);
|
||||
decodeAndroidManifest(entryStore, outDir);
|
||||
logMessage("Decoding resource files ...");
|
||||
List<ResFile> resFileList=apkModule.listResFiles();
|
||||
for(ResFile resFile:resFileList){
|
||||
decodeResFile(entryStore, outDir, resFile);
|
||||
}
|
||||
decodeValues(entryStore, outDir, tableBlock);
|
||||
}
|
||||
private void decodeResFile(EntryStore entryStore, File outDir, ResFile resFile)
|
||||
throws IOException, XMLException {
|
||||
@ -73,6 +87,8 @@ public class ApkModuleXmlDecoder {
|
||||
FileOutputStream outputStream=new FileOutputStream(file);
|
||||
resFile.getInputSource().write(outputStream);
|
||||
outputStream.close();
|
||||
|
||||
addDecodedEntry(resFile.getEntryBlockList());
|
||||
}
|
||||
private void decodeResXml(EntryStore entryStore, File outDir, ResFile resFile)
|
||||
throws IOException, XMLException{
|
||||
@ -90,6 +106,8 @@ public class ApkModuleXmlDecoder {
|
||||
logVerbose("Decoding: "+path);
|
||||
XMLDocument xmlDocument=resXmlBlock.decodeToXml(entryStore, packageBlock.getId());
|
||||
xmlDocument.save(file, true);
|
||||
|
||||
addDecodedEntry(resFile.getEntryBlockList());
|
||||
}
|
||||
private void decodeAndroidManifest(EntryStore entryStore, File outDir)
|
||||
throws IOException, XMLException {
|
||||
@ -104,6 +122,90 @@ public class ApkModuleXmlDecoder {
|
||||
XMLDocument xmlDocument=manifestBlock.decodeToXml(entryStore, currentPackageId);
|
||||
xmlDocument.save(file, true);
|
||||
}
|
||||
private void addDecodedEntry(Collection<EntryBlock> entryBlockList){
|
||||
for(EntryBlock entryBlock:entryBlockList){
|
||||
addDecodedEntry(entryBlock);
|
||||
}
|
||||
}
|
||||
private void addDecodedEntry(EntryBlock entryBlock){
|
||||
if(entryBlock.isNull()){
|
||||
return;
|
||||
}
|
||||
int resourceId=entryBlock.getResourceId();
|
||||
Set<ResConfig> resConfigSet=decodedEntries.get(resourceId);
|
||||
if(resConfigSet==null){
|
||||
resConfigSet=new HashSet<>();
|
||||
decodedEntries.put(resourceId, resConfigSet);
|
||||
}
|
||||
resConfigSet.add(entryBlock.getResConfig());
|
||||
}
|
||||
private boolean containsDecodedEntry(EntryBlock entryBlock){
|
||||
Set<ResConfig> resConfigSet=decodedEntries.get(entryBlock.getResourceId());
|
||||
if(resConfigSet==null){
|
||||
return false;
|
||||
}
|
||||
return resConfigSet.contains(entryBlock.getResConfig());
|
||||
}
|
||||
private void decodeValues(EntryStore entryStore, File outDir, TableBlock tableBlock) throws IOException {
|
||||
for(PackageBlock packageBlock:tableBlock.listPackages()){
|
||||
decodeValues(entryStore, outDir, packageBlock);
|
||||
}
|
||||
}
|
||||
private void decodeValues(EntryStore entryStore, File outDir, PackageBlock packageBlock) throws IOException {
|
||||
packageBlock.sortTypes();
|
||||
for(SpecTypePair specTypePair: packageBlock.listAllSpecTypePair()){
|
||||
for(TypeBlock typeBlock:specTypePair.listTypeBlocks()){
|
||||
decodeValues(entryStore, outDir, typeBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void decodeValues(EntryStore entryStore, File outDir, TypeBlock typeBlock) throws IOException {
|
||||
XMLDocument xmlDocument = new XMLDocument("resources");
|
||||
XMLElement docElement = xmlDocument.getDocumentElement();
|
||||
for(EntryBlock entryBlock:typeBlock.listEntries(true)){
|
||||
if(containsDecodedEntry(entryBlock)){
|
||||
continue;
|
||||
}
|
||||
docElement.addChild(decodeValue(entryStore, entryBlock));
|
||||
}
|
||||
if(docElement.getChildesCount()==0){
|
||||
return;
|
||||
}
|
||||
File file=new File(outDir, typeBlock.getPackageBlock().getName());
|
||||
file=new File(file, ApkUtil.RES_DIR_NAME);
|
||||
file=new File(file, "values"+typeBlock.getQualifiers());
|
||||
String type=typeBlock.getTypeName();
|
||||
if(!type.endsWith("s")){
|
||||
type=type+"s";
|
||||
}
|
||||
file=new File(file, type+".xml");
|
||||
xmlDocument.save(file, false);
|
||||
}
|
||||
private XMLElement decodeValue(EntryStore entryStore, EntryBlock entryBlock){
|
||||
XMLElement element=new XMLElement(entryBlock.getTypeName());
|
||||
element.setResourceId(entryBlock.getResourceId());
|
||||
if(!entryBlock.isEntryTypeBag()){
|
||||
String name=entryBlock.getName();
|
||||
String value;
|
||||
ResValueInt resValueInt=(ResValueInt) entryBlock.getResValue();
|
||||
if(resValueInt.getValueType()== ValueType.STRING){
|
||||
value=resValueInt.getValueAsString();
|
||||
}else {
|
||||
value= ValueDecoder.decodeEntryValue(entryStore,
|
||||
entryBlock.getPackageBlock(),
|
||||
resValueInt.getValueType(),
|
||||
resValueInt.getData());
|
||||
}
|
||||
XMLAttribute attribute=new XMLAttribute("name", name);
|
||||
element.addAttribute(attribute);
|
||||
element.setTextContent(value);
|
||||
}else {
|
||||
// TODO: implement bags entry decoder
|
||||
return null;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
private void logMessage(String msg) {
|
||||
APKLogger apkLogger=apkModule.getApkLogger();
|
||||
if(apkLogger!=null){
|
||||
|
@ -36,6 +36,9 @@ public class ResFile {
|
||||
this.inputSource=inputSource;
|
||||
this.entryBlockList=entryBlockList;
|
||||
}
|
||||
public List<EntryBlock> getEntryBlockList(){
|
||||
return entryBlockList;
|
||||
}
|
||||
public String validateTypeDirectoryName(){
|
||||
EntryBlock entryBlock=pickOne();
|
||||
if(entryBlock==null){
|
||||
|
Loading…
x
Reference in New Issue
Block a user