feat: finish the bag apis

This commit is contained in:
Ax333l 2023-04-08 22:22:00 +02:00
parent 2eb4e7f96d
commit b110635b47
No known key found for this signature in database
GPG Key ID: D2B4D85271127D23
11 changed files with 990 additions and 586 deletions

View File

@ -196,21 +196,12 @@
} }
private TableEntry<?, ?> ensureTableEntry(boolean is_complex){ private TableEntry<?, ?> ensureTableEntry(boolean is_complex){
TableEntry<?, ?> tableEntry = getTableEntry(); TableEntry<?, ?> tableEntry = getTableEntry();
if(tableEntry == null){
boolean is_correct_type = (is_complex && tableEntry instanceof ResTableMapEntry) || (!is_complex && tableEntry instanceof ResTableEntry);
if (tableEntry == null || !is_correct_type) {
tableEntry = createTableEntry(is_complex); tableEntry = createTableEntry(is_complex);
setTableEntry(tableEntry); setTableEntry(tableEntry);
return tableEntry;
} }
if(is_complex){
if(tableEntry instanceof ResTableMapEntry){
return tableEntry;
}
tableEntry = createTableEntry(true);
setTableEntry(tableEntry);
return tableEntry;
}
tableEntry = createTableEntry(false);
setTableEntry(tableEntry);
return tableEntry; return tableEntry;
} }

View File

