mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-29 22:04:25 +02:00
better complex entry structure
This commit is contained in:
parent
f0747a6b4f
commit
3a5e7087a8
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -258,7 +258,7 @@ import java.util.zip.ZipEntry;
|
||||
return false;
|
||||
}
|
||||
TableEntry<?, ?> tableEntry = entry.getTableEntry();
|
||||
if(tableEntry instanceof ResTableMapEntry){
|
||||
if(tableEntry instanceof CompoundEntry){
|
||||
return false;
|
||||
}
|
||||
if(!(tableEntry instanceof ResTableEntry)){
|
||||
|
@ -16,10 +16,9 @@
|
||||
package com.reandroid.apk.xmldecoder;
|
||||
|
||||
import com.reandroid.apk.XmlHelper;
|
||||
import com.reandroid.arsc.array.CompoundItemArray;
|
||||
import com.reandroid.arsc.util.HexUtil;
|
||||
import com.reandroid.arsc.value.Entry;
|
||||
import com.reandroid.arsc.value.ResTableMapEntry;
|
||||
import com.reandroid.arsc.value.ValueType;
|
||||
import com.reandroid.arsc.value.*;
|
||||
import com.reandroid.arsc.value.attribute.AttributeBag;
|
||||
import com.reandroid.arsc.value.attribute.AttributeBagItem;
|
||||
import com.reandroid.common.EntryStore;
|
||||
@ -39,16 +38,18 @@ class BagDecoderAttr<OUTPUT> extends BagDecoder<OUTPUT>{
|
||||
writer.startTag(tag);
|
||||
writer.attribute("name", entry.getName());
|
||||
AttributeBag attributeBag = AttributeBag.create(mapEntry.getValue());
|
||||
writeParentAttributes(writer, attributeBag);
|
||||
writeParentAttributes(writer, mapEntry.getValue());
|
||||
ResValueMap formatsMap = mapEntry.getByType(AttributeType.FORMATS);
|
||||
|
||||
boolean is_flag = AttributeTypeFormat.FLAG.matches(formatsMap.getData());
|
||||
|
||||
boolean is_flag = attributeBag.isFlag();
|
||||
String childTag = is_flag ? "flag" : "enum";
|
||||
|
||||
AttributeBagItem[] bagItems = attributeBag.getBagItems();
|
||||
|
||||
EntryStore entryStore = getEntryStore();
|
||||
|
||||
for(int i=0;i< bagItems.length;i++){
|
||||
for(int i = 0; i < bagItems.length; i++){
|
||||
AttributeBagItem item = bagItems[i];
|
||||
if(item.isType()){
|
||||
continue;
|
||||
@ -63,7 +64,7 @@ class BagDecoderAttr<OUTPUT> extends BagDecoder<OUTPUT>{
|
||||
if(item.getBagItem().getValueType() == ValueType.INT_HEX){
|
||||
value = HexUtil.toHex8(rawVal);
|
||||
}else {
|
||||
value = String.valueOf(rawVal);
|
||||
value = Integer.toString(rawVal);
|
||||
}
|
||||
writer.text(value);
|
||||
|
||||
@ -72,6 +73,24 @@ class BagDecoderAttr<OUTPUT> extends BagDecoder<OUTPUT>{
|
||||
return writer.endTag(tag);
|
||||
}
|
||||
|
||||
private void writeParentAttributes(EntryWriter<OUTPUT> writer, CompoundItemArray<? extends ResValueMap> itemArray) throws IOException {
|
||||
String formats = AttributeTypeFormat.toString(itemArray.getFormats());
|
||||
if(formats!=null){
|
||||
writer.attribute(AttributeType.FORMATS.getName(), formats);
|
||||
}
|
||||
ResValueMap item = itemArray.getByType(AttributeType.MIN);
|
||||
if(item != null){
|
||||
writer.attribute(AttributeType.MIN.getName(), Integer.toString(item.getData()));
|
||||
}
|
||||
item = itemArray.getByType(AttributeType.MAX);
|
||||
if(item != null){
|
||||
writer.attribute(AttributeType.MAX.getName(), Integer.toString(item.getData()));
|
||||
}
|
||||
item = itemArray.getByType(AttributeType.L10N);;
|
||||
if(item != null){
|
||||
writer.attribute(AttributeType.L10N.getName(), Integer.toString(item.getData()));
|
||||
}
|
||||
}
|
||||
private void writeParentAttributes(EntryWriter<OUTPUT> writer, AttributeBag attributeBag) throws IOException {
|
||||
String formats= attributeBag.decodeValueType();
|
||||
if(formats!=null){
|
||||
|
@ -17,11 +17,9 @@ package com.reandroid.apk.xmldecoder;
|
||||
|
||||
import com.reandroid.apk.XmlHelper;
|
||||
import com.reandroid.arsc.chunk.PackageBlock;
|
||||
import com.reandroid.arsc.decoder.ValueDecoder;
|
||||
import com.reandroid.arsc.value.*;
|
||||
import com.reandroid.arsc.value.plurals.PluralsQuantity;
|
||||
import com.reandroid.common.EntryStore;
|
||||
import com.reandroid.xml.XMLElement;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -46,12 +44,11 @@ class BagDecoderPlural<OUTPUT> extends BagDecoder<OUTPUT>{
|
||||
writer.enableIndent(true);
|
||||
writer.startTag(childTag);
|
||||
|
||||
PluralsQuantity quantity =
|
||||
PluralsQuantity.valueOf((short) (valueMap.getName() & 0xffff));
|
||||
if(quantity == null){
|
||||
AttributeType quantity = valueMap.getAttributeType();
|
||||
if(quantity == null || !quantity.isPlural()){
|
||||
throw new IOException("Unknown plural quantity: " + valueMap);
|
||||
}
|
||||
writer.attribute("quantity", quantity.toString());
|
||||
writer.attribute("quantity", quantity.getName());
|
||||
|
||||
writeText(writer, packageBlock, valueMap);
|
||||
|
||||
|
113
src/main/java/com/reandroid/arsc/array/CompoundItemArray.java
Normal file
113
src/main/java/com/reandroid/arsc/array/CompoundItemArray.java
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.array;
|
||||
|
||||
import com.reandroid.arsc.base.BlockArray;
|
||||
import com.reandroid.arsc.value.AttributeType;
|
||||
import com.reandroid.arsc.value.AttributeTypeFormat;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONArray;
|
||||
|
||||
public abstract class CompoundItemArray<T extends ResValueMap> extends BlockArray<T> implements JSONConvert<JSONArray> {
|
||||
public CompoundItemArray(){
|
||||
super();
|
||||
}
|
||||
public AttributeTypeFormat[] getFormats(){
|
||||
ResValueMap formatsMap = getByType(AttributeType.FORMATS);
|
||||
if(formatsMap != null){
|
||||
return AttributeTypeFormat.valuesOf(formatsMap.getData());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public boolean containsType(AttributeType attributeType){
|
||||
for(T valueMap : getChildes()){
|
||||
if(attributeType == valueMap.getAttributeType()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public T getByType(AttributeType attributeType){
|
||||
if(attributeType == null){
|
||||
return null;
|
||||
}
|
||||
for(T valueMap : getChildes()){
|
||||
if(attributeType == valueMap.getAttributeType()){
|
||||
return valueMap;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public T getByName(int name){
|
||||
for(T resValueMap : getChildes()){
|
||||
if(resValueMap != null && name == resValueMap.getName()){
|
||||
return resValueMap;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected void onRefreshed() {
|
||||
}
|
||||
public void onRemoved(){
|
||||
for(T resValueMap : getChildes()){
|
||||
resValueMap.onRemoved();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void clearChildes(){
|
||||
this.onRemoved();
|
||||
super.clearChildes();
|
||||
}
|
||||
@Override
|
||||
public JSONArray toJson() {
|
||||
JSONArray jsonArray=new JSONArray();
|
||||
if(isNull()){
|
||||
return jsonArray;
|
||||
}
|
||||
T[] childes = getChildes();
|
||||
for(int i = 0; i < childes.length; i++){
|
||||
jsonArray.put(i, childes[i].toJson());
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
@Override
|
||||
public void fromJson(JSONArray json){
|
||||
clearChildes();
|
||||
if(json==null){
|
||||
return;
|
||||
}
|
||||
int count=json.length();
|
||||
ensureSize(count);
|
||||
for(int i=0;i<count;i++){
|
||||
get(i).fromJson(json.getJSONObject(i));
|
||||
}
|
||||
}
|
||||
public void merge(CompoundItemArray<?> mapArray){
|
||||
if(mapArray == null || mapArray == this){
|
||||
return;
|
||||
}
|
||||
clearChildes();
|
||||
int count = mapArray.childesCount();
|
||||
ensureSize(count);
|
||||
for(int i=0;i<count;i++){
|
||||
ResValueMap coming = mapArray.get(i);
|
||||
ResValueMap exist = get(i);
|
||||
exist.merge(coming);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -15,24 +15,12 @@
|
||||
*/
|
||||
package com.reandroid.arsc.array;
|
||||
|
||||
import com.reandroid.arsc.base.BlockArray;
|
||||
import com.reandroid.arsc.value.ResValueMap;
|
||||
import com.reandroid.json.JSONConvert;
|
||||
import com.reandroid.json.JSONArray;
|
||||
|
||||
public class ResValueMapArray extends BlockArray<ResValueMap> implements JSONConvert<JSONArray> {
|
||||
public class ResValueMapArray extends CompoundItemArray<ResValueMap> {
|
||||
public ResValueMapArray(){
|
||||
super();
|
||||
}
|
||||
|
||||
public ResValueMap getByName(int name){
|
||||
for(ResValueMap resValueMap:listItems()){
|
||||
if(resValueMap != null &&name == resValueMap.getName()){
|
||||
return resValueMap;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public ResValueMap newInstance() {
|
||||
return new ResValueMap();
|
||||
@ -42,55 +30,4 @@ public class ResValueMapArray extends BlockArray<ResValueMap> implements JSONCon
|
||||
public ResValueMap[] newInstance(int len) {
|
||||
return new ResValueMap[len];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRefreshed() {
|
||||
}
|
||||
public void onRemoved(){
|
||||
for(ResValueMap resValueMap:listItems()){
|
||||
resValueMap.onRemoved();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void clearChildes(){
|
||||
this.onRemoved();
|
||||
super.clearChildes();
|
||||
}
|
||||
@Override
|
||||
public JSONArray toJson() {
|
||||
JSONArray jsonArray=new JSONArray();
|
||||
if(isNull()){
|
||||
return jsonArray;
|
||||
}
|
||||
ResValueMap[] childes = getChildes();
|
||||
for(int i=0;i<childes.length;i++){
|
||||
jsonArray.put(i, childes[i].toJson());
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
@Override
|
||||
public void fromJson(JSONArray json){
|
||||
clearChildes();
|
||||
if(json==null){
|
||||
return;
|
||||
}
|
||||
int count=json.length();
|
||||
ensureSize(count);
|
||||
for(int i=0;i<count;i++){
|
||||
get(i).fromJson(json.getJSONObject(i));
|
||||
}
|
||||
}
|
||||
public void merge(ResValueMapArray bagItemArray){
|
||||
if(bagItemArray==null||bagItemArray==this){
|
||||
return;
|
||||
}
|
||||
clearChildes();
|
||||
int count=bagItemArray.childesCount();
|
||||
ensureSize(count);
|
||||
for(int i=0;i<count;i++){
|
||||
ResValueMap coming=bagItemArray.get(i);
|
||||
ResValueMap exist=get(i);
|
||||
exist.merge(coming);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -429,11 +429,11 @@ public class ValueDecoder {
|
||||
return null;
|
||||
}
|
||||
TableEntry<?, ?> tableEntry = entry.getTableEntry();
|
||||
if(tableEntry == null || (tableEntry instanceof ResTableMapEntry)){
|
||||
if(tableEntry == null || (tableEntry instanceof CompoundEntry)){
|
||||
return null;
|
||||
}
|
||||
ResValue resValue =(ResValue) tableEntry.getValue();
|
||||
int resourceId= resValue.getData();
|
||||
ResValue resValue = (ResValue) tableEntry.getValue();
|
||||
int resourceId = resValue.getData();
|
||||
ValueType valueType= resValue.getValueType();
|
||||
return buildReferenceValue(store, entry, valueType, resourceId);
|
||||
}
|
||||
|
80
src/main/java/com/reandroid/arsc/value/AttributeType.java
Normal file
80
src/main/java/com/reandroid/arsc/value/AttributeType.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value;
|
||||
|
||||
public enum AttributeType {
|
||||
|
||||
FORMATS(0x01000000),
|
||||
MIN(0x01000001),
|
||||
MAX(0x01000002),
|
||||
L10N(0x01000003),
|
||||
|
||||
OTHER(0x01000004),
|
||||
ZERO(0x01000005),
|
||||
ONE(0x01000006),
|
||||
TWO(0x01000007),
|
||||
FEW(0x01000008),
|
||||
MANY(0x01000009);
|
||||
|
||||
private final int id;
|
||||
AttributeType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isPlural(){
|
||||
int i = id & 0xffff;
|
||||
return i>=4 && i<=9;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name().toLowerCase();
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
return getName();
|
||||
}
|
||||
|
||||
public static AttributeType valueOf(int value){
|
||||
for(AttributeType type:VALUES){
|
||||
if(type.getId() == value){
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static AttributeType fromName(String name){
|
||||
if(name == null){
|
||||
return null;
|
||||
}
|
||||
name = name.toUpperCase();
|
||||
if("FORMAT".equals(name)){
|
||||
return FORMATS;
|
||||
}
|
||||
for(AttributeType type:VALUES){
|
||||
if(name.equals(type.name())){
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final AttributeType[] VALUES = values();
|
||||
}
|
251
src/main/java/com/reandroid/arsc/value/AttributeTypeFormat.java
Normal file
251
src/main/java/com/reandroid/arsc/value/AttributeTypeFormat.java
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value;
|
||||
|
||||
public enum AttributeTypeFormat {
|
||||
|
||||
REFERENCE(1<<0,
|
||||
new ValueType[]{
|
||||
ValueType.REFERENCE,
|
||||
ValueType.ATTRIBUTE,
|
||||
ValueType.DYNAMIC_REFERENCE,
|
||||
ValueType.DYNAMIC_ATTRIBUTE,
|
||||
ValueType.NULL,
|
||||
}),
|
||||
STRING(1<<1, new ValueType[]{
|
||||
ValueType.STRING
|
||||
}),
|
||||
INTEGER(1<<2, new ValueType[]{
|
||||
ValueType.INT_DEC,
|
||||
ValueType.INT_HEX
|
||||
}),
|
||||
BOOL(1<<3, new ValueType[]{
|
||||
ValueType.INT_BOOLEAN
|
||||
}),
|
||||
COLOR(1<<4, new ValueType[]{
|
||||
ValueType.INT_COLOR_RGB4,
|
||||
ValueType.INT_COLOR_ARGB4,
|
||||
ValueType.INT_COLOR_RGB8,
|
||||
ValueType.INT_COLOR_ARGB8
|
||||
}),
|
||||
FLOAT(1<<5, new ValueType[]{
|
||||
ValueType.FLOAT
|
||||
}),
|
||||
DIMENSION(1<<6, new ValueType[]{
|
||||
ValueType.DIMENSION
|
||||
}),
|
||||
FRACTION(1<<7, new ValueType[]{
|
||||
ValueType.FRACTION
|
||||
}),
|
||||
ANY(0x0000FFFF, ValueType.values().clone()),
|
||||
|
||||
ENUM(1<<16, new ValueType[]{
|
||||
ValueType.INT_DEC,
|
||||
ValueType.INT_HEX
|
||||
}),
|
||||
FLAG(1<<17, new ValueType[]{
|
||||
ValueType.INT_HEX,
|
||||
ValueType.INT_DEC
|
||||
});
|
||||
|
||||
private final int mask;
|
||||
private final ValueType[] valueTypes;
|
||||
|
||||
AttributeTypeFormat(int mask, ValueType[] valueTypes) {
|
||||
this.mask = mask;
|
||||
this.valueTypes = valueTypes;
|
||||
}
|
||||
|
||||
public int getMask() {
|
||||
return mask;
|
||||
}
|
||||
public boolean matches(int value){
|
||||
int mask = this.mask;
|
||||
return (value & mask) == mask;
|
||||
}
|
||||
|
||||
public ValueType[] getValueTypes() {
|
||||
return valueTypes.clone();
|
||||
}
|
||||
public boolean contains(ValueType valueType){
|
||||
ValueType[] valueTypes = this.valueTypes;
|
||||
for(int i = 0; i < valueTypes.length; i++){
|
||||
if(valueType == valueTypes[i]){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public String getName(){
|
||||
return name().toLowerCase();
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(getName());
|
||||
builder.append('{');
|
||||
ValueType[] valueTypes = this.valueTypes;
|
||||
for(int i = 0; i < valueTypes.length; i++){
|
||||
if(i != 0){
|
||||
builder.append(',');
|
||||
}
|
||||
builder.append(valueTypes[i]);
|
||||
}
|
||||
builder.append('}');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String toString(int typeValue){
|
||||
return toString(valuesOf(typeValue));
|
||||
}
|
||||
public static String toString(AttributeTypeFormat[] typeValues){
|
||||
if(typeValues == null || typeValues.length == 0){
|
||||
return null;
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
boolean appendOnce = false;
|
||||
int appendedTypes = 0;
|
||||
for(AttributeTypeFormat typeValue : typeValues){
|
||||
if(typeValue == ENUM || typeValue == FLAG){
|
||||
continue;
|
||||
}
|
||||
if(typeValue == AttributeTypeFormat.ANY){
|
||||
return AttributeTypeFormat.ANY.getName();
|
||||
}
|
||||
int mask = typeValue.getMask();
|
||||
if((appendedTypes & mask) == mask){
|
||||
continue;
|
||||
}
|
||||
if(appendOnce){
|
||||
builder.append('|');
|
||||
}
|
||||
builder.append(typeValue.getName());
|
||||
appendOnce = true;
|
||||
appendedTypes = appendedTypes | mask;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
public static int sum(AttributeTypeFormat[] typeValues){
|
||||
if(typeValues == null){
|
||||
return 0;
|
||||
}
|
||||
int result = 0;
|
||||
for(AttributeTypeFormat typeValue:typeValues){
|
||||
if(typeValue==null){
|
||||
continue;
|
||||
}
|
||||
result |= typeValue.getMask();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static AttributeTypeFormat[] valuesOf(int value){
|
||||
AttributeTypeFormat[] tmp = new AttributeTypeFormat[VALUES.length];
|
||||
int length = 0;
|
||||
for(AttributeTypeFormat typeValue : VALUES){
|
||||
int mask = typeValue.getMask();
|
||||
if(mask == value){
|
||||
return new AttributeTypeFormat[]{typeValue};
|
||||
}
|
||||
if(typeValue == ANY){
|
||||
continue;
|
||||
}
|
||||
if((value & mask) == mask){
|
||||
tmp[length] = typeValue;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
if(length == 0){
|
||||
return null;
|
||||
}
|
||||
AttributeTypeFormat[] results = new AttributeTypeFormat[length];
|
||||
System.arraycopy(tmp, 0, results, 0, length);
|
||||
return results;
|
||||
}
|
||||
public static AttributeTypeFormat[] valuesOf(String valuesString){
|
||||
if(valuesString == null){
|
||||
return null;
|
||||
}
|
||||
valuesString = valuesString.trim();
|
||||
String[] valueNames = valuesString.split("\\s*\\|\\s*");
|
||||
AttributeTypeFormat[] tmp = new AttributeTypeFormat[VALUES.length];
|
||||
int length = 0;
|
||||
for(String name:valueNames){
|
||||
AttributeTypeFormat typeValue = fromName(name);
|
||||
if(typeValue!=null){
|
||||
tmp[length] = typeValue;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
if(length == 0){
|
||||
return null;
|
||||
}
|
||||
AttributeTypeFormat[] results = new AttributeTypeFormat[length];
|
||||
System.arraycopy(tmp, 0, results, 0, length);
|
||||
return results;
|
||||
}
|
||||
public static AttributeTypeFormat valueOf(int mask){
|
||||
for(AttributeTypeFormat typeValue:VALUES){
|
||||
if(typeValue.getMask() == mask){
|
||||
return typeValue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static AttributeTypeFormat typeOf(int mask){
|
||||
for(AttributeTypeFormat typeValue:TYPES){
|
||||
if(typeValue.matches(mask)){
|
||||
return typeValue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static AttributeTypeFormat fromName(String name){
|
||||
if(name==null){
|
||||
return null;
|
||||
}
|
||||
name = name.trim().toUpperCase();
|
||||
for(AttributeTypeFormat typeValue:VALUES){
|
||||
if(name.equals(typeValue.name())){
|
||||
return typeValue;
|
||||
}
|
||||
}
|
||||
for(AttributeTypeFormat typeValue:TYPES){
|
||||
if(name.equals(typeValue.name())){
|
||||
return typeValue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final AttributeTypeFormat[] VALUES = new AttributeTypeFormat[]{
|
||||
REFERENCE,
|
||||
STRING,
|
||||
INTEGER,
|
||||
BOOL,
|
||||
COLOR,
|
||||
FLOAT,
|
||||
DIMENSION,
|
||||
FRACTION,
|
||||
ANY
|
||||
};
|
||||
|
||||
private static final AttributeTypeFormat[] TYPES = new AttributeTypeFormat[]{
|
||||
ENUM,
|
||||
FLAG
|
||||
};
|
||||
}
|
114
src/main/java/com/reandroid/arsc/value/CompoundEntry.java
Normal file
114
src/main/java/com/reandroid/arsc/value/CompoundEntry.java
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2022 github.com/REAndroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.reandroid.arsc.value;
|
||||
|
||||
import com.reandroid.arsc.array.CompoundItemArray;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
public abstract class CompoundEntry<ITEM extends ResValueMap, ARRAY extends CompoundItemArray<ITEM>> extends TableEntry<EntryHeaderMap, ARRAY> {
|
||||
public CompoundEntry(ARRAY mapArray){
|
||||
super(new EntryHeaderMap(), mapArray);
|
||||
}
|
||||
// Valid for type attr
|
||||
public AttributeTypeFormat[] getAttributeTypeFormats(){
|
||||
ITEM item = getByType(AttributeType.FORMATS);
|
||||
if(item != null){
|
||||
return item.getAttributeTypeFormats();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public boolean containsType(AttributeType attributeType){
|
||||
return getValue().containsType(attributeType);
|
||||
}
|
||||
public ITEM getByType(AttributeType attributeType){
|
||||
return getValue().getByType(attributeType);
|
||||
}
|
||||
public void refresh(){
|
||||
getHeader().setValuesCount(getValue().childesCount());
|
||||
}
|
||||
public ITEM[] listResValueMap(){
|
||||
return getValue().getChildes();
|
||||
}
|
||||
public int getParentId(){
|
||||
return getHeader().getParentId();
|
||||
}
|
||||
public void setParentId(int parentId){
|
||||
getHeader().setParentId(parentId);
|
||||
}
|
||||
public int getValuesCount(){
|
||||
return getHeader().getValuesCount();
|
||||
}
|
||||
public void setValuesCount(int valuesCount){
|
||||
getHeader().setValuesCount(valuesCount);
|
||||
getValue().setChildesCount(valuesCount);
|
||||
}
|
||||
@Override
|
||||
void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
for(ITEM item : listResValueMap()){
|
||||
item.linkTableStrings(tableStringPool);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
void onHeaderLoaded(ValueHeader valueHeader){
|
||||
getValue().setChildesCount(getValuesCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
void onRemoved(){
|
||||
getHeader().onRemoved();
|
||||
getValue().onRemoved();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject toJson() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
getHeader().toJson(jsonObject);
|
||||
jsonObject.put(NAME_values, getValue().toJson());
|
||||
return jsonObject;
|
||||
}
|
||||
@Override
|
||||
public void fromJson(JSONObject json) {
|
||||
getHeader().fromJson(json);
|
||||
getValue().fromJson(json.optJSONArray(NAME_values));
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(getHeader());
|
||||
ITEM[] valueMaps = listResValueMap();
|
||||
int len = valueMaps.length;
|
||||
int max = len;
|
||||
if(max>4){
|
||||
max = 4;
|
||||
}
|
||||
for(int i=0;i<max;i++){
|
||||
builder.append("\n ");
|
||||
builder.append(valueMaps[i]);
|
||||
}
|
||||
if(len>0){
|
||||
if(max!=len){
|
||||
builder.append("\n ...");
|
||||
}
|
||||
builder.append("\n ");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static final String NAME_values = "values";
|
||||
}
|
@ -302,7 +302,7 @@ public class Entry extends Block implements JSONConvert<JSONObject> {
|
||||
}
|
||||
|
||||
public boolean isComplex(){
|
||||
return getTableEntry() instanceof ResTableMapEntry;
|
||||
return getTableEntry() instanceof CompoundEntry;
|
||||
}
|
||||
public void setTableEntry(TableEntry<?, ?> tableEntry){
|
||||
if(tableEntry==this.mTableEntry){
|
||||
|
@ -16,47 +16,10 @@
|
||||
package com.reandroid.arsc.value;
|
||||
|
||||
import com.reandroid.arsc.array.ResValueMapArray;
|
||||
import com.reandroid.arsc.pool.TableStringPool;
|
||||
import com.reandroid.json.JSONObject;
|
||||
|
||||
public class ResTableMapEntry extends TableEntry<EntryHeaderMap, ResValueMapArray> {
|
||||
public class ResTableMapEntry extends CompoundEntry<ResValueMap, ResValueMapArray> {
|
||||
public ResTableMapEntry(){
|
||||
super(new EntryHeaderMap(), new ResValueMapArray());
|
||||
}
|
||||
public void refresh(){
|
||||
getHeader().setValuesCount(getValue().childesCount());
|
||||
}
|
||||
public ResValueMap[] listResValueMap(){
|
||||
return getValue().getChildes();
|
||||
}
|
||||
public int getParentId(){
|
||||
return getHeader().getParentId();
|
||||
}
|
||||
public void setParentId(int parentId){
|
||||
getHeader().setParentId(parentId);
|
||||
}
|
||||
public int getValuesCount(){
|
||||
return getHeader().getValuesCount();
|
||||
}
|
||||
public void setValuesCount(int valuesCount){
|
||||
getHeader().setValuesCount(valuesCount);
|
||||
getValue().setChildesCount(valuesCount);
|
||||
}
|
||||
@Override
|
||||
void linkTableStringsInternal(TableStringPool tableStringPool){
|
||||
for(ResValueMap resValueMap : listResValueMap()){
|
||||
resValueMap.linkTableStrings(tableStringPool);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
void onHeaderLoaded(ValueHeader valueHeader){
|
||||
getValue().setChildesCount(getValuesCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
void onRemoved(){
|
||||
getHeader().onRemoved();
|
||||
getValue().onRemoved();
|
||||
super(new ResValueMapArray());
|
||||
}
|
||||
@Override
|
||||
boolean shouldMerge(TableEntry<?, ?> tableEntry){
|
||||
@ -80,42 +43,4 @@ public class ResTableMapEntry extends TableEntry<EntryHeaderMap, ResValueMapArra
|
||||
getValue().merge(coming.getValue());
|
||||
refresh();
|
||||
}
|
||||
@Override
|
||||
public JSONObject toJson() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
getHeader().toJson(jsonObject);
|
||||
jsonObject.put(NAME_values, getValue().toJson());
|
||||
return jsonObject;
|
||||
}
|
||||
@Override
|
||||
public void fromJson(JSONObject json) {
|
||||
getHeader().fromJson(json);
|
||||
getValue().fromJson(json.optJSONArray(NAME_values));
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(getHeader());
|
||||
ResValueMap[] valueMaps = listResValueMap();
|
||||
int len = valueMaps.length;
|
||||
int max = len;
|
||||
if(max>4){
|
||||
max = 4;
|
||||
}
|
||||
for(int i=0;i<max;i++){
|
||||
builder.append("\n ");
|
||||
builder.append(valueMaps[i]);
|
||||
}
|
||||
if(len>0){
|
||||
if(max!=len){
|
||||
builder.append("\n ...");
|
||||
}
|
||||
builder.append("\n ");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static final String NAME_values = "values";
|
||||
}
|
||||
|
@ -26,6 +26,22 @@ public class ResValueMap extends ValueItem implements AttributeValue{
|
||||
super(12, OFFSET_SIZE);
|
||||
}
|
||||
|
||||
public AttributeType getAttributeType(){
|
||||
return AttributeType.valueOf(getNameResourceID());
|
||||
}
|
||||
public void setAttributeType(AttributeType attributeType){
|
||||
setNameResourceID(attributeType.getId());
|
||||
}
|
||||
public AttributeTypeFormat[] getAttributeTypeFormats(){
|
||||
AttributeType attributeType = getAttributeType();
|
||||
if(attributeType != AttributeType.FORMATS){
|
||||
return null;
|
||||
}
|
||||
return AttributeTypeFormat.valuesOf(getData());
|
||||
}
|
||||
public void setAttributeTypeFormats(AttributeTypeFormat[] formats){
|
||||
setData(AttributeTypeFormat.sum(formats));
|
||||
}
|
||||
public Entry getEntry(){
|
||||
return getParent(Entry.class);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user