diff --git a/build.gradle b/build.gradle index 0e23ca1..db1c9d5 100755 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,10 @@ repositories { mavenLocal() } +dependencies { + compile(files("$rootProject.projectDir/libs/ArchiveUtil.jar")) +} + processResources { filesMatching('lib.properties') { expand('version': version) diff --git a/libs/ArchiveUtil.jar b/libs/ArchiveUtil.jar new file mode 100644 index 0000000..222aafb Binary files /dev/null and b/libs/ArchiveUtil.jar differ diff --git a/src/main/java/com/reandroid/lib/arsc/chunk/TableBlock.java b/src/main/java/com/reandroid/lib/arsc/chunk/TableBlock.java index 0495055..dc4f7d1 100755 --- a/src/main/java/com/reandroid/lib/arsc/chunk/TableBlock.java +++ b/src/main/java/com/reandroid/lib/arsc/chunk/TableBlock.java @@ -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 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 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"; } diff --git a/src/main/java/com/reandroid/lib/arsc/chunk/xml/AndroidManifestBlock.java b/src/main/java/com/reandroid/lib/arsc/chunk/xml/AndroidManifestBlock.java index 67b98c0..04e1c24 100644 --- a/src/main/java/com/reandroid/lib/arsc/chunk/xml/AndroidManifestBlock.java +++ b/src/main/java/com/reandroid/lib/arsc/chunk/xml/AndroidManifestBlock.java @@ -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"; } diff --git a/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java b/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java index 423dade..5319066 100755 --- a/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java +++ b/src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java @@ -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; diff --git a/src/main/java/com/reandroid/lib/arsc/io/BlockReader.java b/src/main/java/com/reandroid/lib/arsc/io/BlockReader.java index ba8d334..11dbbf7 100755 --- a/src/main/java/com/reandroid/lib/arsc/io/BlockReader.java +++ b/src/main/java/com/reandroid/lib/arsc/io/BlockReader.java @@ -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){ diff --git a/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java b/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java index e777599..5c52e15 100755 --- a/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java +++ b/src/main/java/com/reandroid/lib/arsc/value/EntryBlock.java @@ -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; diff --git a/src/main/java/com/reandroid/lib/arsc/value/ResConfig.java b/src/main/java/com/reandroid/lib/arsc/value/ResConfig.java index f179427..2e37f20 100755 --- a/src/main/java/com/reandroid/lib/arsc/value/ResConfig.java +++ b/src/main/java/com/reandroid/lib/arsc/value/ResConfig.java @@ -495,6 +495,9 @@ public class ResConfig extends BlockArray 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){ diff --git a/src/main/java/com/reandroid/lib/arsc/value/ResConfigHelper.java b/src/main/java/com/reandroid/lib/arsc/value/ResConfigHelper.java index df9537a..50c550c 100755 --- a/src/main/java/com/reandroid/lib/arsc/value/ResConfigHelper.java +++ b/src/main/java/com/reandroid/lib/arsc/value/ResConfigHelper.java @@ -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("^-?(?[0-9]+)x(?[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; diff --git a/src/main/java/com/reandroid/lib/arsc/value/ResValueBagItem.java b/src/main/java/com/reandroid/lib/arsc/value/ResValueBagItem.java index f80bc79..1cdc79f 100755 --- a/src/main/java/com/reandroid/lib/arsc/value/ResValueBagItem.java +++ b/src/main/java/com/reandroid/lib/arsc/value/ResValueBagItem.java @@ -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; diff --git a/src/main/java/com/reandroid/lib/arsc/value/array/ArrayBag.java b/src/main/java/com/reandroid/lib/arsc/value/array/ArrayBag.java new file mode 100644 index 0000000..8fe936e --- /dev/null +++ b/src/main/java/com/reandroid/lib/arsc/value/array/ArrayBag.java @@ -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"); + 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"; +} diff --git a/src/main/java/com/reandroid/lib/arsc/value/array/ArrayBagItem.java b/src/main/java/com/reandroid/lib/arsc/value/array/ArrayBagItem.java new file mode 100644 index 0000000..2153486 --- /dev/null +++ b/src/main/java/com/reandroid/lib/arsc/value/array/ArrayBagItem.java @@ -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(""); + if(hasStringValue()){ + builder.append(getStringValue()); + }else { + builder.append(String.format("0x%08x", getValue())); + } + builder.append(""); + return builder.toString(); + } + public static ArrayBagItem[] create(ResValueBagItem[] resValueBagItems){ + if(resValueBagItems==null){ + return null; + } + int len=resValueBagItems.length; + if(len==0){ + return null; + } + List results=new ArrayList<>(); + for(int i=0;i"); + PluralsBagItem[] allItems = getBagItems(); + for(int i=0;i"); + 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"; +} diff --git a/src/main/java/com/reandroid/lib/arsc/value/plurals/PluralsBagItem.java b/src/main/java/com/reandroid/lib/arsc/value/plurals/PluralsBagItem.java new file mode 100644 index 0000000..aa3875e --- /dev/null +++ b/src/main/java/com/reandroid/lib/arsc/value/plurals/PluralsBagItem.java @@ -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(""); + if(hasStringValue()){ + builder.append(getStringValue()); + }else { + builder.append(String.format("@0x%08x", getValue())); + } + builder.append(""); + return builder.toString(); + } + + public static PluralsBagItem[] create(ResValueBagItem[] resValueBagItems){ + if(resValueBagItems==null){ + return null; + } + int len=resValueBagItems.length; + if(len==0){ + return null; + } + Set duplicates=new HashSet<>(); + List results=new ArrayList<>(); + for(int i=0;i"); + StyleBagItem[] allItems = getBagItems(); + for(int i=0;i"); + 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"; +} diff --git a/src/main/java/com/reandroid/lib/arsc/value/style/StyleBagItem.java b/src/main/java/com/reandroid/lib/arsc/value/style/StyleBagItem.java new file mode 100644 index 0000000..d9f519c --- /dev/null +++ b/src/main/java/com/reandroid/lib/arsc/value/style/StyleBagItem.java @@ -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(""); + 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(""); + return builder.toString(); + } + public static StyleBagItem[] create(ResValueBagItem[] resValueBagItems){ + if(resValueBagItems==null){ + return null; + } + int len=resValueBagItems.length; + if(len==0){ + return null; + } + List results=new ArrayList<>(); + for(int i=0;i