mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-02 15:14:26 +02:00
better complex entry structure
This commit is contained in:
parent
f0747a6b4f
commit
3a5e7087a8
@ -258,7 +258,7 @@ import java.util.zip.ZipEntry;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TableEntry<?, ?> tableEntry = entry.getTableEntry();
|
TableEntry<?, ?> tableEntry = entry.getTableEntry();
|
||||||
if(tableEntry instanceof ResTableMapEntry){
|
if(tableEntry instanceof CompoundEntry){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!(tableEntry instanceof ResTableEntry)){
|
if(!(tableEntry instanceof ResTableEntry)){
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
package com.reandroid.apk.xmldecoder;
|
package com.reandroid.apk.xmldecoder;
|
||||||
|
|
||||||
import com.reandroid.apk.XmlHelper;
|
import com.reandroid.apk.XmlHelper;
|
||||||
|
import com.reandroid.arsc.array.CompoundItemArray;
|
||||||
import com.reandroid.arsc.util.HexUtil;
|
import com.reandroid.arsc.util.HexUtil;
|
||||||
import com.reandroid.arsc.value.Entry;
|
import com.reandroid.arsc.value.*;
|
||||||
import com.reandroid.arsc.value.ResTableMapEntry;
|
|
||||||
import com.reandroid.arsc.value.ValueType;
|
|
||||||
import com.reandroid.arsc.value.attribute.AttributeBag;
|
import com.reandroid.arsc.value.attribute.AttributeBag;
|
||||||
import com.reandroid.arsc.value.attribute.AttributeBagItem;
|
import com.reandroid.arsc.value.attribute.AttributeBagItem;
|
||||||
import com.reandroid.common.EntryStore;
|
import com.reandroid.common.EntryStore;
|
||||||
@ -39,9 +38,11 @@ class BagDecoderAttr<OUTPUT> extends BagDecoder<OUTPUT>{
|
|||||||
writer.startTag(tag);
|
writer.startTag(tag);
|
||||||
writer.attribute("name", entry.getName());
|
writer.attribute("name", entry.getName());
|
||||||
AttributeBag attributeBag = AttributeBag.create(mapEntry.getValue());
|
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";
|
String childTag = is_flag ? "flag" : "enum";
|
||||||
|
|
||||||
AttributeBagItem[] bagItems = attributeBag.getBagItems();
|
AttributeBagItem[] bagItems = attributeBag.getBagItems();
|
||||||
@ -63,7 +64,7 @@ class BagDecoderAttr<OUTPUT> extends BagDecoder<OUTPUT>{
|
|||||||
if(item.getBagItem().getValueType() == ValueType.INT_HEX){
|
if(item.getBagItem().getValueType() == ValueType.INT_HEX){
|
||||||
value = HexUtil.toHex8(rawVal);
|
value = HexUtil.toHex8(rawVal);
|
||||||
}else {
|
}else {
|
||||||
value = String.valueOf(rawVal);
|
value = Integer.toString(rawVal);
|
||||||
}
|
}
|
||||||
writer.text(value);
|
writer.text(value);
|
||||||
|
|
||||||
@ -72,6 +73,24 @@ class BagDecoderAttr<OUTPUT> extends BagDecoder<OUTPUT>{
|
|||||||
return writer.endTag(tag);
|
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 {
|
private void writeParentAttributes(EntryWriter<OUTPUT> writer, AttributeBag attributeBag) throws IOException {
|
||||||
String formats= attributeBag.decodeValueType();
|
String formats= attributeBag.decodeValueType();
|
||||||
if(formats!=null){
|
if(formats!=null){
|
||||||
|
@ -17,11 +17,9 @@ package com.reandroid.apk.xmldecoder;
|
|||||||
|
|
||||||
import com.reandroid.apk.XmlHelper;
|
import com.reandroid.apk.XmlHelper;
|
||||||
import com.reandroid.arsc.chunk.PackageBlock;
|
import com.reandroid.arsc.chunk.PackageBlock;
|
||||||
import com.reandroid.arsc.decoder.ValueDecoder;
|
|
||||||
import com.reandroid.arsc.value.*;
|
import com.reandroid.arsc.value.*;
|
||||||
import com.reandroid.arsc.value.plurals.PluralsQuantity;
|
import com.reandroid.arsc.value.plurals.PluralsQuantity;
|
||||||
import com.reandroid.common.EntryStore;
|
import com.reandroid.common.EntryStore;
|
||||||
import com.reandroid.xml.XMLElement;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -46,12 +44,11 @@ class BagDecoderPlural<OUTPUT> extends BagDecoder<OUTPUT>{
|
|||||||
writer.enableIndent(true);
|
writer.enableIndent(true);
|
||||||
writer.startTag(childTag);
|
writer.startTag(childTag);
|
||||||
|
|
||||||
PluralsQuantity quantity =
|
AttributeType quantity = valueMap.getAttributeType();
|
||||||
PluralsQuantity.valueOf((short) (valueMap.getName() & 0xffff));
|
if(quantity == null || !quantity.isPlural()){
|
||||||
if(quantity == null){
|
|
||||||
throw new IOException("Unknown plural quantity: " + valueMap);
|
throw new IOException("Unknown plural quantity: " + valueMap);
|
||||||
}
|
}
|
||||||
writer.attribute("quantity", quantity.toString());
|
writer.attribute("quantity", quantity.getName());
|
||||||
|
|
||||||
writeText(writer, packageBlock, valueMap);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,24 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.reandroid.arsc.array;
|
package com.reandroid.arsc.array;
|
||||||
|
|
||||||
import com.reandroid.arsc.base.BlockArray;
|
|
||||||
import com.reandroid.arsc.value.ResValueMap;
|
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(){
|
public ResValueMapArray(){
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResValueMap getByName(int name){
|
|
||||||
for(ResValueMap resValueMap:listItems()){
|
|
||||||
if(resValueMap != null &&name == resValueMap.getName()){
|
|
||||||
return resValueMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public ResValueMap newInstance() {
|
public ResValueMap newInstance() {
|
||||||
return new ResValueMap();
|
return new ResValueMap();
|
||||||
@ -42,55 +30,4 @@ public class ResValueMapArray extends BlockArray<ResValueMap> implements JSONCon
|
|||||||
public ResValueMap[] newInstance(int len) {
|
public ResValueMap[] newInstance(int len) {
|
||||||
return new ResValueMap[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,7 +429,7 @@ public class ValueDecoder {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TableEntry<?, ?> tableEntry = entry.getTableEntry();
|
TableEntry<?, ?> tableEntry = entry.getTableEntry();
|
||||||
if(tableEntry == null || (tableEntry instanceof ResTableMapEntry)){
|
if(tableEntry == null || (tableEntry instanceof CompoundEntry)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ResValue resValue = (ResValue) tableEntry.getValue();
|
ResValue resValue = (ResValue) tableEntry.getValue();
|
||||||
|
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(){
|
public boolean isComplex(){
|
||||||
return getTableEntry() instanceof ResTableMapEntry;
|
return getTableEntry() instanceof CompoundEntry;
|
||||||
}
|
}
|
||||||
public void setTableEntry(TableEntry<?, ?> tableEntry){
|
public void setTableEntry(TableEntry<?, ?> tableEntry){
|
||||||
if(tableEntry==this.mTableEntry){
|
if(tableEntry==this.mTableEntry){
|
||||||
|
@ -16,47 +16,10 @@
|
|||||||
package com.reandroid.arsc.value;
|
package com.reandroid.arsc.value;
|
||||||
|
|
||||||
import com.reandroid.arsc.array.ResValueMapArray;
|
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(){
|
public ResTableMapEntry(){
|
||||||
super(new EntryHeaderMap(), new ResValueMapArray());
|
super(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();
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
boolean shouldMerge(TableEntry<?, ?> tableEntry){
|
boolean shouldMerge(TableEntry<?, ?> tableEntry){
|
||||||
@ -80,42 +43,4 @@ public class ResTableMapEntry extends TableEntry<EntryHeaderMap, ResValueMapArra
|
|||||||
getValue().merge(coming.getValue());
|
getValue().merge(coming.getValue());
|
||||||
refresh();
|
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);
|
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(){
|
public Entry getEntry(){
|
||||||
return getParent(Entry.class);
|
return getParent(Entry.class);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user