@ -15,32 +15,105 @@
*/ */
package com.reandroid.arsc.value.array; package com.reandroid.arsc.value.array;
import com.reandroid.arsc.array.ResValueMapArray;
import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.Entry;
import com.reandroid.arsc.value.ResTableMapEntry; import com.reandroid.arsc.value.ResTableMapEntry;
import com.reandroid.arsc.value.ResValueMap; import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.bag.Bag;
public class ArrayBag { import java.util.AbstractList;
private final ArrayBagItem[] mBagItems; import java.util.RandomAccess;
private ArrayBag(ArrayBagItem[] bagItems){
this.mBagItems=bagItems; public class ArrayBag extends AbstractList<ArrayBagItem> implements Bag, RandomAccess {
private final Entry entry;
private ArrayBag(Entry entry) {
this.entry = entry;
} }
private ResTableMapEntry getTableEntry() {
return (ResTableMapEntry) entry.getTableEntry();
}
private ResValueMapArray getMapArray() {
return getTableEntry().getValue();
}
private void updateStructure(int regenStart) {
getTableEntry().setValuesCount(size());
modCount += 1;
if (regenStart < 1) {
return;
}
ResValueMapArray array = getMapArray();
for (int i = regenStart; i < array.childesCount(); i++) {
setIndex(array.get(i), i);
}
}
@Override
public Entry getEntry() {
return entry;
}
public ArrayBagItem[] getBagItems() { public ArrayBagItem[] getBagItems() {
return mBagItems; return toArray(new ArrayBagItem[0]);
} }
public String getName(){
Entry entry =getBagItems()[0].getBagItem().getEntry(); @Override
if(entry ==null){ public int size() {
return null; return getMapArray().childesCount();
} }
return entry.getName();
@Override
public ArrayBagItem get(int i) {
return ArrayBagItem.create(getMapArray().get(i));
} }
public String getTypeName(){
Entry entry =getBagItems()[0].getBagItem().getEntry(); @Override
if(entry ==null){ public ArrayBagItem set(int index, ArrayBagItem value) {
return null; ArrayBagItem target = get(index);
value.copyTo(target.getBagItem());
return target;
} }
return entry.getTypeName();
private void setIndex(ResValueMap valueMap, int index) {
valueMap.setNameHigh((short) 0x0100);
valueMap.setNameLow((short) (index + 1));
} }
@Override
public void add(int index, ArrayBagItem value) {
if (index < 0 || index > size()) {
throw new IndexOutOfBoundsException();
}
if (value == null) {
throw new NullPointerException("value is null");
}
ResValueMap valueMap = new ResValueMap();
setIndex(valueMap, index);
getMapArray().insertItem(index, valueMap);
value.copyTo(valueMap);
updateStructure(index);
}
@Override
public ArrayBagItem remove(int index) {
ResValueMapArray array = getMapArray();
ResValueMap target = array.getChildes()[index];
array.remove(target);
updateStructure(index);
return ArrayBagItem.copyOf(target);
}
@Override
public void clear() {
getMapArray().clearChildes();
updateStructure(-1);
}
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@ -51,9 +124,9 @@ public class ArrayBag {
builder.append(getName()); builder.append(getName());
builder.append("\">"); builder.append("\">");
ArrayBagItem[] allItems = getBagItems(); ArrayBagItem[] allItems = getBagItems();
for(int i=0;i<allItems.length;i++){ for (ArrayBagItem allItem : allItems) {
builder.append("\n "); builder.append("\n ");
builder.append(allItems[i].toString()); builder.append(allItem.toString());
} }
builder.append("\n</"); builder.append("\n</");
builder.append(type); builder.append(type);
@ -61,22 +134,26 @@ public class ArrayBag {
return builder.toString(); return builder.toString();
} }
/** The result of this is not always 100% accurate, /**
* in addition to this use your methods to cross check like type-name == "array"**/ * The result of this is not always 100% accurate,
public static boolean isArray(ResTableMapEntry mapEntry){ * in addition to this use your methods to cross check like type-name == "array"
if(mapEntry==null){ **/
public static boolean isArray(Entry entry) {
ArrayBag array = create(entry);
if (array == null) {
return false; return false;
} }
if(mapEntry.getParentId()!=0){ ResTableMapEntry tableEntry = array.getTableEntry();
if (tableEntry.getParentId() != 0) {
return false; return false;
} }
ArrayBagItem[] arrayBagItems = ArrayBagItem.create(mapEntry.listResValueMap()); ResValueMap[] items = tableEntry.listResValueMap();
if(arrayBagItems==null || arrayBagItems.length==0){ if (items.length == 0) {
return false; return false;
} }
for(int i=0;i< arrayBagItems.length; i++){
ArrayBagItem arrayBagItem = arrayBagItems[i]; for (int i = 0; i < items.length; i++) {
ResValueMap resValueMap = arrayBagItem.getBagItem(); ResValueMap resValueMap = items[i];
int name = resValueMap.getName(); int name = resValueMap.getName();
int high = (name >> 16) & 0xffff; int high = (name >> 16) & 0xffff;
if(high!=0x0100){ if(high!=0x0100){
@ -90,14 +167,10 @@ public class ArrayBag {
return true; return true;
} }
public static ArrayBag create(ResTableMapEntry mapEntry){ public static ArrayBag create(Entry entry) {
if(mapEntry==null){ if (entry == null || !entry.isComplex()) {
return null; return null;
} }
ArrayBagItem[] bagItems=ArrayBagItem.create(mapEntry.listResValueMap()); return new ArrayBag(entry);
if(bagItems==null){
return null;
}
return new ArrayBag(bagItems);
} }
} }

View File

@ -15,65 +15,24 @@
*/ */
package com.reandroid.arsc.value.array; package com.reandroid.arsc.value.array;
import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.decoder.ValueDecoder;
import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.item.StringItem;
import com.reandroid.arsc.item.TableString; import com.reandroid.arsc.item.TableString;
import com.reandroid.arsc.pool.TableStringPool;
import com.reandroid.arsc.value.Entry;
import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.ValueType; import com.reandroid.arsc.value.ValueType;
import com.reandroid.arsc.value.bag.BagItem;
import com.reandroid.arsc.value.ResValueMap;
import java.util.ArrayList; public class ArrayBagItem extends BagItem {
import java.util.List; private ArrayBagItem(ResValueMap valueMap) {
super(valueMap);
public class ArrayBagItem {
private final ResValueMap mBagItem;
public ArrayBagItem(ResValueMap bagItem){
this.mBagItem=bagItem;
}
public ResValueMap getBagItem() {
return mBagItem;
} }
public ValueType getValueType(){ private ArrayBagItem(StringItem str) {
return getBagItem().getValueType(); super(str);
} }
private TableStringPool getStringPool(){
Entry entry =getBagItem().getEntry(); private ArrayBagItem(ValueType valueType, int value) {
if(entry ==null){ super(valueType, value);
return null;
}
PackageBlock pkg = entry.getPackageBlock();
if(pkg==null){
return null;
}
TableBlock tableBlock= pkg.getTableBlock();
if(tableBlock==null){
return null;
}
return tableBlock.getTableStringPool();
}
public int getValue(){
return getBagItem().getData();
}
public boolean hasStringValue(){
return getValueType()==ValueType.STRING;
}
public boolean hasReferenceValue(){
return getValueType()==ValueType.REFERENCE;
}
public String getStringValue(){
ValueType valueType=getValueType();
if(valueType!=ValueType.STRING){
throw new IllegalArgumentException("Not STRING ValueType="+valueType);
}
TableStringPool stringPool=getStringPool();
if(stringPool==null){
return null;
}
int ref=getValue();
TableString tableString = stringPool.get(ref);
return tableString.getHtml();
} }
@Override @Override
@ -88,29 +47,49 @@ import java.util.List;
builder.append("</item>"); builder.append("</item>");
return builder.toString(); return builder.toString();
} }
public static ArrayBagItem[] create(ResValueMap[] resValueMaps){
if(resValueMaps ==null){ protected static ArrayBagItem create(ResValueMap valueMap) {
if (valueMap == null) {
return null; return null;
} }
int len= resValueMaps.length; return new ArrayBagItem(valueMap);
if(len==0){ }
public static ArrayBagItem create(ValueType valueType, int value) {
if (valueType == null || valueType == ValueType.STRING) {
return null; return null;
} }
List<ArrayBagItem> results=new ArrayList<>(); return new ArrayBagItem(valueType, value);
for(int i=0;i<len;i++){ }
ArrayBagItem item=create(resValueMaps[i]);
if(item==null){ protected static ArrayBagItem copyOf(ResValueMap resValueMap) {
ValueType valueType = resValueMap.getValueType();
if (valueType == ValueType.STRING) {
return new ArrayBagItem(resValueMap.getDataAsPoolString());
} else {
return new ArrayBagItem(valueType, resValueMap.getData());
}
}
public static ArrayBagItem encoded(ValueDecoder.EncodeResult encodeResult) {
if (encodeResult == null) {
return null; return null;
} }
results.add(item); return create(encodeResult.valueType, encodeResult.value);
} }
return results.toArray(new ArrayBagItem[0]);
public static ArrayBagItem integer(int n) {
return create(ValueType.INT_DEC, n);
} }
public static ArrayBagItem create(ResValueMap resValueMap){
if(resValueMap ==null){ public static ArrayBagItem string(TableString str) {
if (str == null) {
return null; return null;
} }
ArrayBagItem item=new ArrayBagItem(resValueMap); return new ArrayBagItem(str);
return item; }
public static ArrayBagItem reference(int resourceId) {
return create(ValueType.REFERENCE, resourceId);
} }
} }

View File

@ -0,0 +1,21 @@
package com.reandroid.arsc.value.bag;
import com.reandroid.arsc.value.Entry;
public interface Bag {
Entry getEntry();
default String getName(){
Entry entry =getEntry();
if(entry ==null){
return null;
}
return entry.getName();
}
default String getTypeName(){
Entry entry =getEntry();
if(entry ==null){
return null;
}
return entry.getTypeName();
}
}

View File

@ -0,0 +1,91 @@
package com.reandroid.arsc.value.bag;
import com.reandroid.arsc.item.StringItem;
import com.reandroid.arsc.pool.TableStringPool;
import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.ValueType;
public abstract class BagItem {
protected final ResValueMap mBagItem;
private final ValueType valueType;
private final int data;
private final StringItem string;
protected BagItem(ResValueMap bagItem) {
this.mBagItem = bagItem;
this.valueType = null;
this.string = null;
this.data = 0;
}
protected BagItem(ValueType valueType, int data) {
if (valueType == ValueType.STRING) {
throw new IllegalArgumentException("Use the string constructor instead");
}
this.mBagItem = null;
this.string = null;
this.valueType = valueType;
this.data = data;
}
protected BagItem(StringItem str) {
this.string = str;
this.mBagItem = null;
this.valueType = ValueType.STRING;
this.data = 0;
}
public ValueType getValueType() {
if (mBagItem != null) {
return mBagItem.getValueType();
}
return valueType;
}
public int getValue() {
if (mBagItem != null) {
return mBagItem.getData();
} else if (valueType == ValueType.STRING) {
return string.getIndex();
} else {
return data;
}
}
public void copyTo(ResValueMap target) {
if (mBagItem != null) {
target.setTypeAndData(mBagItem.getValueType(), mBagItem.getData());
} else if (valueType == ValueType.STRING) {
TableStringPool targetStrPool = (TableStringPool) target.getStringPool();
if (targetStrPool == string.getParent(TableStringPool.class)) {
target.setTypeAndData(ValueType.STRING, string.getIndex());
} else {
target.setTypeAndData(ValueType.STRING, targetStrPool.getOrCreate(string.get()).getIndex());
}
} else {
target.setTypeAndData(valueType, data);
}
}
public ResValueMap getBagItem() {
return mBagItem;
}
public boolean hasStringValue() {
return getValueType() == ValueType.STRING;
}
public boolean hasReferenceValue() {
return getValueType() == ValueType.REFERENCE;
}
public String getStringValue() {
if (mBagItem != null) {
return mBagItem.getValueAsString();
} else if (valueType == ValueType.STRING) {
return string.getHtml();
} else {
throw new IllegalArgumentException("Not a string");
}
}
}

View File

@ -0,0 +1,196 @@
package com.reandroid.arsc.value.bag;
import com.reandroid.arsc.array.ResValueMapArray;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.pool.TableStringPool;
import com.reandroid.arsc.value.ResTableMapEntry;
import com.reandroid.arsc.value.ResValueMap;
import java.util.*;
public abstract class MapBag<K, V extends BagItem> extends AbstractMap<K, V> implements Bag {
protected final com.reandroid.arsc.value.Entry entry;
private int modCount = 0;
protected MapBag(com.reandroid.arsc.value.Entry entry) {
this.entry = entry;
}
protected ResTableMapEntry getTableEntry() {
return (ResTableMapEntry) entry.getTableEntry();
}
protected ResValueMapArray getMapArray() {
return getTableEntry().getValue();
}
private void updateSize() {
getTableEntry().setValuesCount(size());
modCount += 1;
}
@Override
public com.reandroid.arsc.value.Entry getEntry() {
return entry;
}
protected abstract V createBagItem(ResValueMap valueMap, boolean copied);
protected abstract ResValueMap newKey(K key);
protected abstract K getKeyFor(ResValueMap valueMap);
protected TableStringPool getStringPool() {
com.reandroid.arsc.value.Entry entry = getEntry();
if (entry == null) {
return null;
}
PackageBlock pkg = entry.getPackageBlock();
if (pkg == null) {
return null;
}
TableBlock tableBlock = pkg.getTableBlock();
if (tableBlock == null) {
return null;
}
return tableBlock.getTableStringPool();
}
private class MapEntry implements Map.Entry<K, V> {
private final ResValueMap item;
private MapEntry(ResValueMap item) {
this.item = item;
}
@Override
public K getKey() {
return getKeyFor(item);
}
@Override
public V getValue() {
return createBagItem(item, false);
}
@Override
public V setValue(V v) {
v.copyTo(item);
return getValue();
}
}
private class EntrySet extends AbstractSet<Entry<K, V>> {
@Override
public Iterator<Entry<K, V>> iterator() {
return new Iterator<Entry<K, V>>() {
private final Iterator<ResValueMap> iterator = getMapArray().iterator();
private final int expectedModCount = modCount;
private void checkValidity() {
if (expectedModCount != modCount) {
throw new ConcurrentModificationException("Iterator is no longer valid because the size has changed.");
}
}
@Override
public boolean hasNext() {
checkValidity();
return iterator.hasNext();
}
@Override
public Entry<K, V> next() {
checkValidity();
return new MapEntry(iterator.next());
}
};
}
@Override
public int size() {
return getMapArray().childesCount();
}
}
@Override
public V remove(Object key) {
ResValueMapArray array = getMapArray();
for (ResValueMap item : array.getChildes()) {
if (getKeyFor(item).equals(key)) {
if (!array.remove(item)) {
throw new IllegalStateException("Could not remove item");
}
updateSize();
return createBagItem(item, true);
}
}
return null;
}
@Override
public void clear() {
getMapArray().clearChildes();
updateSize();
}
@Override
public Set<Entry<K, V>> entrySet() {
return new EntrySet();
}
@Override
public V put(K key, V value) {
if (key == null) {
throw new NullPointerException("key is null");
}
if (value == null) {
throw new NullPointerException("value is null");
}
ResValueMapArray array = getMapArray();
ResValueMap valueMap = null;
for (ResValueMap item : array.getChildes()) {
if (getKeyFor(item).equals(key)) {
valueMap = item;
break;
}
}
if (valueMap == null) {
valueMap = newKey(key);
array.add(valueMap);
updateSize();
}
value.copyTo(valueMap);
return createBagItem(valueMap, false);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
LinkedHashSet<K> keys = new LinkedHashSet<>(m.keySet());
ResValueMapArray array = getMapArray();
for (ResValueMap item : array.getChildes()) {
K currentKey = getKeyFor(item);
if (keys.remove(currentKey)) {
V src = m.get(currentKey);
src.copyTo(item);
}
}
for (K key : keys) {
if (key == null) {
throw new NullPointerException("Key is null");
}
ResValueMap item = newKey(key);
array.add(item);
V src = m.get(key);
src.copyTo(item);
}
updateSize();
}
}

View File

@ -15,30 +15,54 @@
*/ */
package com.reandroid.arsc.value.plurals; package com.reandroid.arsc.value.plurals;
import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.ResTableMapEntry; import com.reandroid.arsc.value.ValueType;
import com.reandroid.arsc.value.bag.MapBag;
public class PluralsBag { import java.util.Arrays;
private final PluralsBagItem[] mBagItems; import java.util.HashSet;
private PluralsBag(PluralsBagItem[] bagItems){ import java.util.Set;
this.mBagItems=bagItems;
public class PluralsBag extends MapBag<PluralsQuantity, PluralsBagItem> {
private PluralsBag(com.reandroid.arsc.value.Entry entry) {
super(entry);
} }
public PluralsBagItem[] getBagItems() {
return mBagItems; @Override
protected PluralsBagItem createBagItem(ResValueMap valueMap, boolean copied) {
if (copied) {
return PluralsBagItem.copyOf(valueMap);
} }
public String getName(){ return PluralsBagItem.create(valueMap);
Entry entry =getBagItems()[0].getBagItem().getEntry(); }
if(entry ==null){
@Override
protected ResValueMap newKey(PluralsQuantity key) {
ResValueMap valueMap = new ResValueMap();
valueMap.setParent(getMapArray());
valueMap.setNameHigh((short) 0x0100);
valueMap.setNameLow(key.getId());
return valueMap;
}
@Override
protected PluralsQuantity getKeyFor(ResValueMap valueMap) {
return PluralsQuantity.valueOf(valueMap);
}
public String getQuantityString(PluralsQuantity quantity) {
PluralsBagItem item = get(quantity);
if (item == null) {
return null; return null;
} }
return entry.getName(); return item.getQualityString();
} }
public String getTypeName(){
Entry entry =getBagItems()[0].getBagItem().getEntry(); public void setQuantityString(PluralsQuantity quantity, String str) {
if(entry ==null){ if (quantity == null || str == null) {
return null; return;
} }
return entry.getTypeName(); put(quantity, PluralsBagItem.string(getStringPool().getOrCreate(str)));
} }
@Override @Override
@ -50,10 +74,9 @@ import com.reandroid.arsc.value.ResTableMapEntry;
builder.append(" name=\""); builder.append(" name=\"");
builder.append(getName()); builder.append(getName());
builder.append("\">"); builder.append("\">");
PluralsBagItem[] allItems = getBagItems(); for (PluralsBagItem pluralsBagItem : values()) {
for(int i=0;i<allItems.length;i++){
builder.append("\n "); builder.append("\n ");
builder.append(allItems[i].toString()); builder.append(pluralsBagItem.toString());
} }
builder.append("\n</"); builder.append("\n</");
builder.append(type); builder.append(type);
@ -61,23 +84,39 @@ import com.reandroid.arsc.value.ResTableMapEntry;
return builder.toString(); return builder.toString();
} }
/** The result of this is not always 100% accurate, private final static Set<ValueType> validTypes = new HashSet<>(Arrays.asList(ValueType.NULL, ValueType.STRING, ValueType.REFERENCE));
* in addition to this use your methods to cross check like type-name == "plurals"**/
public static boolean isPlurals(ResTableMapEntry mapEntry){ /**
if(mapEntry==null){ * The result of this is not always 100% accurate,
* in addition to this use your methods to cross check like type-name == "plurals"
**/
public static boolean isPlurals(com.reandroid.arsc.value.Entry entry) {
PluralsBag plurals = create(entry);
if (plurals == null) {
return false; return false;
} }
return PluralsBagItem.create(mapEntry.listResValueMap()) != null; ResValueMap[] items = plurals.getMapArray().getChildes();
if (items.length == 0) {
return false;
} }
public static PluralsBag create(ResTableMapEntry mapEntry){ for (ResValueMap item : items) {
if(mapEntry==null){ if (item == null || !validTypes.contains(item.getValueType())) {
return false;
}
int name = item.getName();
int high = (name >> 16) & 0xffff;
if (PluralsQuantity.valueOf(item) == null || high != 0x0100) {
return false;
}
}
return true;
}
public static PluralsBag create(com.reandroid.arsc.value.Entry entry) {
if (entry == null || !entry.isComplex()) {
return null; return null;
} }
PluralsBagItem[] bagItems=PluralsBagItem.create(mapEntry.listResValueMap()); return new PluralsBag(entry);
if(bagItems==null){
return null;
}
return new PluralsBag(bagItems);
} }
} }

