From eeeb061925de0ba58d8cc832fec6ecc32a8fb045 Mon Sep 17 00:00:00 2001 From: REAndroid Date: Fri, 30 Dec 2022 11:45:25 -0500 Subject: [PATCH] Implement XML bag entry decoder --- .../lib/apk/ApkModuleXmlDecoder.java | 22 ++--- .../lib/apk/xmldecoder/BagDecoder.java | 32 ++++++++ .../lib/apk/xmldecoder/XMLArrayDecoder.java | 66 +++++++++++++++ .../lib/apk/xmldecoder/XMLAttrDecoder.java | 80 +++++++++++++++++++ .../lib/apk/xmldecoder/XMLBagDecoder.java | 49 ++++++++++++ .../apk/xmldecoder/XMLCommonBagDecoder.java | 72 +++++++++++++++++ .../lib/apk/xmldecoder/XMLPluralsDecoder.java | 77 ++++++++++++++++++ 7 files changed, 388 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/reandroid/lib/apk/xmldecoder/BagDecoder.java create mode 100644 src/main/java/com/reandroid/lib/apk/xmldecoder/XMLArrayDecoder.java create mode 100644 src/main/java/com/reandroid/lib/apk/xmldecoder/XMLAttrDecoder.java create mode 100644 src/main/java/com/reandroid/lib/apk/xmldecoder/XMLBagDecoder.java create mode 100644 src/main/java/com/reandroid/lib/apk/xmldecoder/XMLCommonBagDecoder.java create mode 100644 src/main/java/com/reandroid/lib/apk/xmldecoder/XMLPluralsDecoder.java diff --git a/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java b/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java index 33ae279..35b8465 100644 --- a/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java +++ b/src/main/java/com/reandroid/lib/apk/ApkModuleXmlDecoder.java @@ -15,6 +15,7 @@ */ package com.reandroid.lib.apk; +import com.reandroid.lib.apk.xmldecoder.XMLBagDecoder; import com.reandroid.lib.arsc.chunk.PackageBlock; import com.reandroid.lib.arsc.chunk.TableBlock; import com.reandroid.lib.arsc.chunk.TypeBlock; @@ -22,10 +23,7 @@ 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.arsc.value.*; import com.reandroid.lib.common.EntryStore; import com.reandroid.lib.common.Frameworks; import com.reandroid.lib.common.TableEntryStore; @@ -42,6 +40,7 @@ import java.util.*; public class ApkModuleXmlDecoder { private final ApkModule apkModule; private final Map> decodedEntries; + private XMLBagDecoder xmlBagDecoder; public ApkModuleXmlDecoder(ApkModule apkModule){ this.apkModule=apkModule; this.decodedEntries = new HashMap<>(); @@ -53,6 +52,7 @@ import java.util.*; entryStore.add(Frameworks.getAndroid()); TableBlock tableBlock=apkModule.getTableBlock(); entryStore.add(tableBlock); + xmlBagDecoder=new XMLBagDecoder(entryStore); decodeAndroidManifest(entryStore, outDir); logMessage("Decoding resource files ..."); List resFileList=apkModule.listResFiles(); @@ -183,9 +183,12 @@ import java.util.*; } private XMLElement decodeValue(EntryStore entryStore, EntryBlock entryBlock){ XMLElement element=new XMLElement(entryBlock.getTypeName()); - element.setResourceId(entryBlock.getResourceId()); + int resourceId=entryBlock.getResourceId(); + XMLAttribute attribute=new XMLAttribute("name", entryBlock.getName()); + element.addAttribute(attribute); + attribute.setNameId(resourceId); + element.setResourceId(resourceId); if(!entryBlock.isEntryTypeBag()){ - String name=entryBlock.getName(); String value; ResValueInt resValueInt=(ResValueInt) entryBlock.getResValue(); if(resValueInt.getValueType()== ValueType.STRING){ @@ -196,12 +199,11 @@ import java.util.*; resValueInt.getValueType(), resValueInt.getData()); } - XMLAttribute attribute=new XMLAttribute("name", name); - element.addAttribute(attribute); element.setTextContent(value); }else { - // TODO: implement bags entry decoder - return null; + ResValueBag resValueBag=(ResValueBag) entryBlock.getResValue(); + xmlBagDecoder.decode(resValueBag, element); + return element; } return element; } diff --git a/src/main/java/com/reandroid/lib/apk/xmldecoder/BagDecoder.java b/src/main/java/com/reandroid/lib/apk/xmldecoder/BagDecoder.java new file mode 100644 index 0000000..f0a2c56 --- /dev/null +++ b/src/main/java/com/reandroid/lib/apk/xmldecoder/BagDecoder.java @@ -0,0 +1,32 @@ + /* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.lib.apk.xmldecoder; + +import com.reandroid.lib.arsc.value.ResValueBag; +import com.reandroid.lib.common.EntryStore; +import com.reandroid.xml.XMLElement; + +abstract class BagDecoder { + private final EntryStore entryStore; + public BagDecoder(EntryStore entryStore){ + this.entryStore=entryStore; + } + EntryStore getEntryStore(){ + return entryStore; + } + public abstract void decode(ResValueBag resValueBag, XMLElement parentElement); + public abstract boolean canDecode(ResValueBag resValueBag); +} diff --git a/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLArrayDecoder.java b/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLArrayDecoder.java new file mode 100644 index 0000000..f56e49f --- /dev/null +++ b/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLArrayDecoder.java @@ -0,0 +1,66 @@ + /* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.lib.apk.xmldecoder; + +import com.reandroid.lib.arsc.decoder.ValueDecoder; +import com.reandroid.lib.arsc.value.ResValueBag; +import com.reandroid.lib.arsc.value.ResValueBagItem; +import com.reandroid.lib.common.EntryStore; +import com.reandroid.xml.XMLElement; + +class XMLArrayDecoder extends BagDecoder{ + public XMLArrayDecoder(EntryStore entryStore) { + super(entryStore); + } + + @Override + public void decode(ResValueBag resValueBag, XMLElement parentElement) { + ResValueBagItem[] bagItems = resValueBag.getBagItems(); + EntryStore entryStore=getEntryStore(); + for(int i=0;i decoderList; + private final XMLCommonBagDecoder commonBagDecoder; + public XMLBagDecoder(EntryStore entryStore){ + this.entryStore=entryStore; + this.decoderList=new ArrayList<>(); + this.decoderList.add(new XMLAttrDecoder(entryStore)); + this.decoderList.add(new XMLPluralsDecoder(entryStore)); + this.decoderList.add(new XMLArrayDecoder(entryStore)); + this.commonBagDecoder = new XMLCommonBagDecoder(entryStore); + } + public void decode(ResValueBag resValueBag, XMLElement parentElement){ + BagDecoder bagDecoder=getFor(resValueBag); + bagDecoder.decode(resValueBag, parentElement); + } + private BagDecoder getFor(ResValueBag resValueBag){ + for(BagDecoder bagDecoder:decoderList){ + if(bagDecoder.canDecode(resValueBag)){ + return bagDecoder; + } + } + return commonBagDecoder; + } +} diff --git a/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLCommonBagDecoder.java b/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLCommonBagDecoder.java new file mode 100644 index 0000000..1dd1928 --- /dev/null +++ b/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLCommonBagDecoder.java @@ -0,0 +1,72 @@ + /* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.lib.apk.xmldecoder; + +import com.reandroid.lib.arsc.chunk.PackageBlock; +import com.reandroid.lib.arsc.decoder.ValueDecoder; +import com.reandroid.lib.arsc.value.ResValueBag; +import com.reandroid.lib.arsc.value.ResValueBagItem; +import com.reandroid.lib.arsc.value.ValueType; +import com.reandroid.lib.common.EntryStore; +import com.reandroid.xml.XMLElement; + +class XMLCommonBagDecoder extends BagDecoder{ + public XMLCommonBagDecoder(EntryStore entryStore) { + super(entryStore); + } + + @Override + public void decode(ResValueBag resValueBag, XMLElement parentElement) { + + PackageBlock currentPackage=resValueBag + .getEntryBlock().getPackageBlock(); + + int parentId = resValueBag.getParentId(); + String parent; + if(parentId!=0){ + parent = ValueDecoder.decodeEntryValue(getEntryStore(), + currentPackage, ValueType.REFERENCE, parentId); + }else { + parent=null; + } + if(parent!=null){ + parentElement.setAttribute("parent", parent); + } + int currentPackageId=currentPackage.getId(); + ResValueBagItem[] bagItems = resValueBag.getBagItems(); + EntryStore entryStore = getEntryStore(); + for(int i=0;i< bagItems.length;i++){ + ResValueBagItem item=bagItems[i]; + int resourceId=item.getId(); + XMLElement child=new XMLElement("item"); + String name = ValueDecoder.decodeAttributeName( + entryStore, currentPackage, item.getId()); + + child.setAttribute("name", name); + + String value = ValueDecoder.decode(entryStore, currentPackageId, + resourceId, item.getValueType(), item.getData()); + + child.setTextContent(value); + + parentElement.addChild(child); + } + } + @Override + public boolean canDecode(ResValueBag resValueBag) { + return resValueBag!=null; + } +} diff --git a/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLPluralsDecoder.java b/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLPluralsDecoder.java new file mode 100644 index 0000000..8d6dc56 --- /dev/null +++ b/src/main/java/com/reandroid/lib/apk/xmldecoder/XMLPluralsDecoder.java @@ -0,0 +1,77 @@ + /* + * Copyright (C) 2022 github.com/REAndroid + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.reandroid.lib.apk.xmldecoder; + +import com.reandroid.lib.arsc.decoder.ValueDecoder; +import com.reandroid.lib.arsc.value.BaseResValue; +import com.reandroid.lib.arsc.value.ResValueBag; +import com.reandroid.lib.arsc.value.ResValueBagItem; +import com.reandroid.lib.arsc.value.plurals.PluralsQuantity; +import com.reandroid.lib.common.EntryStore; +import com.reandroid.xml.XMLElement; + +class XMLPluralsDecoder extends BagDecoder{ + public XMLPluralsDecoder(EntryStore entryStore) { + super(entryStore); + } + @Override + public void decode(ResValueBag resValueBag, XMLElement parentElement) { + ResValueBagItem[] bagItems = resValueBag.getBagItems(); + int len=bagItems.length; + EntryStore entryStore=getEntryStore(); + for(int i=0;i