Minor bug fix

This commit is contained in:
REAndroid 2022-12-26 10:37:09 -05:00
parent c288c50c89
commit 5826eb8a47
22 changed files with 306 additions and 136 deletions

View File

@ -15,7 +15,6 @@
*/
package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.chunk.TypeBlock;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.BaseResValue;
@ -56,12 +55,27 @@ public class EntryBlockArray extends OffsetBlockArray<EntryBlock> implements JSO
public EntryBlock newInstance() {
return new EntryBlock();
}
@Override
public EntryBlock[] newInstance(int len) {
return new EntryBlock[len];
}
/**
* It is allowed to have duplicate entry name therefore it is not recommend to use this.
* Lets depreciate to warn developer
*/
@Deprecated
public EntryBlock searchByEntryName(String entryName){
if(entryName==null){
return null;
}
for(EntryBlock entryBlock:listItems()){
if(entryName.equals(entryBlock.getName())){
return entryBlock;
}
}
return null;
}
@Override
public JSONArray toJson() {
JSONArray jsonArray=new JSONArray();

View File

@ -254,6 +254,27 @@ public class SpecTypePairArray extends BlockArray<SpecTypePair>
exist.merge(typePair);
}
}
/**
* It is allowed to have duplicate type name therefore it is not recommend to use this.
* Lets depreciate to warn developer
*/
@Deprecated
public SpecTypePair searchByTypeName(String typeName){
if(typeName==null){
return null;
}
SpecTypePair[] childes=getChildes();
if(childes==null){
return null;
}
for(int i=0;i<childes.length;i++){
SpecTypePair specTypePair=childes[i];
if(typeName.equals(specTypePair.getTypeName())){
return specTypePair;
}
}
return null;
}
@Override
public int compare(SpecTypePair typePair1, SpecTypePair typePair2) {
return typePair1.compareTo(typePair2);

View File

@ -302,6 +302,21 @@ public class TypeBlockArray extends BlockArray<TypeBlock>
block.merge(typeBlock);
}
}
/**
* It is allowed to have duplicate entry name therefore it is not recommend to use this.
* Lets depreciate to warn developer
*/
@Deprecated
public EntryBlock searchByEntryName(String entryName){
if(entryName==null){
return null;
}
TypeBlock[] childes = getChildes();
if(childes==null || childes.length==0){
return null;
}
return childes[0].searchByEntryName(entryName);
}
@Override
public int compare(TypeBlock typeBlock1, TypeBlock typeBlock2) {
return typeBlock1.compareTo(typeBlock2);

View File

@ -47,8 +47,7 @@ public abstract class Block {
blockLoad.onBlockLoaded(reader, this);
}
}
public void onReadBytes(BlockReader reader) throws IOException{
protected void onReadBytes(BlockReader reader) throws IOException{
}
public final int writeBytes(OutputStream stream) throws IOException{
if(isNull()){

View File

@ -323,6 +323,14 @@ public class PackageBlock extends BaseChunk
getLibraryBlock().merge(packageBlock.getLibraryBlock());
getSpecTypePairArray().merge(packageBlock.getSpecTypePairArray());
}
/**
* It is allowed to have duplicate type name therefore it is not recommend to use this.
* Lets depreciate to warn developer
*/
@Deprecated
public SpecTypePair searchByTypeName(String typeName){
return getSpecTypePairArray().searchByTypeName(typeName);
}
@Override
public int compareTo(PackageBlock pkg) {
return Integer.compare(getId(), pkg.getId());

View File

@ -190,6 +190,14 @@ public class TypeBlock extends BaseTypeBlock
}
return getResConfig().compareTo(typeBlock.getResConfig());
}
/**
* It is allowed to have duplicate entry name therefore it is not recommend to use this.
* Lets depreciate to warn developer
*/
@Deprecated
public EntryBlock searchByEntryName(String entryName){
return getEntryBlockArray().searchByEntryName(entryName);
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();

View File

@ -15,8 +15,6 @@
*/
package com.reandroid.lib.arsc.chunk.xml;
import com.reandroid.lib.arsc.item.ResXmlString;
import com.reandroid.lib.arsc.pool.ResXmlStringPool;
import com.reandroid.lib.arsc.value.ValueType;
import java.io.File;
@ -76,10 +74,10 @@ public class AndroidManifestBlock extends ResXmlBlock{
List<ResXmlElement> permissionList = manifestElement.listElements(TAG_uses_permission);
for(ResXmlElement permission:permissionList){
ResXmlAttribute nameAttr = permission.searchAttributeByResourceId(ID_name);
if(nameAttr==null){
if(nameAttr==null||nameAttr.getValueType()!=ValueType.STRING){
continue;
}
String val=nameAttr.getValueString();
String val=nameAttr.getValueAsString();
if(val!=null){
results.add(val);
}
@ -94,10 +92,10 @@ public class AndroidManifestBlock extends ResXmlBlock{
List<ResXmlElement> permissionList = manifestElement.listElements(TAG_uses_permission);
for(ResXmlElement permission:permissionList){
ResXmlAttribute nameAttr = permission.searchAttributeByResourceId(ID_name);
if(nameAttr==null){
if(nameAttr==null || nameAttr.getValueType()!=ValueType.STRING){
continue;
}
String val=nameAttr.getValueString();
String val=nameAttr.getValueAsString();
if(val==null){
continue;
}
@ -112,87 +110,93 @@ public class AndroidManifestBlock extends ResXmlBlock{
if(manifestElement==null){
return null;
}
ResXmlElement exist=getUsesPermission(permissionName);
ResXmlElement exist = getUsesPermission(permissionName);
if(exist!=null){
return exist;
}
ResXmlElement result=manifestElement.createChildElement(TAG_uses_permission);
ResXmlElement result = manifestElement.createChildElement(TAG_uses_permission);
ResXmlAttribute attr = result.createAndroidAttribute(NAME_name, ID_name);
attr.setValueAsString(permissionName);
return result;
}
public String getPackageName(){
return getManifestAttributeString(NAME_PACKAGE);
ResXmlElement manifest=getManifestElement();
if(manifest==null){
return null;
}
ResXmlAttribute attribute = manifest.searchAttributeByName(NAME_PACKAGE);
if(attribute==null || attribute.getValueType()!=ValueType.STRING){
return null;
}
return attribute.getValueAsString();
}
public boolean setPackageName(String packageName){
return setManifestAttributeString(NAME_PACKAGE, packageName);
ResXmlElement manifestElement=getManifestElement();
if(manifestElement==null){
return false;
}
ResXmlAttribute attribute= manifestElement.searchAttributeByName(NAME_PACKAGE);
if(attribute==null){
return false;
}
attribute.setValueAsString(packageName);
return true;
}
public Integer getCompileSdkVersion(){
return getManifestAttributeInt(NAME_compileSdkVersion);
return getManifestAttributeInt(ID_compileSdkVersion);
}
public boolean setCompileSdkVersion(int val){
return setManifestAttributeInt(ID_compileSdkVersion, val);
}
public String getCompileSdkVersionCodename(){
return getManifestAttributeString(NAME_compileSdkVersionCodename);
return getManifestAttributeString(ID_compileSdkVersionCodename);
}
public boolean setCompileSdkVersionCodename(String val){
return setManifestAttributeString(ID_compileSdkVersionCodename, val);
ResXmlElement manifest=getManifestElement();
if(manifest==null){
return false;
}
ResXmlAttribute attribute = manifest.searchAttributeByResourceId(ID_compileSdkVersionCodename);
if(attribute==null){
return false;
}
attribute.setValueAsString(val);
return true;
}
public Integer getVersionCode(){
return getManifestAttributeInt(NAME_versionCode);
return getManifestAttributeInt(ID_versionCode);
}
public boolean setVersionCode(int val){
return setManifestAttributeInt(NAME_versionCode, val);
return setManifestAttributeInt(ID_versionCode, val);
}
public String getVersionName(){
return getManifestAttributeString(NAME_versionName);
return getManifestAttributeString(ID_versionName);
}
public boolean setVersionName(String packageName){
return setManifestAttributeString(NAME_versionName, packageName);
return setManifestAttributeString(ID_versionName, packageName);
}
private String getManifestAttributeString(String name){
ResXmlElement manifestElement=getManifestElement();
if(manifestElement==null){
private String getManifestAttributeString(int resourceId){
ResXmlElement manifest=getManifestElement();
if(manifest==null){
return null;
}
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
if(attribute==null){
ResXmlAttribute attribute = manifest.searchAttributeByResourceId(resourceId);
if(attribute==null || attribute.getValueType()!=ValueType.STRING){
return null;
}
int raw=attribute.getRawValue();
ResXmlStringPool pool = getStringPool();
ResXmlString resXmlString = pool.get(raw);
if(resXmlString==null){
return null;
}
return resXmlString.getHtml();
return attribute.getValueAsString();
}
private boolean setManifestAttributeString(int resId, String value){
private boolean setManifestAttributeString(int resourceId, String value){
ResXmlElement manifestElement=getManifestElement();
if(manifestElement==null){
return false;
}
ResXmlAttribute attribute= manifestElement.searchAttributeByResourceId(resId);
ResXmlAttribute attribute = manifestElement.searchAttributeByResourceId(resourceId);
if(attribute==null){
return false;
}
attribute.setValueType(ValueType.STRING);
ResXmlString resXmlString=attribute.setValueString(value);
return resXmlString!=null;
}
private boolean setManifestAttributeString(String name, String value){
ResXmlElement manifestElement=getManifestElement();
if(manifestElement==null){
return false;
}
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
if(attribute==null){
return false;
}
attribute.setValueType(ValueType.STRING);
ResXmlString resXmlString=attribute.setValueString(value);
return resXmlString!=null;
attribute.setValueAsString(value);
return true;
}
private boolean setManifestAttributeInt(int resId, int value){
ResXmlElement manifestElement=getManifestElement();
@ -203,32 +207,16 @@ public class AndroidManifestBlock extends ResXmlBlock{
if(attribute==null){
return false;
}
attribute.setValueType(ValueType.INT_DEC);
attribute.setValueString(String.valueOf(value));
attribute.setRawValue(value);
attribute.setValueAsIntegerDec(value);
return true;
}
private boolean setManifestAttributeInt(String name, int value){
ResXmlElement manifestElement=getManifestElement();
if(manifestElement==null){
return false;
}
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
if(attribute==null){
return false;
}
attribute.setValueType(ValueType.INT_DEC);
attribute.setValueString(String.valueOf(value));
attribute.setRawValue(value);
return true;
}
private Integer getManifestAttributeInt(String name){
private Integer getManifestAttributeInt(int resourceId){
ResXmlElement manifestElement=getManifestElement();
if(manifestElement==null){
return null;
}
ResXmlAttribute attribute= manifestElement.searchAttributeByName(name);
if(attribute==null){
ResXmlAttribute attribute= manifestElement.searchAttributeByResourceId(resourceId);
if(attribute==null || attribute.getValueType()!=ValueType.INT_DEC){
return null;
}
return attribute.getRawValue();
@ -324,6 +312,8 @@ public class AndroidManifestBlock extends ResXmlBlock{
public static final String NAME_name = "name";
public static final String NAME_extractNativeLibs = "extractNativeLibs";
public static final String NAME_isSplitRequired = "isSplitRequired";
public static final String NAME_value = "value";
public static final String NAME_resource = "resource";
public static final int ID_name = 0x01010003;
public static final int ID_compileSdkVersion = 0x01010572;
@ -334,6 +324,10 @@ public class AndroidManifestBlock extends ResXmlBlock{
public static final int ID_screenOrientation = 0x0101001e;
public static final int ID_extractNativeLibs = 0x010104ea;
public static final int ID_isSplitRequired = 0x01010591;
public static final int ID_value = 0x01010024;
public static final int ID_resource = 0x01010025;
public static final int ID_versionCode = 0x0101021b;
public static final int ID_versionName = 0x0101021c;
public static final String VALUE_android_intent_action_MAIN = "android.intent.action.MAIN";

View File

@ -178,22 +178,10 @@ import java.util.Set;
}
return xmlElement.getStartNamespaceByUriRef(getNamespaceReference());
}
@Deprecated
public String getValueString(){
return getString(getValueStringReference());
}
ResXmlString setValueString(String str){
ResXmlString resXmlString=getOrCreateResXmlString(str);
if(resXmlString==null){
return null;
}
int ref=resXmlString.getIndex();
setValueStringReference(ref);
if(getValueType()==ValueType.STRING){
setRawValue(ref);
setValueStringReference(ref);
}
return resXmlString;
}
public int getNameResourceID(){
return getResourceId(getNameReference());
}
@ -313,8 +301,8 @@ import java.util.Set;
setRawValue(ref);
setValueStringReference(-1);
}
public void setValueAsInteger(int val){
setValueType(ValueType.FIRST_INT);
public void setValueAsIntegerDec(int val){
setValueType(ValueType.INT_DEC);
setRawValue(val);
setValueStringReference(-1);
}
@ -362,18 +350,6 @@ import java.util.Set;
setRawValue(val);
setValueStringReference(-1);
}
private String getCompareName(){
int id=getNameResourceID();
StringBuilder builder=new StringBuilder();
if(id!=0){
builder.append("0 ");
builder.append(String.format("%08x", id));
}else {
builder.append("1 ");
builder.append(getName());
}
return builder.toString();
}
@Override
public int compareTo(ResXmlAttribute other) {
int id1=getNameResourceID();
@ -473,7 +449,7 @@ import java.util.Set;
}
static final String NAME_id = "id";
public static final String NAME_value_type = "value_type";
static final String NAME_name = "name";
public static final String NAME_name = "name";
public static final String NAME_namespace_uri = "namespace_uri";
public static final String NAME_data= "data";
}

View File

@ -88,6 +88,21 @@ public class SpecTypePair extends BlockContainer<Block>
mSpecBlock.setTypeId(id);
mTypeBlockArray.setTypeId(id);
}
public String getTypeName(){
TypeString typeString = getTypeString();
if(typeString!=null){
return typeString.get();
}
return null;
}
/**
* It is allowed to have duplicate entry name therefore it is not recommend to use this.
* Lets depreciate to warn developer
*/
@Deprecated
public EntryBlock searchByEntryName(String entryName){
return getTypeBlockArray().searchByEntryName(entryName);
}
public SpecBlock getSpecBlock(){
return mSpecBlock;
}
@ -118,7 +133,7 @@ public class SpecTypePair extends BlockContainer<Block>
return results;
}
public Collection<TypeBlock> listTypeBlocks(){
return mTypeBlockArray.listItems();
return getTypeBlockArray().listItems();
}
@Override

View File

@ -29,7 +29,8 @@ public abstract class BlockItem extends Block {
super();
mBytes=new byte[bytesLength];
}
public abstract void onBytesChanged();
protected void onBytesChanged(){
}
protected byte[] getBytesInternal() {
return mBytes;
}

View File

@ -149,10 +149,6 @@ public class ByteArray extends BlockItem {
}
};
}
@Override
public void onBytesChanged() {
}
@Override
public String toString(){
return "size="+size();

View File

@ -44,9 +44,6 @@ public class ByteItem extends BlockItem {
return getBytesInternal()[0];
}
@Override
public void onBytesChanged() {
}
@Override
public String toString(){
return String.valueOf(get());
}

View File

@ -49,18 +49,16 @@ public class IntegerArray extends BlockItem {
}
}
public final List<Integer> toList(){
List<Integer> results=new AbstractList<Integer>() {
return new AbstractList<Integer>() {
@Override
public Integer get(int i) {
return IntegerArray.this.get(i);
}
@Override
public int size() {
return IntegerArray.this.size();
}
};
return results;
}
public final int[] toArray(){
int s=size();
@ -112,8 +110,4 @@ public class IntegerArray extends BlockItem {
bts[i+1]= (byte) (value >>> 8 & 0xff);
bts[i]= (byte) (value & 0xff);
}
@Override
public void onBytesChanged() {
}
}

View File

@ -41,11 +41,9 @@ public class IntegerItem extends BlockItem implements ReferenceItem{
public int get(){
return mCache;
}
@Override
public void onBytesChanged() {
protected void onBytesChanged() {
// To save cpu usage, better to calculate once only when bytes changed
mCache=readIntBytes();
}
private int readIntBytes(){

View File

@ -38,7 +38,8 @@ public class ShortItem extends BlockItem {
return mCache;
}
@Override
public void onBytesChanged() {
protected void onBytesChanged() {
// To save cpu usage, better to calculate once only when bytes changed
mCache=readShortBytes();
}
private short readShortBytes(){

View File

@ -118,12 +118,11 @@ public class StringItem extends BlockItem implements JSONConvert<JSONObject> {
mUtf8=utf8;
onBytesChanged();
}
@Override
public void onBytesChanged() {
protected void onBytesChanged() {
// To save cpu/memory usage, better to decode once only when bytes changed
mCache=decodeString();
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
if(reader.available()<4){

View File

@ -254,9 +254,6 @@ public class StyleItem extends IntegerArray implements JSONConvert<JSONObject> {
return true;
}
@Override
public void onBytesChanged() {
}
@Override
public void setNull(boolean is_null){
if(!is_null){
return;

View File

@ -16,11 +16,19 @@
package com.reandroid.lib.arsc.item;
public class TypeString extends StringItem {
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.pool.TypeStringPool;
public class TypeString extends StringItem {
public TypeString(boolean utf8) {
super(utf8);
}
public byte getId(){
TypeStringPool stringPool=getTypeStringPool();
if(stringPool!=null){
return stringPool.idOf(this);
}
// Should not reach here , this means it not added to string pool
return (byte) (getIndex()+1);
}
@Override
@ -28,4 +36,14 @@ public class TypeString extends StringItem {
// Type don't have style unless to obfuscate/confuse other decompilers
return null;
}
private TypeStringPool getTypeStringPool(){
Block parent=this;
while (parent!=null){
if(parent instanceof TypeStringPool){
return (TypeStringPool) parent;
}
parent=parent.getParent();
}
return null;
}
}

View File

@ -144,6 +144,9 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
public List<T> listUnusedStrings(){
return getStringsArray().listUnusedStrings();
}
public Collection<T> listStrings(){
return getStringsArray().listItems();
}
public StyleArray getStyleArray(){
return mArrayStyles;
}
@ -195,7 +198,7 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
public final StringGroup<T> get(String str){
return mUniqueMap.get(str);
}
public final T getOrCreate(String str){
public T getOrCreate(String str){
StringGroup<T> group=getOrCreateGroup(str);
T[] items=group.getItems();
if(items.length==0){

View File

@ -17,20 +17,44 @@ package com.reandroid.lib.arsc.pool;
import com.reandroid.lib.arsc.array.StringArray;
import com.reandroid.lib.arsc.array.TypeStringArray;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.chunk.TypeBlock;
import com.reandroid.lib.arsc.group.StringGroup;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.TypeString;
import java.io.IOException;
public class TypeStringPool extends BaseStringPool<TypeString> {
private final IntegerItem mTypeIdOffset;
public TypeStringPool(boolean is_utf8, IntegerItem typeIdOffset) {
super(is_utf8);
this.mTypeIdOffset = typeIdOffset;
}
public byte idOf(String typeName){
return idOf(getByName(typeName));
}
/**
* Resolves id of {@link TypeBlock}
* Not recommend to use unless unless you are sure of proper pool
**/
public byte idOf(TypeString typeString){
if(typeString==null){
return 0;
}
return (byte) (typeString.getIndex()+mTypeIdOffset.get()+1);
}
/**
* Searches string entry {@link TypeBlock}
* {@param name} is name of {@link TypeBlock}
* This might not working if duplicate type names are present
**/
public TypeString getByName(String name){
for(TypeString typeString:listStrings()){
if(name.equals(typeString.get())){
return typeString;
}
}
return null;
}
public TypeString getById(int id){
int index=id-mTypeIdOffset.get()-1;
return super.get(index);
@ -42,6 +66,19 @@ public class TypeStringPool extends BaseStringPool<TypeString> {
typeString.set(typeName);
return typeString;
}
/**
* Use getOrCreate(typeId, typeName)}
**/
@Deprecated
@Override
public final TypeString getOrCreate(String str){
StringGroup<TypeString> group = get(str);
if(group==null||group.size()==0){
throw new IllegalArgumentException("Can not create TypeString (" + str
+") without type id. use getOrCreate(typeId, typeName)");
}
return group.get(0);
}
@Override
StringArray<TypeString> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
return new TypeStringArray(offsets, itemCount, itemStart, is_utf8);

View File

@ -39,9 +39,92 @@ public class FrameworkTable extends TableBlock {
private String mFrameworkTitle;
private String mFrameworkName;
private String mFrameworkVersion;
private Map<String, Map<String, EntryGroup>> mNameGroupMap;
private final Object mMapLock=new Object();
public FrameworkTable(){
super();
}
public int resolveResourceId(String typeName, String entryName){
EntryBlock entryBlock=searchEntryBlock(typeName, entryName);
if(entryBlock!=null){
return entryBlock.getResourceId();
}
return 0;
}
/**
* Loads all resource name map to memory for faster use
* Call this if you plan to search entries frequently
*/
public void loadResourceNameMap(){
synchronized (mMapLock){
if(mNameGroupMap !=null){
return;
}
Map<String, Map<String, EntryGroup>> typeMap=new HashMap<>();
for(PackageBlock packageBlock:listPackages()){
for(EntryGroup group:packageBlock.listEntryGroup()){
String type=group.getTypeName();
Map<String, EntryGroup> groupMap=typeMap.get(type);
if(groupMap==null){
groupMap=new HashMap<>();
typeMap.put(type, groupMap);
}
groupMap.put(group.getSpecName(), group);
}
}
mNameGroupMap = typeMap;
}
}
/**
* Clears resource name map from memory
*/
public void clearResourceNameMap(){
synchronized (mMapLock){
if(mNameGroupMap!=null){
mNameGroupMap.clear();
mNameGroupMap =null;
}
}
}
private boolean hasResourceGroupMap(){
synchronized (mMapLock){
return mNameGroupMap!=null;
}
}
private EntryBlock searchEntryBlockFromMap(String typeName, String entryName){
synchronized (mMapLock){
if(mNameGroupMap ==null){
return null;
}
Map<String, EntryGroup> groupMap = mNameGroupMap.get(typeName);
if(groupMap!=null){
EntryGroup group=groupMap.get(entryName);
if(group!=null){
return group.pickOne();
}
}
return null;
}
}
public EntryBlock searchEntryBlock(String typeName, String entryName){
if(hasResourceGroupMap()){
return searchEntryBlockFromMap(typeName, entryName);
}
return searchEntryBlockFromTable(typeName, entryName);
}
/**
* Since this is framework, we are sure of proper names.
*/
public EntryBlock searchEntryBlockFromTable(String typeName, String entryName){
for(PackageBlock packageBlock:listPackages()){
SpecTypePair specTypePair = packageBlock.searchByTypeName(typeName);
if(specTypePair!=null){
return specTypePair.searchByEntryName(entryName);
}
}
return null;
}
public String getFrameworkTitle(){
if(mFrameworkTitle==null){
mFrameworkTitle=loadProperty(PROP_TITLE);

View File

@ -66,10 +66,6 @@ public abstract class BaseResValue extends BlockItem implements JSONConvert<JSON
return;
}
entryBlock.addTableReference(ref);
}
@Override
public void onBytesChanged() {
}
void onDataLoaded() {