View File

@ -15,71 +15,41 @@
*/ */
package com.reandroid.arsc.value.plurals; package com.reandroid.arsc.value.plurals;
import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.item.StringItem;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.item.TableString; import com.reandroid.arsc.item.TableString;
import com.reandroid.arsc.pool.TableStringPool;
import com.reandroid.arsc.value.Entry;
import com.reandroid.arsc.value.ResValueMap; import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.ValueType; import com.reandroid.arsc.value.ValueType;
import com.reandroid.arsc.value.bag.BagItem;
import java.util.ArrayList; public class PluralsBagItem extends BagItem {
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PluralsBagItem {
private final ResValueMap mBagItem;
private PluralsBagItem(ResValueMap bagItem) { private PluralsBagItem(ResValueMap bagItem) {
this.mBagItem=bagItem; super(bagItem);
} }
public ResValueMap getBagItem() {
return mBagItem; private PluralsBagItem(StringItem str) {
super(str);
} }
private PluralsBagItem(ValueType valueType, int data) {
super(valueType, data);
}
public PluralsQuantity getQuantity() { public PluralsQuantity getQuantity() {
ResValueMap item=getBagItem(); if (mBagItem == null || mBagItem.getName() == 0) {
int low = item.getName() & 0xffff;
return PluralsQuantity.valueOf((short) low);
}
public ValueType getValueType(){
return getBagItem().getValueType();
}
private TableStringPool getStringPool(){
Entry entry =getBagItem().getEntry();
if(entry ==null){
return null; return null;
} }
PackageBlock pkg = entry.getPackageBlock(); return PluralsQuantity.valueOf(mBagItem);
if(pkg==null){
return null;
} }
TableBlock tableBlock= pkg.getTableBlock();
if(tableBlock==null){ public String getQualityString() {
return null; switch (getValueType()) {
case STRING:
return getStringValue();
case REFERENCE:
// TODO: resolve string reference based on language
default:
throw new IllegalArgumentException("Not STR/REFERENCE ValueType=" + getValueType());
} }
return tableBlock.getTableStringPool();
}
public int getValue(){
return getBagItem().getData();
}
public boolean hasStringValue(){
return getValueType()==ValueType.STRING;
}
public boolean hasReferenceValue(){
return getValueType()==ValueType.REFERENCE;
}
public String getStringValue(){
ValueType valueType=getValueType();
if(valueType!=ValueType.STRING){
throw new IllegalArgumentException("Not STRING ValueType="+valueType);
}
TableStringPool stringPool=getStringPool();
if(stringPool==null){
return null;
}
int ref=getValue();
TableString tableString = stringPool.get(ref);
return tableString.getHtml();
} }
@Override @Override
@ -97,41 +67,30 @@ public class PluralsBagItem {
return builder.toString(); return builder.toString();
} }
public static PluralsBagItem[] create(ResValueMap[] resValueMaps){ protected static PluralsBagItem create(ResValueMap resValueMap) {
if(resValueMaps ==null){ if (resValueMap == null) {
return null; return null;
} }
int len= resValueMaps.length; return new PluralsBagItem(resValueMap);
if(len==0){ }
protected static PluralsBagItem copyOf(ResValueMap resValueMap) {
ValueType valueType = resValueMap.getValueType();
if (valueType == ValueType.STRING) {
return new PluralsBagItem(resValueMap.getDataAsPoolString());
} else {
return new PluralsBagItem(valueType, resValueMap.getData());
}
}
public static PluralsBagItem string(TableString str) {
if (str == null) {
return null; return null;
} }
Set<PluralsQuantity> duplicates=new HashSet<>(); return new PluralsBagItem(str);
List<PluralsBagItem> results=new ArrayList<>();
for(int i=0;i<len;i++){
ResValueMap resValueMap = resValueMaps[i];
int high = (resValueMap.getName() >> 16) & 0xffff;
if(high != 0x0100){
return null;
} }
PluralsBagItem item=create(resValueMap);
if(item==null){ public static PluralsBagItem reference(int resourceId) {
// If it reaches here type name is obfuscated return new PluralsBagItem(ValueType.REFERENCE, resourceId);
return null;
}
PluralsQuantity quantity=item.getQuantity();
if(duplicates.contains(quantity)){
return null;
}
duplicates.add(quantity);
results.add(item);
}
return results.toArray(new PluralsBagItem[0]);
}
public static PluralsBagItem create(ResValueMap resValueMap){
PluralsBagItem item=new PluralsBagItem(resValueMap);
if(item.getQuantity()==null){
return null;
}
return item;
} }
} }

