This commit is contained in:
REAndroid 2022-11-20 16:10:21 -05:00
parent 15e031fdeb
commit a17ba317b9
16 changed files with 914 additions and 89 deletions

View File

@ -21,6 +21,10 @@ repositories {
mavenLocal()
}
dependencies {
compile(files("$rootProject.projectDir/libs/ArchiveUtil.jar"))
}
processResources {
filesMatching('lib.properties') {
expand('version': version)

BIN
libs/ArchiveUtil.jar Normal file

Binary file not shown.

View File

@ -2,18 +2,23 @@ package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.array.PackageArray;
import com.reandroid.lib.arsc.chunk.xml.ResXmlBlock;
import com.reandroid.lib.arsc.group.EntryGroup;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.common.Frameworks;
import java.io.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class TableBlock extends BaseChunk {
private final IntegerItem mPackageCount;
private final TableStringPool mTableStringPool;
private final PackageArray mPackageArray;
private final Set<TableBlock> mFrameWorks=new HashSet<>();
public TableBlock() {
super(ChunkType.TABLE, 2);
this.mPackageCount=new IntegerItem();
@ -81,18 +86,60 @@ public class TableBlock extends BaseChunk {
builder.append(pkgCount);
return builder.toString();
}
public EntryGroup search(int resourceId){
if(resourceId==0){
return null;
}
int pkgId=resourceId>>24;
pkgId=pkgId&0xff;
PackageBlock packageBlock=getPackageBlockById((byte) pkgId);
if(packageBlock!=null){
EntryGroup entryGroup=packageBlock.getEntryGroup(resourceId);
if(entryGroup!=null){
return entryGroup;
}
}
for(TableBlock tableBlock:getFrameWorks()){
EntryGroup entryGroup= tableBlock.search(resourceId);
if(entryGroup!=null){
return entryGroup;
}
}
return null;
}
public Set<TableBlock> getFrameWorks(){
return mFrameWorks;
}
public void addFramework(TableBlock tableBlock){
if(tableBlock==null||tableBlock==this){
return;
}
for(TableBlock frm:tableBlock.getFrameWorks()){
if(frm==this){
return;
}
}
mFrameWorks.add(tableBlock);
}
public static TableBlock loadWithAndroidFramework(InputStream inputStream) throws IOException{
TableBlock tableBlock=new TableBlock();
tableBlock.readBytes(inputStream);
tableBlock.addFramework(Frameworks.getAndroid());
return tableBlock;
}
public static boolean isResTableBlock(File file){
if(file==null){
return false;
}
boolean result=false;
try {
InputStream inputStream=new FileInputStream(file);
return isResTableBlock(inputStream);
} catch (FileNotFoundException ignored) {
return false;
result=isResTableBlock(inputStream);
inputStream.close();
} catch (IOException ignored) {
}
return result;
}
public static boolean isResTableBlock(InputStream inputStream){
try {
@ -120,5 +167,6 @@ public class TableBlock extends BaseChunk {
ChunkType chunkType=headerBlock.getChunkType();
return chunkType==ChunkType.TABLE;
}
public static final String FILE_NAME="resources.arsc";
}

View File

@ -163,4 +163,5 @@ public class AndroidManifestBlock extends ResXmlBlock{
private static final String ATTR_versionName="versionName";
private static final String ATTR_android_name="name";
public static final String FILE_NAME="AndroidManifest.xml";
}

View File

@ -45,7 +45,6 @@ public class ValueDecoder {
return attributeBag.decodeAttributeValue(store, rawValue);
}
public static String decodeEntryValue(EntryStore store, PackageBlock currentPackage, ValueType valueType, int data){
if(store==null || currentPackage==null){
return null;

View File

@ -315,7 +315,6 @@ public class BlockReader extends InputStream {
while((len=in.read(buff))>0){
result=add(result, buff, len);
}
in.close();
return result;
}
private static byte[] add(byte[] arr1, byte[] arr2, int len){

View File

@ -5,6 +5,7 @@ import com.reandroid.lib.arsc.base.BlockCounter;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.chunk.TableBlock;
import com.reandroid.lib.arsc.chunk.TypeBlock;
import com.reandroid.lib.arsc.group.EntryGroup;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.*;
import com.reandroid.lib.arsc.pool.SpecStringPool;
@ -202,6 +203,27 @@ public class EntryBlock extends Block {
}
return null;
}
public String getName(){
SpecString specString=getSpecString();
if(specString==null){
return null;
}
return specString.get();
}
public String getTypeName(){
TypeString typeString=getTypeString();
if(typeString==null){
return null;
}
return typeString.get();
}
public String getPackageName(){
PackageBlock packageBlock=getPackageBlock();
if(packageBlock==null){
return null;
}
return packageBlock.getPackageName();
}
public SpecString getSpecString(){
PackageBlock packageBlock=getPackageBlock();
if(packageBlock==null){
@ -217,35 +239,60 @@ public class EntryBlock extends Block {
}
return null;
}
public String buildResourceName(int resourceId, char prefix, boolean includeType){
if(resourceId==0){
return null;
}
EntryBlock entryBlock=searchEntry(resourceId);
return buildResourceName(entryBlock, prefix, includeType);
}
private EntryBlock searchEntry(int resourceId){
if(resourceId==getResourceId()){
return this;
}
PackageBlock packageBlock=getPackageBlock();
if(packageBlock==null){
return null;
}
TableBlock tableBlock= packageBlock.getTableBlock();
if(tableBlock==null){
return null;
}
EntryGroup entryGroup = tableBlock.search(resourceId);
if(entryGroup!=null){
return entryGroup.pickOne();
}
return null;
}
public String buildResourceName(EntryBlock entryBlock, char prefix, boolean includeType){
if(entryBlock==null){
return null;
}
String pkgName=entryBlock.getPackageName();
if(getResourceId()==entryBlock.getResourceId()){
pkgName=null;
}else if(pkgName!=null){
if(pkgName.equals(this.getPackageName())){
pkgName=null;
}
}
String type=null;
if(includeType){
type=entryBlock.getTypeName();
}
String name=entryBlock.getName();
return buildResourceName(prefix, pkgName, type, name);
}
public String getResourceName(){
return getResourceName("@", null);
return buildResourceName('@',null, getTypeName(), getName());
}
public String getResourceName(String prefix){
return getResourceName(prefix, null);
public String getResourceName(char prefix){
return getResourceName(prefix, false, true);
}
public String getResourceName(String prefix, String appName){
if(isNull()){
return null;
}
TypeString type=getTypeString();
if(type==null){
return null;
}
SpecString spec=getSpecString();
if(spec==null){
return null;
}
StringBuilder builder=new StringBuilder();
if(prefix!=null){
builder.append(prefix);
}
if(appName!=null){
builder.append(appName);
}
builder.append(type.get());
builder.append('/');
builder.append(spec.get());
return builder.toString();
public String getResourceName(char prefix, boolean includePackage, boolean includeType){
String pkg=includePackage?getPackageName():null;
String type=includeType?getTypeName():null;
return buildResourceName(prefix,pkg, type, getName());
}
public int getResourceId(){
TypeBlock typeBlock=getTypeBlock();
@ -497,6 +544,25 @@ public class EntryBlock extends Block {
}
return builder.toString();
}
public static String buildResourceName(char prefix, String packageName, String type, String name){
if(name==null){
return null;
}
StringBuilder builder=new StringBuilder();
if(prefix!=0){
builder.append(prefix);
}
if(packageName!=null){
builder.append(packageName);
builder.append(':');
}
if(type!=null){
builder.append(type);
builder.append('/');
}
builder.append(name);
return builder.toString();
}
private final static short FLAG_COMPLEX_MASK = 0x0001;

View File

@ -495,6 +495,9 @@ public class ResConfig extends BlockArray<Block> implements BlockLoad {
qualifiers=ResConfigHelper.sortQualifiers(qualifiers);
return getQualifiers().equals(qualifiers);
}
public String getLocale(){
return ResConfigHelper.decodeLocale(this);
}
@Override
public boolean equals(Object o){
if(o instanceof ResConfig){

View File

@ -139,6 +139,24 @@ public class ResConfigHelper {
char[] chs=country.toCharArray();
resConfig.setRegion(chs);
}
public static String decodeLocale(ResConfig resConfig){
char[] region=resConfig.getRegion();
char[] language=resConfig.getLanguage();
StringBuilder builder=new StringBuilder();
if(language[0]!=0){
builder.append(language[0]).append(language[1]);
}
if(region[0]!=0){
if(language[0]!=0){
builder.append('-');
}
builder.append(region[0]).append(region[1]);
}
if(builder.length()==0){
return null;
}
return builder.toString();
}
private static String decodeLanguageAndCountry(ResConfig resConfig) {
StringBuilder builder = new StringBuilder();
char[] localeVariant=resConfig.getLocaleVariant();
@ -993,81 +1011,81 @@ public class ResConfigHelper {
private static final Pattern PATTERN_SCREEN_SIZE=Pattern.compile("^-?(?<A>[0-9]+)x(?<B>[0-9]+)$");
private final static short MASK_LAYOUTDIR = 0xc0;
private final static short SCREENLAYOUT_LAYOUTDIR_ANY = 0x00;
private final static short SCREENLAYOUT_LAYOUTDIR_LTR = 0x40;
private final static short SCREENLAYOUT_LAYOUTDIR_RTL = 0x80;
private final static short SCREENLAYOUT_LAYOUTDIR_SHIFT = 0x06;
public final static short MASK_LAYOUTDIR = 0xc0;
public final static short SCREENLAYOUT_LAYOUTDIR_ANY = 0x00;
public final static short SCREENLAYOUT_LAYOUTDIR_LTR = 0x40;
public final static short SCREENLAYOUT_LAYOUTDIR_RTL = 0x80;
public final static short SCREENLAYOUT_LAYOUTDIR_SHIFT = 0x06;
private final static byte MASK_SCREENSIZE = 0x0f;
private final static byte SCREENSIZE_ANY = 0x00;
private final static byte SCREENSIZE_SMALL = 0x01;
private final static byte SCREENSIZE_NORMAL = 0x02;
private final static byte SCREENSIZE_LARGE = 0x03;
private final static byte SCREENSIZE_XLARGE = 0x04;
public final static byte MASK_SCREENSIZE = 0x0f;
public final static byte SCREENSIZE_ANY = 0x00;
public final static byte SCREENSIZE_SMALL = 0x01;
public final static byte SCREENSIZE_NORMAL = 0x02;
public final static byte SCREENSIZE_LARGE = 0x03;
public final static byte SCREENSIZE_XLARGE = 0x04;
private final static byte MASK_SCREENLONG = 0x30;
private final static byte SCREENLONG_ANY = 0x00;
private final static byte SCREENLONG_NO = 0x10;
private final static byte SCREENLONG_YES = 0x20;
public final static byte MASK_SCREENLONG = 0x30;
public final static byte SCREENLONG_ANY = 0x00;
public final static byte SCREENLONG_NO = 0x10;
public final static byte SCREENLONG_YES = 0x20;
private final static short MASK_SCREENROUND = 0x03;
private final static short SCREENLAYOUT_ROUND_ANY = 0;
private final static short SCREENLAYOUT_ROUND_NO = 0x1;
private final static short SCREENLAYOUT_ROUND_YES = 0x2;
public final static short MASK_SCREENROUND = 0x03;
public final static short SCREENLAYOUT_ROUND_ANY = 0;
public final static short SCREENLAYOUT_ROUND_NO = 0x1;
public final static short SCREENLAYOUT_ROUND_YES = 0x2;
private final static byte ORIENTATION_ANY = 0;
private final static byte ORIENTATION_PORT = 1;
private final static byte ORIENTATION_LAND = 2;
private final static byte ORIENTATION_SQUARE = 3;
public final static byte ORIENTATION_ANY = 0;
public final static byte ORIENTATION_PORT = 1;
public final static byte ORIENTATION_LAND = 2;
public final static byte ORIENTATION_SQUARE = 3;
private final static byte MASK_UI_MODE_TYPE = 0x0f;
private final static byte UI_MODE_TYPE_ANY = 0x00;
private final static byte UI_MODE_TYPE_NORMAL = 0x01;
private final static byte UI_MODE_TYPE_DESK = 0x02;
private final static byte UI_MODE_TYPE_CAR = 0x03;
private final static byte UI_MODE_TYPE_TELEVISION = 0x04;
private final static byte UI_MODE_TYPE_APPLIANCE = 0x05;
private final static byte UI_MODE_TYPE_WATCH = 0x06;
private final static byte UI_MODE_TYPE_VR_HEADSET = 0x07;
public final static byte MASK_UI_MODE_TYPE = 0x0f;
public final static byte UI_MODE_TYPE_ANY = 0x00;
public final static byte UI_MODE_TYPE_NORMAL = 0x01;
public final static byte UI_MODE_TYPE_DESK = 0x02;
public final static byte UI_MODE_TYPE_CAR = 0x03;
public final static byte UI_MODE_TYPE_TELEVISION = 0x04;
public final static byte UI_MODE_TYPE_APPLIANCE = 0x05;
public final static byte UI_MODE_TYPE_WATCH = 0x06;
public final static byte UI_MODE_TYPE_VR_HEADSET = 0x07;
private final static byte MASK_UI_MODE_NIGHT = 0x30;
private final static byte UI_MODE_NIGHT_ANY = 0x00;
private final static byte UI_MODE_NIGHT_NO = 0x10;
private final static byte UI_MODE_NIGHT_YES = 0x20;
public final static byte MASK_UI_MODE_NIGHT = 0x30;
public final static byte UI_MODE_NIGHT_ANY = 0x00;
public final static byte UI_MODE_NIGHT_NO = 0x10;
public final static byte UI_MODE_NIGHT_YES = 0x20;
private final static byte UI_MODE_TYPE_GODZILLAUI = 0x0b;
private final static byte UI_MODE_TYPE_SMALLUI = 0x0c;
private final static byte UI_MODE_TYPE_MEDIUMUI = 0x0d;
private final static byte UI_MODE_TYPE_LARGEUI = 0x0e;
private final static byte UI_MODE_TYPE_HUGEUI = 0x0f;
public final static byte UI_MODE_TYPE_GODZILLAUI = 0x0b;
public final static byte UI_MODE_TYPE_SMALLUI = 0x0c;
public final static byte UI_MODE_TYPE_MEDIUMUI = 0x0d;
public final static byte UI_MODE_TYPE_LARGEUI = 0x0e;
public final static byte UI_MODE_TYPE_HUGEUI = 0x0f;
private final static byte TOUCHSCREEN_ANY = 0;
private final static byte TOUCHSCREEN_NOTOUCH = 1;
private final static byte TOUCHSCREEN_STYLUS = 2;
private final static byte TOUCHSCREEN_FINGER = 3;
public final static byte TOUCHSCREEN_ANY = 0;
public final static byte TOUCHSCREEN_NOTOUCH = 1;
public final static byte TOUCHSCREEN_STYLUS = 2;
public final static byte TOUCHSCREEN_FINGER = 3;
private final static byte MASK_KEYSHIDDEN = 0x3;
private final static byte KEYSHIDDEN_ANY = 0x0;
private final static byte KEYSHIDDEN_NO = 0x1;
private final static byte KEYSHIDDEN_YES = 0x2;
private final static byte KEYSHIDDEN_SOFT = 0x3;
public final static byte MASK_KEYSHIDDEN = 0x3;
public final static byte KEYSHIDDEN_ANY = 0x0;
public final static byte KEYSHIDDEN_NO = 0x1;
public final static byte KEYSHIDDEN_YES = 0x2;
public final static byte KEYSHIDDEN_SOFT = 0x3;
private final static byte KEYBOARD_ANY = 0;
private final static byte KEYBOARD_NOKEYS = 1;
private final static byte KEYBOARD_QWERTY = 2;
private final static byte KEYBOARD_12KEY = 3;
private final static byte MASK_NAVHIDDEN = 0xc;
private final static byte NAVHIDDEN_ANY = 0x0;
private final static byte NAVHIDDEN_NO = 0x4;
private final static byte NAVHIDDEN_YES = 0x8;
public final static byte MASK_NAVHIDDEN = 0xc;
public final static byte NAVHIDDEN_ANY = 0x0;
public final static byte NAVHIDDEN_NO = 0x4;
public final static byte NAVHIDDEN_YES = 0x8;
private final static byte NAVIGATION_ANY = 0;

View File

@ -1,8 +1,7 @@
package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.arsc.pool.SpecStringPool;
public class ResValueBagItem extends BaseResValueItem{
@ -11,6 +10,17 @@ public class ResValueBagItem extends BaseResValueItem{
setHeaderSize(BYTES_SIZE);
}
public ResValueBag getParentBag(){
Block parent=getParent();
while(parent!=null){
if(parent instanceof ResValueBag){
return (ResValueBag) parent;
}
parent=parent.getParent();
}
return null;
}
@Override
public void setHeaderSize(short size) {
setShort(OFFSET_SIZE, size);
@ -28,13 +38,13 @@ public class ResValueBagItem extends BaseResValueItem{
return getByte(OFFSET_RESERVED);
}
public void setId(int id){
setInt(OFFSET_ID, id);
}
public int getId(){
return getInt(OFFSET_ID);
}
@Override
public void setType(ValueType valueType){
byte type=0;

View File

@ -0,0 +1,90 @@
package com.reandroid.lib.arsc.value.array;
import com.reandroid.lib.arsc.item.SpecString;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResValueBag;
import com.reandroid.lib.arsc.value.attribute.AttributeBag;
public class ArrayBag {
private final ArrayBagItem[] mBagItems;
private ArrayBag(ArrayBagItem[] bagItems){
this.mBagItems=bagItems;
}
public ArrayBagItem[] getBagItems() {
return mBagItems;
}
public String getName(){
EntryBlock entryBlock=getBagItems()[0].getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
SpecString spec = entryBlock.getSpecString();
if(spec==null){
return null;
}
return spec.get();
}
public String getTypeName(){
EntryBlock entryBlock=getBagItems()[0].getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
TypeString typeString = entryBlock.getTypeString();
if(typeString==null){
return null;
}
return typeString.get();
}
@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();
}
/** TODO: find another method to check instead of checking type name (plurals),
* just like {@link AttributeBag} **/
public static boolean isArray(ResValueBag resValueBag){
if(resValueBag==null){
return false;
}
EntryBlock entryBlock= resValueBag.getEntryBlock();
if(entryBlock==null){
return false;
}
TypeString typeString = entryBlock.getTypeString();
if(typeString==null){
return false;
}
if(!NAME.equals(typeString.get())){
return false;
}
return ArrayBagItem.create(resValueBag.getBagItems()) != null;
}
public static ArrayBag create(ResValueBag resValueBag){
if(resValueBag==null){
return null;
}
ArrayBagItem[] bagItems=ArrayBagItem.create(resValueBag.getBagItems());
if(bagItems==null){
return null;
}
return new ArrayBag(bagItems);
}
public static final String NAME="array";
}

View File

@ -0,0 +1,107 @@
package com.reandroid.lib.arsc.value.array;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.chunk.TableBlock;
import com.reandroid.lib.arsc.item.SpecString;
import com.reandroid.lib.arsc.item.TableString;
import com.reandroid.lib.arsc.pool.SpecStringPool;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResValueBagItem;
import com.reandroid.lib.arsc.value.ValueType;
import com.reandroid.lib.arsc.value.plurals.PluralsBagItem;
import com.reandroid.lib.arsc.value.plurals.PluralsQuantity;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ArrayBagItem {
private final ResValueBagItem mBagItem;
public ArrayBagItem(ResValueBagItem bagItem){
this.mBagItem=bagItem;
}
public ResValueBagItem getBagItem() {
return mBagItem;
}
public ValueType getValueType(){
return getBagItem().getValueType();
}
private TableStringPool getStringPool(){
EntryBlock entryBlock=getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
PackageBlock pkg = entryBlock.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
public String toString() {
StringBuilder builder=new StringBuilder();
builder.append("<item>");
if(hasStringValue()){
builder.append(getStringValue());
}else {
builder.append(String.format("0x%08x", getValue()));
}
builder.append("</item>");
return builder.toString();
}
public static ArrayBagItem[] create(ResValueBagItem[] resValueBagItems){
if(resValueBagItems==null){
return null;
}
int len=resValueBagItems.length;
if(len==0){
return null;
}
List<ArrayBagItem> results=new ArrayList<>();
for(int i=0;i<len;i++){
ArrayBagItem item=create(resValueBagItems[i]);
if(item==null){
return null;
}
results.add(item);
}
return results.toArray(new ArrayBagItem[0]);
}
public static ArrayBagItem create(ResValueBagItem resValueBagItem){
if(resValueBagItem==null){
return null;
}
ArrayBagItem item=new ArrayBagItem(resValueBagItem);
return item;
}
}

View File

@ -0,0 +1,90 @@
package com.reandroid.lib.arsc.value.plurals;
import com.reandroid.lib.arsc.item.SpecString;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResValueBag;
import com.reandroid.lib.arsc.value.attribute.AttributeBag;
public class PluralsBag {
private final PluralsBagItem[] mBagItems;
private PluralsBag(PluralsBagItem[] bagItems){
this.mBagItems=bagItems;
}
public PluralsBagItem[] getBagItems() {
return mBagItems;
}
public String getName(){
EntryBlock entryBlock=getBagItems()[0].getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
SpecString spec = entryBlock.getSpecString();
if(spec==null){
return null;
}
return spec.get();
}
public String getTypeName(){
EntryBlock entryBlock=getBagItems()[0].getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
TypeString typeString = entryBlock.getTypeString();
if(typeString==null){
return null;
}
return typeString.get();
}
@Override
public String toString() {
StringBuilder builder=new StringBuilder();
builder.append("<");
String type=getTypeName();
builder.append(type);
builder.append(" name=\"");
builder.append(getName());
builder.append("\">");
PluralsBagItem[] allItems = getBagItems();
for(int i=0;i<allItems.length;i++){
builder.append("\n ");
builder.append(allItems[i].toString());
}
builder.append("\n</");
builder.append(type);
builder.append(">");
return builder.toString();
}
/** TODO: find another method to check instead of checking type name (plurals),
* just like {@link AttributeBag} **/
public static boolean isPlurals(ResValueBag resValueBag){
if(resValueBag==null){
return false;
}
EntryBlock entryBlock= resValueBag.getEntryBlock();
if(entryBlock==null){
return false;
}
TypeString typeString = entryBlock.getTypeString();
if(typeString==null){
return false;
}
if(!NAME.equals(typeString.get())){
return false;
}
return PluralsBagItem.create(resValueBag.getBagItems()) != null;
}
public static PluralsBag create(ResValueBag resValueBag){
if(resValueBag==null){
return null;
}
PluralsBagItem[] bagItems=PluralsBagItem.create(resValueBag.getBagItems());
if(bagItems==null){
return null;
}
return new PluralsBag(bagItems);
}
public static final String NAME="plurals";
}

View File

@ -0,0 +1,115 @@
package com.reandroid.lib.arsc.value.plurals;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.chunk.TableBlock;
import com.reandroid.lib.arsc.item.TableString;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResValueBagItem;
import com.reandroid.lib.arsc.value.ValueType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PluralsBagItem {
private final ResValueBagItem mBagItem;
private PluralsBagItem(ResValueBagItem bagItem){
this.mBagItem=bagItem;
}
public ResValueBagItem getBagItem() {
return mBagItem;
}
public PluralsQuantity getQuantity(){
ResValueBagItem item=getBagItem();
return PluralsQuantity.valueOf(item.getIdLow());
}
public ValueType getValueType(){
return getBagItem().getValueType();
}
private TableStringPool getStringPool(){
EntryBlock entryBlock=getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
PackageBlock pkg = entryBlock.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
public String toString() {
StringBuilder builder=new StringBuilder();
builder.append("<item quantity=\"");
builder.append(getQuantity());
builder.append("\">");
if(hasStringValue()){
builder.append(getStringValue());
}else {
builder.append(String.format("@0x%08x", getValue()));
}
builder.append("</item>");
return builder.toString();
}
public static PluralsBagItem[] create(ResValueBagItem[] resValueBagItems){
if(resValueBagItems==null){
return null;
}
int len=resValueBagItems.length;
if(len==0){
return null;
}
Set<PluralsQuantity> duplicates=new HashSet<>();
List<PluralsBagItem> results=new ArrayList<>();
for(int i=0;i<len;i++){
PluralsBagItem item=create(resValueBagItems[i]);
if(item==null){
return null;
}
PluralsQuantity quantity=item.getQuantity();
if(duplicates.contains(quantity)){
return null;
}
duplicates.add(quantity);
results.add(item);
}
return results.toArray(new PluralsBagItem[0]);
}
public static PluralsBagItem create(ResValueBagItem resValueBagItem){
PluralsBagItem item=new PluralsBagItem(resValueBagItem);
if(item.getQuantity()==null){
return null;
}
return item;
}
}

View File

@ -0,0 +1,126 @@
package com.reandroid.lib.arsc.value.style;
import com.reandroid.lib.arsc.item.SpecString;
import com.reandroid.lib.arsc.item.TypeString;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResValueBag;
import com.reandroid.lib.arsc.value.array.ArrayBagItem;
import com.reandroid.lib.arsc.value.attribute.AttributeBag;
public class StyleBag {
private final StyleBagItem[] mBagItems;
private StyleBag(StyleBagItem[] bagItems){
this.mBagItems=bagItems;
}
public StyleBagItem[] getBagItems() {
return mBagItems;
}
public String getName(){
EntryBlock entryBlock=getEntryBlock();
if(entryBlock==null){
return null;
}
SpecString spec = entryBlock.getSpecString();
if(spec==null){
return null;
}
return spec.get();
}
public String getParentResourceName(){
int id=getParentId();
if(id==0){
return null;
}
EntryBlock entryBlock=getEntryBlock();
if(entryBlock==null){
return null;
}
return entryBlock.buildResourceName(id, '@', true);
}
public int getParentId(){
ResValueBag resValueBag=getBagItems()[0].getBagItem().getParentBag();
if(resValueBag==null){
return 0;
}
return resValueBag.getParentId();
}
public int getResourceId(){
EntryBlock entryBlock=getEntryBlock();
if(entryBlock==null){
return 0;
}
return entryBlock.getResourceId();
}
public String getTypeName(){
EntryBlock entryBlock=getBagItems()[0].getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
TypeString typeString = entryBlock.getTypeString();
if(typeString==null){
return null;
}
return typeString.get();
}
private EntryBlock getEntryBlock(){
return getBagItems()[0].getBagItem().getEntryBlock();
}
@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();
}
/** TODO: find another method to check instead of checking type name (plurals),
* just like {@link AttributeBag} **/
public static boolean isStyle(ResValueBag resValueBag){
if(resValueBag==null){
return false;
}
EntryBlock entryBlock = resValueBag.getEntryBlock();
if(entryBlock==null){
return false;
}
TypeString typeString = entryBlock.getTypeString();
if(typeString==null){
return false;
}
if(!NAME.equals(typeString.get())){
return false;
}
return ArrayBagItem.create(resValueBag.getBagItems()) != null;
}
public static StyleBag create(ResValueBag resValueBag){
if(resValueBag==null){
return null;
}
StyleBagItem[] bagItems=StyleBagItem.create(resValueBag.getBagItems());
if(bagItems==null){
return null;
}
return new StyleBag(bagItems);
}
public static final String NAME="style";
}

View File

@ -0,0 +1,149 @@
package com.reandroid.lib.arsc.value.style;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.chunk.TableBlock;
import com.reandroid.lib.arsc.item.SpecString;
import com.reandroid.lib.arsc.item.TableString;
import com.reandroid.lib.arsc.pool.SpecStringPool;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.ResValueBagItem;
import com.reandroid.lib.arsc.value.ValueType;
import java.util.ArrayList;
import java.util.List;
public class StyleBagItem {
private final ResValueBagItem mBagItem;
public StyleBagItem(ResValueBagItem bagItem){
this.mBagItem=bagItem;
}
public ResValueBagItem getBagItem() {
return mBagItem;
}
public String getName(){
EntryBlock block=getBagItem().getEntryBlock();
if(block==null){
return null;
}
char prefix=0;
return block.buildResourceName(getNameId(), prefix, false);
}
public int getNameId(){
return getBagItem().getId();
}
public boolean hasStringValue(){
return getValueType()== ValueType.STRING;
}
public boolean hasReferenceValue(){
return getValueType()==ValueType.REFERENCE;
}
public boolean hasAttributeValue(){
return getValueType()==ValueType.REFERENCE;
}
public String getValueAsReference(){
ValueType valueType=getValueType();
if(valueType!=ValueType.REFERENCE && valueType!=ValueType.ATTRIBUTE){
throw new IllegalArgumentException("Not REF ValueType="+valueType);
}
EntryBlock entryBlock=getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
char prefix='@';
boolean includeType=true;
if(valueType==ValueType.ATTRIBUTE){
prefix='?';
includeType=false;
}
int id=getValue();
return entryBlock.buildResourceName(id, prefix, includeType);
}
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);
if(tableString==null){
return null;
}
return tableString.getHtml();
}
public ValueType getValueType(){
return getBagItem().getValueType();
}
public int getValue(){
return getBagItem().getData();
}
private TableStringPool getStringPool(){
EntryBlock entryBlock=getBagItem().getEntryBlock();
if(entryBlock==null){
return null;
}
PackageBlock pkg = entryBlock.getPackageBlock();
if(pkg==null){
return null;
}
TableBlock tableBlock= pkg.getTableBlock();
if(tableBlock==null){
return null;
}
return tableBlock.getTableStringPool();
}
@Override
public String toString() {
StringBuilder builder=new StringBuilder();
builder.append("<item name=\"");
String name=getName();
if(name==null){
name=String.format("@0x%08x", getNameId());
}
builder.append(name);
builder.append("\">");
if(hasStringValue()){
builder.append(getStringValue());
}
String val=null;
if(hasReferenceValue()||hasAttributeValue()) {
val=getValueAsReference();
}
if(val==null) {
val=String.format("0x%08x", getValue());
}
builder.append(val);
builder.append("</item>");
return builder.toString();
}
public static StyleBagItem[] create(ResValueBagItem[] resValueBagItems){
if(resValueBagItems==null){
return null;
}
int len=resValueBagItems.length;
if(len==0){
return null;
}
List<StyleBagItem> results=new ArrayList<>();
for(int i=0;i<len;i++){
StyleBagItem item=create(resValueBagItems[i]);
if(item==null){
return null;
}
results.add(item);
}
return results.toArray(new StyleBagItem[0]);
}
public static StyleBagItem create(ResValueBagItem resValueBagItem){
if(resValueBagItem==null){
return null;
}
StyleBagItem item=new StyleBagItem(resValueBagItem);
return item;
}
}