mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-09 10:14:25 +02:00
feat: finish the bag apis
This commit is contained in:
parent
2eb4e7f96d
commit
b110635b47
@ -196,21 +196,12 @@
|
||||
}
|
||||
private TableEntry<?, ?> ensureTableEntry(boolean is_complex){
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -13,91 +13,164 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value.array;
|
||||
package com.reandroid.arsc.value.array;
|
||||
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResTableMapEntry;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.arsc.array.ResValueMapArray;
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResTableMapEntry;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.arsc.value.bag.Bag;
|
||||
|
||||
public class ArrayBag {
|
||||
private final ArrayBagItem[] mBagItems;
|
||||
private ArrayBag(ArrayBagItem[] bagItems){
|
||||
this.mBagItems=bagItems;
|
||||
}
|
||||
public ArrayBagItem[] getBagItems() {
|
||||
return mBagItems;
|
||||
}
|
||||
public String getName(){
|
||||
Entry entry =getBagItems()[0].getBagItem().getEntry();
|
||||
if(entry ==null){
|
||||
return null;
|
||||
}
|
||||
return entry.getName();
|
||||
}
|
||||
public String getTypeName(){
|
||||
Entry entry =getBagItems()[0].getBagItem().getEntry();
|
||||
if(entry ==null){
|
||||
return null;
|
||||
}
|
||||
return entry.getTypeName();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder=new StringBuilder();
|
||||
builder.append("<");
|
||||
String type=getTypeName();
|
||||
builder.append(type);
|
||||
builder.append(" name=\"");
|
||||
builder.append(getName());
|
||||
builder.append("\">");
|
||||
ArrayBagItem[] allItems = getBagItems();
|
||||
for(int i=0;i<allItems.length;i++){
|
||||
builder.append("\n ");
|
||||
builder.append(allItems[i].toString());
|
||||
}
|
||||
builder.append("\n</");
|
||||
builder.append(type);
|
||||
builder.append(">");
|
||||
return builder.toString();
|
||||
}
|
||||
import java.util.AbstractList;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
/** The result of this is not always 100% accurate,
|
||||
* in addition to this use your methods to cross check like type-name == "array"**/
|
||||
public static boolean isArray(ResTableMapEntry mapEntry){
|
||||
if(mapEntry==null){
|
||||
return false;
|
||||
}
|
||||
if(mapEntry.getParentId()!=0){
|
||||
return false;
|
||||
}
|
||||
ArrayBagItem[] arrayBagItems = ArrayBagItem.create(mapEntry.listResValueMap());
|
||||
if(arrayBagItems==null || arrayBagItems.length==0){
|
||||
return false;
|
||||
}
|
||||
for(int i=0;i< arrayBagItems.length; i++){
|
||||
ArrayBagItem arrayBagItem = arrayBagItems[i];
|
||||
ResValueMap resValueMap = arrayBagItem.getBagItem();
|
||||
int name = resValueMap.getName();
|
||||
int high = (name >> 16) & 0xffff;
|
||||
if(high!=0x0100){
|
||||
return false;
|
||||
}
|
||||
int low = name & 0xffff;
|
||||
if(low != (i+1)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public class ArrayBag extends AbstractList<ArrayBagItem> implements Bag, RandomAccess {
|
||||
private final Entry entry;
|
||||
|
||||
public static ArrayBag create(ResTableMapEntry mapEntry){
|
||||
if(mapEntry==null){
|
||||
return null;
|
||||
}
|
||||
ArrayBagItem[] bagItems=ArrayBagItem.create(mapEntry.listResValueMap());
|
||||
if(bagItems==null){
|
||||
return null;
|
||||
}
|
||||
return new ArrayBag(bagItems);
|
||||
}
|
||||
}
|
||||
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() {
|
||||
return toArray(new ArrayBagItem[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return getMapArray().childesCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayBagItem get(int i) {
|
||||
return ArrayBagItem.create(getMapArray().get(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayBagItem set(int index, ArrayBagItem value) {
|
||||
ArrayBagItem target = get(index);
|
||||
value.copyTo(target.getBagItem());
|
||||
return target;
|
||||
}
|
||||
|
||||
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
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<");
|
||||
String type = getTypeName();
|
||||
builder.append(type);
|
||||
builder.append(" name=\"");
|
||||
builder.append(getName());
|
||||
builder.append("\">");
|
||||
ArrayBagItem[] allItems = getBagItems();
|
||||
for (ArrayBagItem allItem : allItems) {
|
||||
builder.append("\n ");
|
||||
builder.append(allItem.toString());
|
||||
}
|
||||
builder.append("\n</");
|
||||
builder.append(type);
|
||||
builder.append(">");
|
||||
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"
|
||||
**/
|
||||
public static boolean isArray(Entry entry) {
|
||||
ArrayBag array = create(entry);
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
ResTableMapEntry tableEntry = array.getTableEntry();
|
||||
if (tableEntry.getParentId() != 0) {
|
||||
return false;
|
||||
}
|
||||
ResValueMap[] items = tableEntry.listResValueMap();
|
||||
if (items.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
ResValueMap resValueMap = items[i];
|
||||
int name = resValueMap.getName();
|
||||
int high = (name >> 16) & 0xffff;
|
||||
if(high!=0x0100){
|
||||
return false;
|
||||
}
|
||||
int low = name & 0xffff;
|
||||
if(low != (i+1)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ArrayBag create(Entry entry) {
|
||||
if (entry == null || !entry.isComplex()) {
|
||||
return null;
|
||||
}
|
||||
return new ArrayBag(entry);
|
||||
}
|
||||
}
|
||||
|
@ -13,104 +13,83 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value.array;
|
||||
package com.reandroid.arsc.value.array;
|
||||
|
||||
import com.reandroid.arsc.chunk.PackageBlock;
|
||||
import com.reandroid.arsc.chunk.TableBlock;
|
||||
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.decoder.ValueDecoder;
|
||||
import com.reandroid.arsc.item.StringItem;
|
||||
import com.reandroid.arsc.item.TableString;
|
||||
import com.reandroid.arsc.value.ValueType;
|
||||
import com.reandroid.arsc.value.bag.BagItem;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
public class ArrayBagItem extends BagItem {
|
||||
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;
|
||||
}
|
||||
private ArrayBagItem(StringItem str) {
|
||||
super(str);
|
||||
}
|
||||
|
||||
public ValueType getValueType(){
|
||||
return getBagItem().getValueType();
|
||||
}
|
||||
private TableStringPool getStringPool(){
|
||||
Entry entry =getBagItem().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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
private ArrayBagItem(ValueType valueType, int value) {
|
||||
super(valueType, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder=new StringBuilder();
|
||||
builder.append("<item>");
|
||||
if(hasStringValue()){
|
||||
builder.append(getStringValue());
|
||||
}else {
|
||||
builder.append(String.format("0x%08x", getValue()));
|
||||
}
|
||||
builder.append("</item>");
|
||||
return builder.toString();
|
||||
}
|
||||
public static ArrayBagItem[] create(ResValueMap[] resValueMaps){
|
||||
if(resValueMaps ==null){
|
||||
return null;
|
||||
}
|
||||
int len= resValueMaps.length;
|
||||
if(len==0){
|
||||
return null;
|
||||
}
|
||||
List<ArrayBagItem> results=new ArrayList<>();
|
||||
for(int i=0;i<len;i++){
|
||||
ArrayBagItem item=create(resValueMaps[i]);
|
||||
if(item==null){
|
||||
return null;
|
||||
}
|
||||
results.add(item);
|
||||
}
|
||||
return results.toArray(new ArrayBagItem[0]);
|
||||
}
|
||||
public static ArrayBagItem create(ResValueMap resValueMap){
|
||||
if(resValueMap ==null){
|
||||
return null;
|
||||
}
|
||||
ArrayBagItem item=new ArrayBagItem(resValueMap);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<item>");
|
||||
if (hasStringValue()) {
|
||||
builder.append(getStringValue());
|
||||
} else {
|
||||
builder.append(String.format("0x%08x", getValue()));
|
||||
}
|
||||
builder.append("</item>");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected static ArrayBagItem create(ResValueMap valueMap) {
|
||||
if (valueMap == null) {
|
||||
return null;
|
||||
}
|
||||
return new ArrayBagItem(valueMap);
|
||||
}
|
||||
|
||||
public static ArrayBagItem create(ValueType valueType, int value) {
|
||||
if (valueType == null || valueType == ValueType.STRING) {
|
||||
return null;
|
||||
}
|
||||
return new ArrayBagItem(valueType, value);
|
||||
}
|
||||
|
||||
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 create(encodeResult.valueType, encodeResult.value);
|
||||
}
|
||||
|
||||
public static ArrayBagItem integer(int n) {
|
||||
return create(ValueType.INT_DEC, n);
|
||||
}
|
||||
|
||||
public static ArrayBagItem string(TableString str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
return new ArrayBagItem(str);
|
||||
}
|
||||
|
||||
public static ArrayBagItem reference(int resourceId) {
|
||||
return create(ValueType.REFERENCE, resourceId);
|
||||
}
|
||||
}
|
||||
|
21
src/main/java/com/reandroid/arsc/value/bag/Bag.java
Normal file
21
src/main/java/com/reandroid/arsc/value/bag/Bag.java
Normal 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();
|
||||
}
|
||||
}
|
91
src/main/java/com/reandroid/arsc/value/bag/BagItem.java
Normal file
91
src/main/java/com/reandroid/arsc/value/bag/BagItem.java
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
196
src/main/java/com/reandroid/arsc/value/bag/MapBag.java
Normal file
196
src/main/java/com/reandroid/arsc/value/bag/MapBag.java
Normal 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();
|
||||
}
|
||||
}
|
@ -13,71 +13,110 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value.plurals;
|
||||
package com.reandroid.arsc.value.plurals;
|
||||
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResTableMapEntry;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.arsc.value.ValueType;
|
||||
import com.reandroid.arsc.value.bag.MapBag;
|
||||
|
||||
public class PluralsBag {
|
||||
private final PluralsBagItem[] mBagItems;
|
||||
private PluralsBag(PluralsBagItem[] bagItems){
|
||||
this.mBagItems=bagItems;
|
||||
}
|
||||
public PluralsBagItem[] getBagItems() {
|
||||
return mBagItems;
|
||||
}
|
||||
public String getName(){
|
||||
Entry entry =getBagItems()[0].getBagItem().getEntry();
|
||||
if(entry ==null){
|
||||
return null;
|
||||
}
|
||||
return entry.getName();
|
||||
}
|
||||
public String getTypeName(){
|
||||
Entry entry =getBagItems()[0].getBagItem().getEntry();
|
||||
if(entry ==null){
|
||||
return null;
|
||||
}
|
||||
return entry.getTypeName();
|
||||
}
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder=new StringBuilder();
|
||||
builder.append("<");
|
||||
String type=getTypeName();
|
||||
builder.append(type);
|
||||
builder.append(" name=\"");
|
||||
builder.append(getName());
|
||||
builder.append("\">");
|
||||
PluralsBagItem[] allItems = getBagItems();
|
||||
for(int i=0;i<allItems.length;i++){
|
||||
builder.append("\n ");
|
||||
builder.append(allItems[i].toString());
|
||||
}
|
||||
builder.append("\n</");
|
||||
builder.append(type);
|
||||
builder.append(">");
|
||||
return builder.toString();
|
||||
}
|
||||
public class PluralsBag extends MapBag<PluralsQuantity, PluralsBagItem> {
|
||||
private PluralsBag(com.reandroid.arsc.value.Entry entry) {
|
||||
super(entry);
|
||||
}
|
||||
|
||||
/** 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(ResTableMapEntry mapEntry){
|
||||
if(mapEntry==null){
|
||||
return false;
|
||||
}
|
||||
return PluralsBagItem.create(mapEntry.listResValueMap()) != null;
|
||||
}
|
||||
@Override
|
||||
protected PluralsBagItem createBagItem(ResValueMap valueMap, boolean copied) {
|
||||
if (copied) {
|
||||
return PluralsBagItem.copyOf(valueMap);
|
||||
}
|
||||
return PluralsBagItem.create(valueMap);
|
||||
}
|
||||
|
||||
public static PluralsBag create(ResTableMapEntry mapEntry){
|
||||
if(mapEntry==null){
|
||||
return null;
|
||||
}
|
||||
PluralsBagItem[] bagItems=PluralsBagItem.create(mapEntry.listResValueMap());
|
||||
if(bagItems==null){
|
||||
return null;
|
||||
}
|
||||
return new PluralsBag(bagItems);
|
||||
}
|
||||
}
|
||||
@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 item.getQualityString();
|
||||
}
|
||||
|
||||
public void setQuantityString(PluralsQuantity quantity, String str) {
|
||||
if (quantity == null || str == null) {
|
||||
return;
|
||||
}
|
||||
put(quantity, PluralsBagItem.string(getStringPool().getOrCreate(str)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<");
|
||||
String type = getTypeName();
|
||||
builder.append(type);
|
||||
builder.append(" name=\"");
|
||||
builder.append(getName());
|
||||
builder.append("\">");
|
||||
for (PluralsBagItem pluralsBagItem : values()) {
|
||||
builder.append("\n ");
|
||||
builder.append(pluralsBagItem.toString());
|
||||
}
|
||||
builder.append("\n</");
|
||||
builder.append(type);
|
||||
builder.append(">");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private final static Set<ValueType> validTypes = new HashSet<>(Arrays.asList(ValueType.NULL, ValueType.STRING, ValueType.REFERENCE));
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
ResValueMap[] items = plurals.getMapArray().getChildes();
|
||||
if (items.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ResValueMap item : items) {
|
||||
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 new PluralsBag(entry);
|
||||
}
|
||||
}
|
||||
|
@ -13,125 +13,84 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value.plurals;
|
||||
package com.reandroid.arsc.value.plurals;
|
||||
|
||||
import com.reandroid.arsc.chunk.PackageBlock;
|
||||
import com.reandroid.arsc.chunk.TableBlock;
|
||||
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.item.StringItem;
|
||||
import com.reandroid.arsc.item.TableString;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.arsc.value.ValueType;
|
||||
import com.reandroid.arsc.value.bag.BagItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
public class PluralsBagItem extends BagItem {
|
||||
private PluralsBagItem(ResValueMap bagItem) {
|
||||
super(bagItem);
|
||||
}
|
||||
|
||||
public class PluralsBagItem {
|
||||
private final ResValueMap mBagItem;
|
||||
private PluralsBagItem(ResValueMap bagItem){
|
||||
this.mBagItem=bagItem;
|
||||
}
|
||||
public ResValueMap getBagItem() {
|
||||
return mBagItem;
|
||||
}
|
||||
public PluralsQuantity getQuantity(){
|
||||
ResValueMap item=getBagItem();
|
||||
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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
private PluralsBagItem(StringItem str) {
|
||||
super(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder=new StringBuilder();
|
||||
builder.append("<item quantity=\"");
|
||||
builder.append(getQuantity());
|
||||
builder.append("\">");
|
||||
if(hasStringValue()){
|
||||
builder.append(getStringValue());
|
||||
}else {
|
||||
builder.append(String.format("@0x%08x", getValue()));
|
||||
}
|
||||
builder.append("</item>");
|
||||
return builder.toString();
|
||||
}
|
||||
private PluralsBagItem(ValueType valueType, int data) {
|
||||
super(valueType, data);
|
||||
}
|
||||
|
||||
public static PluralsBagItem[] create(ResValueMap[] resValueMaps){
|
||||
if(resValueMaps ==null){
|
||||
return null;
|
||||
}
|
||||
int len= resValueMaps.length;
|
||||
if(len==0){
|
||||
return null;
|
||||
}
|
||||
Set<PluralsQuantity> duplicates=new HashSet<>();
|
||||
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){
|
||||
// If it reaches here type name is obfuscated
|
||||
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;
|
||||
}
|
||||
}
|
||||
public PluralsQuantity getQuantity() {
|
||||
if (mBagItem == null || mBagItem.getName() == 0) {
|
||||
return null;
|
||||
}
|
||||
return PluralsQuantity.valueOf(mBagItem);
|
||||
}
|
||||
|
||||
public String getQualityString() {
|
||||
switch (getValueType()) {
|
||||
case STRING:
|
||||
return getStringValue();
|
||||
case REFERENCE:
|
||||
// TODO: resolve string reference based on language
|
||||
default:
|
||||
throw new IllegalArgumentException("Not STR/REFERENCE ValueType=" + getValueType());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<item quantity=\"");
|
||||
builder.append(getQuantity());
|
||||
builder.append("\">");
|
||||
if (hasStringValue()) {
|
||||
builder.append(getStringValue());
|
||||
} else {
|
||||
builder.append(String.format("@0x%08x", getValue()));
|
||||
}
|
||||
builder.append("</item>");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected static PluralsBagItem create(ResValueMap resValueMap) {
|
||||
if (resValueMap == null) {
|
||||
return null;
|
||||
}
|
||||
return new PluralsBagItem(resValueMap);
|
||||
}
|
||||
|
||||
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 new PluralsBagItem(str);
|
||||
}
|
||||
|
||||
public static PluralsBagItem reference(int resourceId) {
|
||||
return new PluralsBagItem(ValueType.REFERENCE, resourceId);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,9 @@
|
||||
package com.reandroid.arsc.value.plurals;
|
||||
|
||||
|
||||
public enum PluralsQuantity {
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
|
||||
public enum PluralsQuantity {
|
||||
OTHER((short) 0x0004),
|
||||
ZERO((short) 0x0005),
|
||||
ONE((short) 0x0006),
|
||||
@ -44,6 +46,13 @@ public enum PluralsQuantity {
|
||||
}
|
||||
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){
|
||||
if(name==null){
|
||||
return null;
|
||||
|
@ -13,110 +13,124 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value.style;
|
||||
package com.reandroid.arsc.value.style;
|
||||
|
||||
import com.reandroid.arsc.item.SpecString;
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResTableMapEntry;
|
||||
import com.reandroid.apk.xmlencoder.EncodeMaterials;
|
||||
import com.reandroid.arsc.chunk.TableBlock;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.arsc.value.bag.MapBag;
|
||||
|
||||
public class StyleBag {
|
||||
private final StyleBagItem[] mBagItems;
|
||||
private StyleBag(StyleBagItem[] bagItems){
|
||||
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(){
|
||||
int id=getParentId();
|
||||
if(id==0){
|
||||
return null;
|
||||
}
|
||||
Entry entry = getEntry();
|
||||
if(entry ==null){
|
||||
return null;
|
||||
}
|
||||
return entry.buildResourceName(id, '@', true);
|
||||
}
|
||||
public int getParentId(){
|
||||
ResTableMapEntry mapEntry = getBagItems()[0].getBagItem().getParentMapEntry();
|
||||
if(mapEntry==null){
|
||||
return 0;
|
||||
}
|
||||
return mapEntry.getParentId();
|
||||
}
|
||||
public int getResourceId(){
|
||||
Entry entry = getEntry();
|
||||
if(entry ==null){
|
||||
return 0;
|
||||
}
|
||||
return entry.getResourceId();
|
||||
}
|
||||
public String getTypeName(){
|
||||
Entry entry =getBagItems()[0].getBagItem().getEntry();
|
||||
if(entry ==null){
|
||||
return null;
|
||||
}
|
||||
return entry.getTypeName();
|
||||
}
|
||||
private Entry getEntry(){
|
||||
return getBagItems()[0].getBagItem().getEntry();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder=new StringBuilder();
|
||||
builder.append("<");
|
||||
String type=getTypeName();
|
||||
builder.append(type);
|
||||
builder.append(" name=\"");
|
||||
builder.append(getName());
|
||||
builder.append("\"");
|
||||
String parent=getParentResourceName();
|
||||
if(parent!=null){
|
||||
builder.append(" parent=\"");
|
||||
builder.append(parent);
|
||||
builder.append("\"");
|
||||
}
|
||||
builder.append("\">");
|
||||
StyleBagItem[] allItems = getBagItems();
|
||||
for(int i=0;i<allItems.length;i++){
|
||||
builder.append("\n ");
|
||||
builder.append(allItems[i].toString());
|
||||
}
|
||||
builder.append("\n</");
|
||||
builder.append(type);
|
||||
builder.append(">");
|
||||
return builder.toString();
|
||||
}
|
||||
public class StyleBag extends MapBag<Integer, StyleBagItem> {
|
||||
private StyleBag(com.reandroid.arsc.value.Entry entry) {
|
||||
super(entry);
|
||||
}
|
||||
|
||||
/** 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 isStyle(ResTableMapEntry mapEntry){
|
||||
if(mapEntry==null){
|
||||
return false;
|
||||
}
|
||||
return StyleBag.create(mapEntry) != null;
|
||||
}
|
||||
public String getParentResourceName() {
|
||||
int id = getParentId();
|
||||
if (id == 0) {
|
||||
return null;
|
||||
}
|
||||
com.reandroid.arsc.value.Entry entry = getEntry();
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
return entry.buildResourceName(id, '@', true);
|
||||
}
|
||||
|
||||
public static StyleBag create(ResTableMapEntry mapEntry){
|
||||
if(mapEntry==null){
|
||||
return null;
|
||||
}
|
||||
StyleBagItem[] bagItems=StyleBagItem.create(mapEntry.getValue().getChildes());
|
||||
if(bagItems==null){
|
||||
return null;
|
||||
}
|
||||
return new StyleBag(bagItems);
|
||||
}
|
||||
}
|
||||
public int getParentId() {
|
||||
return getTableEntry().getParentId();
|
||||
}
|
||||
|
||||
public int getResourceId() {
|
||||
com.reandroid.arsc.value.Entry entry = getEntry();
|
||||
if (entry == null) {
|
||||
return 0;
|
||||
}
|
||||
return entry.getResourceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StyleBagItem createBagItem(ResValueMap valueMap, boolean copied) {
|
||||
if (copied) {
|
||||
return StyleBagItem.copyOf(valueMap);
|
||||
}
|
||||
return StyleBagItem.create(valueMap);
|
||||
}
|
||||
|
||||
@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
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<");
|
||||
String type = getTypeName();
|
||||
builder.append(type);
|
||||
builder.append(" name=\"");
|
||||
builder.append(getName());
|
||||
builder.append("\"");
|
||||
String parent = getParentResourceName();
|
||||
if (parent != null) {
|
||||
builder.append(" parent=\"");
|
||||
builder.append(parent);
|
||||
builder.append("\"");
|
||||
}
|
||||
builder.append("\">");
|
||||
for (StyleBagItem item : values()) {
|
||||
builder.append("\n ");
|
||||
builder.append(item.toString());
|
||||
}
|
||||
builder.append("\n</");
|
||||
builder.append(type);
|
||||
builder.append(">");
|
||||
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"
|
||||
**/
|
||||
public static boolean isStyle(com.reandroid.arsc.value.Entry entry) {
|
||||
StyleBag style = create(entry);
|
||||
if (style == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TableBlock tableBlock = entry.getPackageBlock().getTableBlock();
|
||||
if (tableBlock == null) {
|
||||
return false;
|
||||
}
|
||||
ResValueMap[] items = style.getMapArray().getChildes();
|
||||
if (items.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ResValueMap item : items) {
|
||||
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 new StyleBag(entry);
|
||||
}
|
||||
}
|
||||
|
@ -13,117 +13,149 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value.style;
|
||||
package com.reandroid.arsc.value.style;
|
||||
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.arsc.value.ValueType;
|
||||
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.ResValueMap;
|
||||
import com.reandroid.arsc.value.ValueType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
public class StyleBagItem extends BagItem {
|
||||
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);
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
Entry block=getBagItem().getEntry();
|
||||
if(block==null){
|
||||
return null;
|
||||
}
|
||||
char prefix=0;
|
||||
return block.buildResourceName(getNameId(), prefix, false);
|
||||
}
|
||||
public int getNameId(){
|
||||
return getBagItem().getName();
|
||||
}
|
||||
public boolean hasStringValue(){
|
||||
return getValueType()== ValueType.STRING;
|
||||
}
|
||||
public boolean hasReferenceValue(){
|
||||
return getValueType()==ValueType.REFERENCE;
|
||||
}
|
||||
public boolean hasAttributeValue(){
|
||||
return getValueType()==ValueType.REFERENCE;
|
||||
}
|
||||
public String getValueAsReference(){
|
||||
ValueType valueType=getValueType();
|
||||
if(valueType!=ValueType.REFERENCE && valueType!=ValueType.ATTRIBUTE){
|
||||
throw new IllegalArgumentException("Not REF ValueType="+valueType);
|
||||
}
|
||||
Entry entry =getBagItem().getEntry();
|
||||
if(entry ==null){
|
||||
return null;
|
||||
}
|
||||
char prefix='@';
|
||||
boolean includeType=true;
|
||||
if(valueType==ValueType.ATTRIBUTE){
|
||||
prefix='?';
|
||||
includeType=false;
|
||||
}
|
||||
int id=getValue();
|
||||
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
|
||||
public String toString() {
|
||||
StringBuilder builder=new StringBuilder();
|
||||
builder.append("<item name=\"");
|
||||
String name=getName();
|
||||
if(name==null){
|
||||
name=String.format("@0x%08x", getNameId());
|
||||
}
|
||||
builder.append(name);
|
||||
builder.append("\">");
|
||||
if(hasStringValue()){
|
||||
builder.append(getStringValue());
|
||||
}
|
||||
String val=null;
|
||||
if(hasReferenceValue()||hasAttributeValue()) {
|
||||
val=getValueAsReference();
|
||||
}
|
||||
if(val==null) {
|
||||
val=String.format("0x%08x", getValue());
|
||||
}
|
||||
builder.append(val);
|
||||
builder.append("</item>");
|
||||
return builder.toString();
|
||||
}
|
||||
public static StyleBagItem[] create(ResValueMap[] resValueMaps){
|
||||
if(resValueMaps ==null){
|
||||
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){
|
||||
return null;
|
||||
}
|
||||
return new StyleBagItem(resValueMap);
|
||||
}
|
||||
}
|
||||
private StyleBagItem(StringItem str) {
|
||||
super(str);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (mBagItem == null) {
|
||||
return null;
|
||||
}
|
||||
Entry block = mBagItem.getEntry();
|
||||
if (block == null) {
|
||||
return null;
|
||||
}
|
||||
char prefix = 0;
|
||||
return block.buildResourceName(mBagItem.getName(), prefix, false);
|
||||
}
|
||||
|
||||
public int getNameId() {
|
||||
if (mBagItem == null) {
|
||||
return 0;
|
||||
}
|
||||
return mBagItem.getName();
|
||||
}
|
||||
|
||||
public boolean hasAttributeValue() {
|
||||
return getValueType() == ValueType.ATTRIBUTE;
|
||||
}
|
||||
|
||||
public String getValueAsReference() {
|
||||
ValueType valueType = getValueType();
|
||||
if (valueType != ValueType.REFERENCE && valueType != ValueType.ATTRIBUTE) {
|
||||
throw new IllegalArgumentException("Not REF ValueType=" + valueType);
|
||||
}
|
||||
Entry entry = getBagItem().getEntry();
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
char prefix = '@';
|
||||
boolean includeType = true;
|
||||
if (valueType == ValueType.ATTRIBUTE) {
|
||||
prefix = '?';
|
||||
includeType = false;
|
||||
}
|
||||
int id = getValue();
|
||||
return entry.buildResourceName(id, prefix, includeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<item name=\"");
|
||||
String name = getName();
|
||||
if (name == null) {
|
||||
name = String.format("@0x%08x", getNameId());
|
||||
}
|
||||
builder.append(name);
|
||||
builder.append("\">");
|
||||
if (hasStringValue()) {
|
||||
builder.append(getStringValue());
|
||||
}
|
||||
String val = null;
|
||||
if (hasReferenceValue() || hasAttributeValue()) {
|
||||
val = getValueAsReference();
|
||||
}
|
||||
if (val == null) {
|
||||
val = String.format("0x%08x", getValue());
|
||||
}
|
||||
builder.append(val);
|
||||
builder.append("</item>");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected static StyleBagItem create(ResValueMap resValueMap) {
|
||||
if (resValueMap == null) {
|
||||
return null;
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user