View File

@ -16,6 +16,8 @@
package com.reandroid.arsc.value.plurals; package com.reandroid.arsc.value.plurals;
import com.reandroid.arsc.value.ResValueMap;
public enum PluralsQuantity { public enum PluralsQuantity {
OTHER((short) 0x0004), OTHER((short) 0x0004),
ZERO((short) 0x0005), ZERO((short) 0x0005),
@ -44,6 +46,13 @@ public enum PluralsQuantity {
} }
return null; return null;
} }
public static PluralsQuantity valueOf(ResValueMap valueMap){
if (valueMap == null) {
return null;
}
int low = valueMap.getName() & 0xffff;
return valueOf((short) low);
}
public static PluralsQuantity value(String name){ public static PluralsQuantity value(String name){
if(name==null){ if(name==null){
return null; return null;

View File

@ -15,64 +15,65 @@
*/ */
package com.reandroid.arsc.value.style; package com.reandroid.arsc.value.style;
import com.reandroid.arsc.item.SpecString; import com.reandroid.apk.xmlencoder.EncodeMaterials;
import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.value.ResTableMapEntry; import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.bag.MapBag;
public class StyleBag { public class StyleBag extends MapBag<Integer, StyleBagItem> {
private final StyleBagItem[] mBagItems; private StyleBag(com.reandroid.arsc.value.Entry entry) {
private StyleBag(StyleBagItem[] bagItems){ super(entry);
this.mBagItems=bagItems;
}
public StyleBagItem[] getBagItems() {
return mBagItems;
}
public String getName(){
Entry entry = getEntry();
if(entry ==null){
return null;
}
SpecString spec = entry.getSpecString();
if(spec==null){
return null;
}
return spec.get();
} }
public String getParentResourceName() { public String getParentResourceName() {
int id = getParentId(); int id = getParentId();
if (id == 0) { if (id == 0) {
return null; return null;
} }
Entry entry = getEntry(); com.reandroid.arsc.value.Entry entry = getEntry();
if (entry == null) { if (entry == null) {
return null; return null;
} }
return entry.buildResourceName(id, '@', true); return entry.buildResourceName(id, '@', true);
} }
public int getParentId() { public int getParentId() {
ResTableMapEntry mapEntry = getBagItems()[0].getBagItem().getParentMapEntry(); return getTableEntry().getParentId();
if(mapEntry==null){
return 0;
}
return mapEntry.getParentId();
} }
public int getResourceId() { public int getResourceId() {
Entry entry = getEntry(); com.reandroid.arsc.value.Entry entry = getEntry();
if (entry == null) { if (entry == null) {
return 0; return 0;
} }
return entry.getResourceId(); return entry.getResourceId();
} }
public String getTypeName(){
Entry entry =getBagItems()[0].getBagItem().getEntry(); @Override
if(entry ==null){ protected StyleBagItem createBagItem(ResValueMap valueMap, boolean copied) {
return null; if (copied) {
return StyleBagItem.copyOf(valueMap);
} }
return entry.getTypeName(); return StyleBagItem.create(valueMap);
} }
private Entry getEntry(){
return getBagItems()[0].getBagItem().getEntry(); @Override
protected ResValueMap newKey(Integer attrId) {
ResValueMap valueMap = new ResValueMap();
valueMap.setParent(getMapArray());
valueMap.setName(attrId);
return valueMap;
} }
@Override
protected Integer getKeyFor(ResValueMap valueMap) {
return valueMap.getName();
}
public static int resolve(EncodeMaterials materials, String name) {
return materials.getAttributeBlock(name).getResourceId();
}
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@ -89,10 +90,9 @@ public class StyleBag {
builder.append("\""); builder.append("\"");
} }
builder.append("\">"); builder.append("\">");
StyleBagItem[] allItems = getBagItems(); for (StyleBagItem item : values()) {
for(int i=0;i<allItems.length;i++){
builder.append("\n "); builder.append("\n ");
builder.append(allItems[i].toString()); builder.append(item.toString());
} }
builder.append("\n</"); builder.append("\n</");
builder.append(type); builder.append(type);
@ -100,23 +100,37 @@ public class StyleBag {
return builder.toString(); return builder.toString();
} }
/** The result of this is not always 100% accurate, /**
* in addition to this use your methods to cross check like type-name == "plurals"**/ * The result of this is not always 100% accurate,
public static boolean isStyle(ResTableMapEntry mapEntry){ * in addition to this use your methods to cross check like type-name == "plurals"
if(mapEntry==null){ **/
public static boolean isStyle(com.reandroid.arsc.value.Entry entry) {
StyleBag style = create(entry);
if (style == null) {
return false; return false;
} }
return StyleBag.create(mapEntry) != null;
TableBlock tableBlock = entry.getPackageBlock().getTableBlock();
if (tableBlock == null) {
return false;
}
ResValueMap[] items = style.getMapArray().getChildes();
if (items.length == 0) {
return false;
} }
public static StyleBag create(ResTableMapEntry mapEntry){ for (ResValueMap item : items) {
if(mapEntry==null){ if (item == null || tableBlock.search(item.getNameResourceID()) == null) {
return false;
}
}
return true;
}
public static StyleBag create(com.reandroid.arsc.value.Entry entry) {
if (entry == null || !entry.isComplex()) {
return null; return null;
} }
StyleBagItem[] bagItems=StyleBagItem.create(mapEntry.getValue().getChildes()); return new StyleBag(entry);
if(bagItems==null){
return null;
}
return new StyleBag(bagItems);
} }
} }

View File

@ -15,42 +15,50 @@
*/ */
package com.reandroid.arsc.value.style; package com.reandroid.arsc.value.style;
import com.reandroid.arsc.decoder.ValueDecoder;
import com.reandroid.arsc.item.StringItem;
import com.reandroid.arsc.item.TableString;
import com.reandroid.arsc.value.bag.BagItem;
import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.Entry;
import com.reandroid.arsc.value.ResValueMap; import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.ValueType; import com.reandroid.arsc.value.ValueType;
import java.util.ArrayList; public class StyleBagItem extends BagItem {
import java.util.List; private StyleBagItem(ResValueMap bagItem) {
super(bagItem);
public class StyleBagItem {
private final ResValueMap mBagItem;
public StyleBagItem(ResValueMap bagItem){
this.mBagItem=bagItem;
} }
public ResValueMap getBagItem() {
return mBagItem; private StyleBagItem(ValueType valueType, int data) {
super(valueType, data);
}
private StyleBagItem(StringItem str) {
super(str);
} }
public String getName() { public String getName() {
Entry block=getBagItem().getEntry(); if (mBagItem == null) {
return null;
}
Entry block = mBagItem.getEntry();
if (block == null) { if (block == null) {
return null; return null;
} }
char prefix = 0; char prefix = 0;
return block.buildResourceName(getNameId(), prefix, false); return block.buildResourceName(mBagItem.getName(), prefix, false);
} }
public int getNameId() { public int getNameId() {
return getBagItem().getName(); if (mBagItem == null) {
return 0;
} }
public boolean hasStringValue(){ return mBagItem.getName();
return getValueType()== ValueType.STRING;
}
public boolean hasReferenceValue(){
return getValueType()==ValueType.REFERENCE;
} }
public boolean hasAttributeValue() { public boolean hasAttributeValue() {
return getValueType()==ValueType.REFERENCE; return getValueType() == ValueType.ATTRIBUTE;
} }
public String getValueAsReference() { public String getValueAsReference() {
ValueType valueType = getValueType(); ValueType valueType = getValueType();
if (valueType != ValueType.REFERENCE && valueType != ValueType.ATTRIBUTE) { if (valueType != ValueType.REFERENCE && valueType != ValueType.ATTRIBUTE) {
@ -69,15 +77,7 @@ public class StyleBagItem {
int id = getValue(); int id = getValue();
return entry.buildResourceName(id, prefix, includeType); return entry.buildResourceName(id, prefix, includeType);
} }
public String getStringValue(){
return mBagItem.getValueAsString();
}
public ValueType getValueType(){
return getBagItem().getValueType();
}
public int getValue(){
return getBagItem().getData();
}
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@ -102,28 +102,60 @@ public class StyleBagItem {
builder.append("</item>"); builder.append("</item>");
return builder.toString(); return builder.toString();
} }
public static StyleBagItem[] create(ResValueMap[] resValueMaps){
if(resValueMaps ==null){ protected static StyleBagItem create(ResValueMap resValueMap) {
return null;
}
int len= resValueMaps.length;
if(len==0){
return null;
}
List<StyleBagItem> results=new ArrayList<>();
for(int i=0;i<len;i++){
StyleBagItem item=create(resValueMaps[i]);
if(item==null){
return null;
}
results.add(item);
}
return results.toArray(new StyleBagItem[0]);
}
public static StyleBagItem create(ResValueMap resValueMap){
if (resValueMap == null) { if (resValueMap == null) {
return null; return null;
} }
return new StyleBagItem(resValueMap); return new StyleBagItem(resValueMap);
} }
public static StyleBagItem create(ValueType valueType, int value) {
if (valueType == null || valueType == ValueType.STRING) {
return null;
}
return new StyleBagItem(valueType, value);
}
protected static StyleBagItem copyOf(ResValueMap resValueMap) {
ValueType valueType = resValueMap.getValueType();
if (valueType == ValueType.STRING) {
return new StyleBagItem(resValueMap.getDataAsPoolString());
} else {
return new StyleBagItem(valueType, resValueMap.getData());
}
}
public static StyleBagItem integer(int n) {
return new StyleBagItem(ValueType.INT_DEC, n);
}
public static StyleBagItem string(TableString str) {
if (str == null) {
return null;
}
return new StyleBagItem(str);
}
public static StyleBagItem reference(int resourceId) {
return new StyleBagItem(ValueType.REFERENCE, resourceId);
}
public static StyleBagItem attribute(int resourceId) {
return new StyleBagItem(ValueType.ATTRIBUTE, resourceId);
}
public static StyleBagItem encoded(ValueDecoder.EncodeResult encodeResult) {
if (encodeResult == null) {
return null;
}
return create(encodeResult.valueType, encodeResult.value);
}
public static StyleBagItem color(String color) {
return encoded(ValueDecoder.encodeColor(color));
}
public static StyleBagItem dimensionOrFraction(String str) {
return encoded(ValueDecoder.encodeDimensionOrFraction(str));
}
public static StyleBagItem createFloat(float n) {
return new StyleBagItem(ValueType.FLOAT, Float.floatToIntBits(n));
}
} }