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){
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,91 +13,164 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.array.ResValueMapArray;
|
||||||
import com.reandroid.arsc.value.ResTableMapEntry;
|
import com.reandroid.arsc.value.Entry;
|
||||||
import com.reandroid.arsc.value.ResValueMap;
|
import com.reandroid.arsc.value.ResTableMapEntry;
|
||||||
|
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 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The result of this is not always 100% accurate,
|
public class ArrayBag extends AbstractList<ArrayBagItem> implements Bag, RandomAccess {
|
||||||
* in addition to this use your methods to cross check like type-name == "array"**/
|
private final Entry entry;
|
||||||
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 static ArrayBag create(ResTableMapEntry mapEntry){
|
private ArrayBag(Entry entry) {
|
||||||
if(mapEntry==null){
|
this.entry = entry;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
ArrayBagItem[] bagItems=ArrayBagItem.create(mapEntry.listResValueMap());
|
private ResTableMapEntry getTableEntry() {
|
||||||
if(bagItems==null){
|
return (ResTableMapEntry) entry.getTableEntry();
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
return new ArrayBag(bagItems);
|
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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.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.ValueType;
|
||||||
import com.reandroid.arsc.value.Entry;
|
import com.reandroid.arsc.value.bag.BagItem;
|
||||||
import com.reandroid.arsc.value.ResValueMap;
|
import com.reandroid.arsc.value.ResValueMap;
|
||||||
import com.reandroid.arsc.value.ValueType;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
public class ArrayBagItem extends BagItem {
|
||||||
import java.util.List;
|
private ArrayBagItem(ResValueMap valueMap) {
|
||||||
|
super(valueMap);
|
||||||
|
}
|
||||||
|
|
||||||
public class ArrayBagItem {
|
private ArrayBagItem(StringItem str) {
|
||||||
private final ResValueMap mBagItem;
|
super(str);
|
||||||
public ArrayBagItem(ResValueMap bagItem){
|
}
|
||||||
this.mBagItem=bagItem;
|
|
||||||
}
|
|
||||||
public ResValueMap getBagItem() {
|
|
||||||
return mBagItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueType getValueType(){
|
private ArrayBagItem(ValueType valueType, int value) {
|
||||||
return getBagItem().getValueType();
|
super(valueType, value);
|
||||||
}
|
}
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder builder=new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
builder.append("<item>");
|
builder.append("<item>");
|
||||||
if(hasStringValue()){
|
if (hasStringValue()) {
|
||||||
builder.append(getStringValue());
|
builder.append(getStringValue());
|
||||||
}else {
|
} else {
|
||||||
builder.append(String.format("0x%08x", getValue()));
|
builder.append(String.format("0x%08x", getValue()));
|
||||||
}
|
}
|
||||||
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) {
|
||||||
return null;
|
if (valueMap == null) {
|
||||||
}
|
return null;
|
||||||
int len= resValueMaps.length;
|
}
|
||||||
if(len==0){
|
return new ArrayBagItem(valueMap);
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
List<ArrayBagItem> results=new ArrayList<>();
|
public static ArrayBagItem create(ValueType valueType, int value) {
|
||||||
for(int i=0;i<len;i++){
|
if (valueType == null || valueType == ValueType.STRING) {
|
||||||
ArrayBagItem item=create(resValueMaps[i]);
|
return null;
|
||||||
if(item==null){
|
}
|
||||||
return null;
|
return new ArrayBagItem(valueType, value);
|
||||||
}
|
}
|
||||||
results.add(item);
|
|
||||||
}
|
protected static ArrayBagItem copyOf(ResValueMap resValueMap) {
|
||||||
return results.toArray(new ArrayBagItem[0]);
|
ValueType valueType = resValueMap.getValueType();
|
||||||
}
|
if (valueType == ValueType.STRING) {
|
||||||
public static ArrayBagItem create(ResValueMap resValueMap){
|
return new ArrayBagItem(resValueMap.getDataAsPoolString());
|
||||||
if(resValueMap ==null){
|
} else {
|
||||||
return null;
|
return new ArrayBagItem(valueType, resValueMap.getData());
|
||||||
}
|
}
|
||||||
ArrayBagItem item=new ArrayBagItem(resValueMap);
|
}
|
||||||
return item;
|
|
||||||
}
|
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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.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 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public class PluralsBag extends MapBag<PluralsQuantity, PluralsBagItem> {
|
||||||
public String toString() {
|
private PluralsBag(com.reandroid.arsc.value.Entry entry) {
|
||||||
StringBuilder builder=new StringBuilder();
|
super(entry);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The result of this is not always 100% accurate,
|
@Override
|
||||||
* in addition to this use your methods to cross check like type-name == "plurals"**/
|
protected PluralsBagItem createBagItem(ResValueMap valueMap, boolean copied) {
|
||||||
public static boolean isPlurals(ResTableMapEntry mapEntry){
|
if (copied) {
|
||||||
if(mapEntry==null){
|
return PluralsBagItem.copyOf(valueMap);
|
||||||
return false;
|
}
|
||||||
}
|
return PluralsBagItem.create(valueMap);
|
||||||
return PluralsBagItem.create(mapEntry.listResValueMap()) != null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static PluralsBag create(ResTableMapEntry mapEntry){
|
@Override
|
||||||
if(mapEntry==null){
|
protected ResValueMap newKey(PluralsQuantity key) {
|
||||||
return null;
|
ResValueMap valueMap = new ResValueMap();
|
||||||
}
|
valueMap.setParent(getMapArray());
|
||||||
PluralsBagItem[] bagItems=PluralsBagItem.create(mapEntry.listResValueMap());
|
valueMap.setNameHigh((short) 0x0100);
|
||||||
if(bagItems==null){
|
valueMap.setNameLow(key.getId());
|
||||||
return null;
|
return valueMap;
|
||||||
}
|
}
|
||||||
return new PluralsBag(bagItems);
|
|
||||||
}
|
@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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.item.StringItem;
|
||||||
import com.reandroid.arsc.chunk.TableBlock;
|
import com.reandroid.arsc.item.TableString;
|
||||||
import com.reandroid.arsc.item.TableString;
|
import com.reandroid.arsc.value.ResValueMap;
|
||||||
import com.reandroid.arsc.pool.TableStringPool;
|
import com.reandroid.arsc.value.ValueType;
|
||||||
import com.reandroid.arsc.value.Entry;
|
import com.reandroid.arsc.value.bag.BagItem;
|
||||||
import com.reandroid.arsc.value.ResValueMap;
|
|
||||||
import com.reandroid.arsc.value.ValueType;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
public class PluralsBagItem extends BagItem {
|
||||||
import java.util.HashSet;
|
private PluralsBagItem(ResValueMap bagItem) {
|
||||||
import java.util.List;
|
super(bagItem);
|
||||||
import java.util.Set;
|
}
|
||||||
|
|
||||||
public class PluralsBagItem {
|
private PluralsBagItem(StringItem str) {
|
||||||
private final ResValueMap mBagItem;
|
super(str);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private PluralsBagItem(ValueType valueType, int data) {
|
||||||
public String toString() {
|
super(valueType, data);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PluralsBagItem[] create(ResValueMap[] resValueMaps){
|
public PluralsQuantity getQuantity() {
|
||||||
if(resValueMaps ==null){
|
if (mBagItem == null || mBagItem.getName() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int len= resValueMaps.length;
|
return PluralsQuantity.valueOf(mBagItem);
|
||||||
if(len==0){
|
}
|
||||||
return null;
|
|
||||||
}
|
public String getQualityString() {
|
||||||
Set<PluralsQuantity> duplicates=new HashSet<>();
|
switch (getValueType()) {
|
||||||
List<PluralsBagItem> results=new ArrayList<>();
|
case STRING:
|
||||||
for(int i=0;i<len;i++){
|
return getStringValue();
|
||||||
ResValueMap resValueMap = resValueMaps[i];
|
case REFERENCE:
|
||||||
int high = (resValueMap.getName() >> 16) & 0xffff;
|
// TODO: resolve string reference based on language
|
||||||
if(high != 0x0100){
|
default:
|
||||||
return null;
|
throw new IllegalArgumentException("Not STR/REFERENCE ValueType=" + getValueType());
|
||||||
}
|
}
|
||||||
PluralsBagItem item=create(resValueMap);
|
}
|
||||||
if(item==null){
|
|
||||||
// If it reaches here type name is obfuscated
|
@Override
|
||||||
return null;
|
public String toString() {
|
||||||
}
|
StringBuilder builder = new StringBuilder();
|
||||||
PluralsQuantity quantity=item.getQuantity();
|
builder.append("<item quantity=\"");
|
||||||
if(duplicates.contains(quantity)){
|
builder.append(getQuantity());
|
||||||
return null;
|
builder.append("\">");
|
||||||
}
|
if (hasStringValue()) {
|
||||||
duplicates.add(quantity);
|
builder.append(getStringValue());
|
||||||
results.add(item);
|
} else {
|
||||||
}
|
builder.append(String.format("@0x%08x", getValue()));
|
||||||
return results.toArray(new PluralsBagItem[0]);
|
}
|
||||||
}
|
builder.append("</item>");
|
||||||
public static PluralsBagItem create(ResValueMap resValueMap){
|
return builder.toString();
|
||||||
PluralsBagItem item=new PluralsBagItem(resValueMap);
|
}
|
||||||
if(item.getQuantity()==null){
|
|
||||||
return null;
|
protected static PluralsBagItem create(ResValueMap resValueMap) {
|
||||||
}
|
if (resValueMap == null) {
|
||||||
return item;
|
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;
|
package com.reandroid.arsc.value.plurals;
|
||||||
|
|
||||||
|
|
||||||
public enum PluralsQuantity {
|
import com.reandroid.arsc.value.ResValueMap;
|
||||||
|
|
||||||
|
public enum PluralsQuantity {
|
||||||
OTHER((short) 0x0004),
|
OTHER((short) 0x0004),
|
||||||
ZERO((short) 0x0005),
|
ZERO((short) 0x0005),
|
||||||
ONE((short) 0x0006),
|
ONE((short) 0x0006),
|
||||||
@ -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;
|
||||||
|
@ -13,110 +13,124 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.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(){
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The result of this is not always 100% accurate,
|
public String getParentResourceName() {
|
||||||
* in addition to this use your methods to cross check like type-name == "plurals"**/
|
int id = getParentId();
|
||||||
public static boolean isStyle(ResTableMapEntry mapEntry){
|
if (id == 0) {
|
||||||
if(mapEntry==null){
|
return null;
|
||||||
return false;
|
}
|
||||||
}
|
com.reandroid.arsc.value.Entry entry = getEntry();
|
||||||
return StyleBag.create(mapEntry) != null;
|
if (entry == null) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
return entry.buildResourceName(id, '@', true);
|
||||||
|
}
|
||||||
|
|
||||||
public static StyleBag create(ResTableMapEntry mapEntry){
|
public int getParentId() {
|
||||||
if(mapEntry==null){
|
return getTableEntry().getParentId();
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
StyleBagItem[] bagItems=StyleBagItem.create(mapEntry.getValue().getChildes());
|
public int getResourceId() {
|
||||||
if(bagItems==null){
|
com.reandroid.arsc.value.Entry entry = getEntry();
|
||||||
return null;
|
if (entry == null) {
|
||||||
}
|
return 0;
|
||||||
return new StyleBag(bagItems);
|
}
|
||||||
}
|
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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.decoder.ValueDecoder;
|
||||||
import com.reandroid.arsc.value.ResValueMap;
|
import com.reandroid.arsc.item.StringItem;
|
||||||
import com.reandroid.arsc.value.ValueType;
|
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;
|
public class StyleBagItem extends BagItem {
|
||||||
import java.util.List;
|
private StyleBagItem(ResValueMap bagItem) {
|
||||||
|
super(bagItem);
|
||||||
|
}
|
||||||
|
|
||||||
public class StyleBagItem {
|
private StyleBagItem(ValueType valueType, int data) {
|
||||||
private final ResValueMap mBagItem;
|
super(valueType, data);
|
||||||
public StyleBagItem(ResValueMap bagItem){
|
}
|
||||||
this.mBagItem=bagItem;
|
|
||||||
}
|
|
||||||
public ResValueMap getBagItem() {
|
|
||||||
return mBagItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName(){
|
private StyleBagItem(StringItem str) {
|
||||||
Entry block=getBagItem().getEntry();
|
super(str);
|
||||||
if(block==null){
|
}
|
||||||
return null;
|
|
||||||
}
|
public String getName() {
|
||||||
char prefix=0;
|
if (mBagItem == null) {
|
||||||
return block.buildResourceName(getNameId(), prefix, false);
|
return null;
|
||||||
}
|
}
|
||||||
public int getNameId(){
|
Entry block = mBagItem.getEntry();
|
||||||
return getBagItem().getName();
|
if (block == null) {
|
||||||
}
|
return null;
|
||||||
public boolean hasStringValue(){
|
}
|
||||||
return getValueType()== ValueType.STRING;
|
char prefix = 0;
|
||||||
}
|
return block.buildResourceName(mBagItem.getName(), prefix, false);
|
||||||
public boolean hasReferenceValue(){
|
}
|
||||||
return getValueType()==ValueType.REFERENCE;
|
|
||||||
}
|
public int getNameId() {
|
||||||
public boolean hasAttributeValue(){
|
if (mBagItem == null) {
|
||||||
return getValueType()==ValueType.REFERENCE;
|
return 0;
|
||||||
}
|
}
|
||||||
public String getValueAsReference(){
|
return mBagItem.getName();
|
||||||
ValueType valueType=getValueType();
|
}
|
||||||
if(valueType!=ValueType.REFERENCE && valueType!=ValueType.ATTRIBUTE){
|
|
||||||
throw new IllegalArgumentException("Not REF ValueType="+valueType);
|
public boolean hasAttributeValue() {
|
||||||
}
|
return getValueType() == ValueType.ATTRIBUTE;
|
||||||
Entry entry =getBagItem().getEntry();
|
}
|
||||||
if(entry ==null){
|
|
||||||
return null;
|
public String getValueAsReference() {
|
||||||
}
|
ValueType valueType = getValueType();
|
||||||
char prefix='@';
|
if (valueType != ValueType.REFERENCE && valueType != ValueType.ATTRIBUTE) {
|
||||||
boolean includeType=true;
|
throw new IllegalArgumentException("Not REF ValueType=" + valueType);
|
||||||
if(valueType==ValueType.ATTRIBUTE){
|
}
|
||||||
prefix='?';
|
Entry entry = getBagItem().getEntry();
|
||||||
includeType=false;
|
if (entry == null) {
|
||||||
}
|
return null;
|
||||||
int id=getValue();
|
}
|
||||||
return entry.buildResourceName(id, prefix, includeType);
|
char prefix = '@';
|
||||||
}
|
boolean includeType = true;
|
||||||
public String getStringValue(){
|
if (valueType == ValueType.ATTRIBUTE) {
|
||||||
return mBagItem.getValueAsString();
|
prefix = '?';
|
||||||
}
|
includeType = false;
|
||||||
public ValueType getValueType(){
|
}
|
||||||
return getBagItem().getValueType();
|
int id = getValue();
|
||||||
}
|
return entry.buildResourceName(id, prefix, includeType);
|
||||||
public int getValue(){
|
}
|
||||||
return getBagItem().getData();
|
|
||||||
}
|
@Override
|
||||||
@Override
|
public String toString() {
|
||||||
public String toString() {
|
StringBuilder builder = new StringBuilder();
|
||||||
StringBuilder builder=new StringBuilder();
|
builder.append("<item name=\"");
|
||||||
builder.append("<item name=\"");
|
String name = getName();
|
||||||
String name=getName();
|
if (name == null) {
|
||||||
if(name==null){
|
name = String.format("@0x%08x", getNameId());
|
||||||
name=String.format("@0x%08x", getNameId());
|
}
|
||||||
}
|
builder.append(name);
|
||||||
builder.append(name);
|
builder.append("\">");
|
||||||
builder.append("\">");
|
if (hasStringValue()) {
|
||||||
if(hasStringValue()){
|
builder.append(getStringValue());
|
||||||
builder.append(getStringValue());
|
}
|
||||||
}
|
String val = null;
|
||||||
String val=null;
|
if (hasReferenceValue() || hasAttributeValue()) {
|
||||||
if(hasReferenceValue()||hasAttributeValue()) {
|
val = getValueAsReference();
|
||||||
val=getValueAsReference();
|
}
|
||||||
}
|
if (val == null) {
|
||||||
if(val==null) {
|
val = String.format("0x%08x", getValue());
|
||||||
val=String.format("0x%08x", getValue());
|
}
|
||||||
}
|
builder.append(val);
|
||||||
builder.append(val);
|
builder.append("</item>");
|
||||||
builder.append("</item>");
|
return builder.toString();
|
||||||
return builder.toString();
|
}
|
||||||
}
|
|
||||||
public static StyleBagItem[] create(ResValueMap[] resValueMaps){
|
protected static StyleBagItem create(ResValueMap resValueMap) {
|
||||||
if(resValueMaps ==null){
|
if (resValueMap == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int len= resValueMaps.length;
|
return new StyleBagItem(resValueMap);
|
||||||
if(len==0){
|
}
|
||||||
return null;
|
|
||||||
}
|
public static StyleBagItem create(ValueType valueType, int value) {
|
||||||
List<StyleBagItem> results=new ArrayList<>();
|
if (valueType == null || valueType == ValueType.STRING) {
|
||||||
for(int i=0;i<len;i++){
|
return null;
|
||||||
StyleBagItem item=create(resValueMaps[i]);
|
}
|
||||||
if(item==null){
|
return new StyleBagItem(valueType, value);
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
results.add(item);
|
protected static StyleBagItem copyOf(ResValueMap resValueMap) {
|
||||||
}
|
ValueType valueType = resValueMap.getValueType();
|
||||||
return results.toArray(new StyleBagItem[0]);
|
if (valueType == ValueType.STRING) {
|
||||||
}
|
return new StyleBagItem(resValueMap.getDataAsPoolString());
|
||||||
public static StyleBagItem create(ResValueMap resValueMap){
|
} else {
|
||||||
if(resValueMap ==null){
|
return new StyleBagItem(valueType, resValueMap.getData());
|
||||||
return null;
|
}
|
||||||
}
|
}
|
||||||
return new StyleBagItem(resValueMap);
|
|
||||||
}
|
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