Initial commit

This commit is contained in:
REAndroid 2021-11-20 00:29:50 +08:00
parent 5a847aae87
commit 1763dfbc3c
35 changed files with 1178 additions and 52 deletions

View File

@ -4,11 +4,16 @@ import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.EntryBlock;
import java.util.Iterator;
public class EntryBlockArray extends OffsetBlockArray<EntryBlock> {
public EntryBlockArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart){
super(offsets, itemCount, itemStart);
}
public boolean isEmpty(){
return !iterator(true).hasNext();
}
public void setEntry(short entryId, EntryBlock entryBlock){
setItem(entryId, entryBlock);
}

View File

@ -32,6 +32,14 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
this.mEnd4Block.fill(b);
}
@Override
public void clearChildes(){
super.clearChildes();
mOffsets.clear();
mItemStart.set(0);
mItemCount.set(0);
mEnd4Block.clear();
}
@Override
public int countBytes(){
int result=super.countBytes();
int endCount=mEnd4Block.countBytes();
@ -58,7 +66,8 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
}
@Override
protected void onRefreshed() {
mOffsets.setSize(childesCount());
int count=childesCount();
mOffsets.setSize(count);
T[] childes=getChildes();
int sum=0;
if(childes!=null){
@ -69,6 +78,10 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
if(item==null || item.isNull()){
offset=-1;
}else {
// slow but accurate
//offset=countUpTo(item);
// fast but fails for duplicate items
offset=sum;
sum+=item.countBytes();
}
@ -79,10 +92,20 @@ public abstract class OffsetBlockArray<T extends Block> extends BlockArray<T> im
refreshStart();
refreshEnd4Block();
}
public void refreshCountAndStart(){
refreshCount();
refreshStart();
}
private void refreshCount(){
mItemCount.set(childesCount());
}
private void refreshStart(){
int count=childesCount();
if(count==0){
mItemStart.set(0);
mEnd4Block.clear();
return;
}
Block parent=getParent();
if(parent==null){
return;

View File

@ -8,6 +8,7 @@ import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.IntegerItem;
import java.io.IOException;
import java.util.Iterator;
public class PackageArray extends BlockArray<PackageBlock> implements BlockLoad {
private final IntegerItem mPackageCount;
@ -15,6 +16,26 @@ public class PackageArray extends BlockArray<PackageBlock> implements BlockLoad
this.mPackageCount=packageCount;
mPackageCount.setBlockLoad(this);
}
public PackageBlock getOrCreate(byte pkgId){
PackageBlock packageBlock=getPackageBlockById(pkgId);
if(packageBlock!=null){
return packageBlock;
}
packageBlock=createNext();
packageBlock.setId(pkgId);
packageBlock.setName("PACKAGE NAME");
return packageBlock;
}
public PackageBlock getPackageBlockById(byte pkgId){
Iterator<PackageBlock> itr=iterator(true);
while (itr.hasNext()){
PackageBlock packageBlock=itr.next();
if(packageBlock.getId()==pkgId){
return packageBlock;
}
}
return null;
}
@Override
public PackageBlock newInstance() {
return new PackageBlock();

View File

@ -1,6 +1,8 @@
package com.reandroid.lib.arsc.array;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.base.BlockArray;
import com.reandroid.lib.arsc.chunk.xml.ResXmlStartElement;
import com.reandroid.lib.arsc.header.HeaderBlock;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.chunk.xml.ResXmlAttribute;
@ -17,6 +19,19 @@ public class ResXmlAttributeArray extends BlockArray<ResXmlAttribute> {
this.mAttributeStart=attributeStart;
this.mAttributeCount=attributeCount;
}
private void refreshCount(){
short count= (short) childesCount();
mAttributeCount.set(count);
}
private void refreshStart(){
Block parent=getParent();
if(parent==null){
return;
}
int start = parent.countUpTo(this);
start=start-mHeaderBlock.countBytes();
mAttributeStart.set((short) start);
}
@Override
public ResXmlAttribute newInstance() {
return new ResXmlAttribute();
@ -27,7 +42,8 @@ public class ResXmlAttributeArray extends BlockArray<ResXmlAttribute> {
}
@Override
protected void onRefreshed() {
refreshCount();
refreshStart();
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {

View File

@ -5,13 +5,39 @@ import com.reandroid.lib.arsc.chunk.TypeBlock;
import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.value.EntryBlock;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SpecTypePairArray extends BlockArray<SpecTypePair> {
public SpecTypePairArray(){
super();
}
public void removeEmptyPairs(){
List<SpecTypePair> allPairs=new ArrayList<>(listItems());
boolean foundEmpty=false;
for(SpecTypePair typePair:allPairs){
typePair.removeEmptyTypeBlocks();
if(typePair.isEmpty()){
super.remove(typePair, false);
foundEmpty=true;
}
}
if(foundEmpty){
trimNullBlocks();
}
}
public boolean isEmpty(){
Iterator<SpecTypePair> iterator=iterator(true);
while (iterator.hasNext()){
SpecTypePair pair=iterator.next();
if(!pair.isEmpty()){
return false;
}
}
return true;
}
public EntryBlock getOrCreateEntry(byte typeId, short entryId, String qualifiers){
TypeBlock typeBlock=getOrCreateTypeBlock(typeId, qualifiers);
return typeBlock.getOrCreateEntry(entryId);

View File

@ -4,6 +4,9 @@ import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.StringItem;
import java.util.ArrayList;
import java.util.List;
public abstract class StringArray<T extends StringItem> extends OffsetBlockArray<T>{
private boolean mUtf8;
public StringArray(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8) {
@ -11,6 +14,20 @@ public abstract class StringArray<T extends StringItem> extends OffsetBlockArray
this.mUtf8=is_utf8;
setEndBytes((byte)0x00);
}
public List<T> removeUnusedStrings(){
List<T> allUnused=listUnusedStrings();
remove(allUnused);
return allUnused;
}
public List<T> listUnusedStrings(){
List<T> results=new ArrayList<>();
for(T item:listItems()){
if(item.getReferencedList().size()==0){
results.add(item);
}
}
return results;
}
public void setUtf8(boolean is_utf8){
if(mUtf8==is_utf8){
return;

View File

@ -12,6 +12,7 @@ import com.reandroid.lib.arsc.value.ResConfig;
import java.io.IOException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
public class TypeBlockArray extends BlockArray<TypeBlock> {
@ -19,10 +20,31 @@ public class TypeBlockArray extends BlockArray<TypeBlock> {
public TypeBlockArray(){
super();
}
public void removeEmptyBlocks(){
List<TypeBlock> allTypes=new ArrayList<>(listItems());
boolean foundEmpty=false;
for(TypeBlock typeBlock:allTypes){
if(typeBlock.isEmpty()){
super.remove(typeBlock, false);
foundEmpty=true;
}
}
if(foundEmpty){
trimNullBlocks();
}
}
public EntryBlock getOrCreateEntry(short entryId, String qualifiers){
TypeBlock typeBlock=getOrCreate(qualifiers);
return typeBlock.getOrCreateEntry(entryId);
}
public boolean isEmpty(){
for(TypeBlock typeBlock:listItems()){
if(typeBlock!=null && !typeBlock.isEmpty()){
return false;
}
}
return true;
}
public EntryBlock getEntry(short entryId, String qualifiers){
TypeBlock typeBlock=getTypeBlock(qualifiers);
if(typeBlock==null){
@ -142,6 +164,14 @@ public class TypeBlockArray extends BlockArray<TypeBlock> {
return null;
}
@Override
protected boolean remove(TypeBlock block, boolean trim){
if(block==null){
return false;
}
block.cleanEntries();
return super.remove(block, trim);
}
@Override
public TypeBlock newInstance() {
byte id=getTypeId();
TypeBlock typeBlock=new TypeBlock();

View File

@ -49,7 +49,7 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
}
changeSize(diff);
}
public final void clearChildes(){
public void clearChildes(){
T[] allChildes=elementData;
if(allChildes==null || allChildes.length==0){
return;
@ -118,6 +118,9 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
block.setIndex(index);
block.setParent(this);
}
public final int countNonNull(){
return countNonNull(true);
}
public final int childesCount(){
return elementData.length;
}
@ -179,7 +182,16 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
}
return false;
}
public void remove(Collection<T> blockList){
for(T block:blockList){
remove(block, false);
}
trimNullBlocks();
}
public boolean remove(T block){
return remove(block, true);
}
protected boolean remove(T block, boolean trim){
T[] items=elementData;
if(block==null||items==null){
return false;
@ -192,17 +204,17 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
found=true;
}
}
if(found){
if(found && trim){
trimNullBlocks();
}
return found;
}
private void trimNullBlocks(){
protected void trimNullBlocks(){
T[] items=elementData;
if(items==null){
return;
}
int count=countNonNull();
int count=countNonNull(false);
int len=items.length;
if(count==len){
return;
@ -219,7 +231,7 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
}
elementData=update;
}
private int countNonNull(){
private int countNonNull(boolean is_null_check){
T[] items=elementData;
if(items==null){
return 0;
@ -227,6 +239,9 @@ public abstract class BlockArray<T extends Block> extends BlockContainer<T> impl
int result=0;
for(T block:items){
if(block!=null){
if(is_null_check && block.isNull()){
continue;
}
result++;
}
}

View File

@ -32,7 +32,6 @@ public abstract class BaseChunk extends ExpandableBlockContainer {
public void onChunkLoaded(){
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
HeaderBlock headerBlock=reader.readHeaderBlock();

View File

@ -4,22 +4,23 @@ import com.reandroid.lib.arsc.array.SpecTypePairArray;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.PackageLastBlocks;
import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.decoder.ResourceNameProvider;
import com.reandroid.lib.arsc.group.EntryGroup;
import com.reandroid.lib.arsc.group.ItemGroup;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.PackageName;
import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.arsc.item.SpecString;
import com.reandroid.lib.arsc.pool.SpecStringPool;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.pool.TypeStringPool;
import com.reandroid.lib.arsc.value.BaseResValue;
import com.reandroid.lib.arsc.value.EntryBlock;
import com.reandroid.lib.arsc.value.LibraryInfo;
import com.reandroid.lib.arsc.value.ResValueBag;
import java.util.*;
public class PackageBlock extends BaseChunk {
public class PackageBlock extends BaseChunk implements ResourceNameProvider {
private final IntegerItem mPackageId;
private final PackageName mPackageName;
@ -72,6 +73,12 @@ public class PackageBlock extends BaseChunk {
addChild(mPackageLastBlocks);
}
public void removeEmpty(){
getSpecTypePairArray().removeEmptyPairs();
}
public boolean isEmpty(){
return getSpecTypePairArray().isEmpty();
}
public int getId(){
return mPackageId.get();
}
@ -178,11 +185,14 @@ public class PackageBlock extends BaseChunk {
public TypeBlock getTypeBlock(byte typeId, String qualifiers){
return getSpecTypePairArray().getTypeBlock(typeId, qualifiers);
}
public Map<Integer, EntryGroup> getEntriesGroupMap(){
return mEntriesGroup;
}
public Collection<EntryGroup> listEntryGroup(){
return mEntriesGroup.values();
return getEntriesGroupMap().values();
}
public EntryGroup getEntryGroup(int resId){
return mEntriesGroup.get(resId);
return getEntriesGroupMap().get(resId);
}
public void updateEntry(EntryBlock entryBlock){
if(entryBlock==null||entryBlock.isNull()){
@ -191,6 +201,20 @@ public class PackageBlock extends BaseChunk {
updateEntryGroup(entryBlock);
updateEntryTableReferences(entryBlock);
}
public void removeEntryGroup(EntryBlock entryBlock){
if(entryBlock==null){
return;
}
int id=entryBlock.getResourceId();
EntryGroup group=getEntriesGroupMap().get(id);
if(group==null){
return;
}
group.remove(entryBlock);
if(group.size()==0){
getEntriesGroupMap().remove(id);
}
}
private void updateEntryTableReferences(EntryBlock entryBlock){
TableBlock tableBlock=getTableBlock();
if(tableBlock==null){
@ -202,10 +226,10 @@ public class PackageBlock extends BaseChunk {
}
private void updateEntryGroup(EntryBlock entryBlock){
int resId=entryBlock.getResourceId();
EntryGroup group=mEntriesGroup.get(resId);
EntryGroup group=getEntriesGroupMap().get(resId);
if(group==null){
group=new EntryGroup(resId);
mEntriesGroup.put(resId, group);
getEntriesGroupMap().put(resId, group);
}
group.add(entryBlock);
}
@ -246,6 +270,67 @@ public class PackageBlock extends BaseChunk {
refreshKeyStrings();
}
@Override
public String getResourceFullName(int resId, boolean includePackageName) {
EntryGroup entryGroup=getEntryGroup(resId);
if(entryGroup==null){
return null;
}
String type=entryGroup.getTypeName();
if(type==null){
return null;
}
String spec=entryGroup.getSpecName();
if(spec==null){
return null;
}
StringBuilder builder=new StringBuilder();
builder.append('@');
if(includePackageName){
builder.append(getPackageName());
builder.append(':');
}
builder.append(type);
builder.append('/');
builder.append(spec);
return builder.toString();
}
@Override
public String getResourceName(int resId, boolean includePackageName) {
EntryGroup entryGroup=getEntryGroup(resId);
if(entryGroup==null){
return null;
}
String spec=entryGroup.getSpecName();
if(spec==null){
return null;
}
StringBuilder builder=new StringBuilder();
if(includePackageName){
builder.append(getPackageName());
builder.append(':');
}
builder.append(spec);
return builder.toString();
}
@Override
public ResValueBag getAttributeBag(int resId){
EntryGroup entryGroup=getEntryGroup(resId);
if(entryGroup==null){
return null;
}
EntryBlock entryBlock=entryGroup.pickOne();
if(entryBlock==null){
return null;
}
BaseResValue resValue=entryBlock.getResValue();
if(resValue instanceof ResValueBag){
return (ResValueBag)resValue;
}
return null;
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();

View File

@ -1,10 +1,14 @@
package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.array.PackageArray;
import com.reandroid.lib.arsc.decoder.ResourceNameProvider;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.value.ResValueBag;
public class TableBlock extends BaseChunk {
import java.util.Collection;
public class TableBlock extends BaseChunk implements ResourceNameProvider {
private final IntegerItem mPackageCount;
private final TableStringPool mTableStringPool;
private final PackageArray mPackageArray;
@ -17,16 +21,63 @@ public class TableBlock extends BaseChunk {
addChild(mTableStringPool);
addChild(mPackageArray);
}
public Collection<PackageBlock> listPackages(){
return getPackageArray().listItems();
}
public TableStringPool getTableStringPool(){
return mTableStringPool;
}
public PackageBlock getPackageBlockById(byte pkgId){
return getPackageArray().getPackageBlockById(pkgId);
}
public PackageArray getPackageArray(){
return mPackageArray;
}
private void refreshPackageCount(){
int count = getPackageArray().childesCount();
mPackageCount.set(count);
}
@Override
protected void onChunkRefreshed() {
refreshPackageCount();
}
@Override
public String getResourceFullName(int resId, boolean includePackageName) {
byte pkgId= (byte) ((resId>>24)&0xFF);
if(pkgId==0){
return null;
}
PackageBlock packageBlock=getPackageBlockById(pkgId);
if(packageBlock!=null){
return packageBlock.getResourceFullName(resId, includePackageName);
}
return null;
}
@Override
public String getResourceName(int resId, boolean includePackageName) {
byte pkgId= (byte) ((resId>>24)&0xFF);
if(pkgId==0){
return null;
}
PackageBlock packageBlock=getPackageBlockById(pkgId);
if(packageBlock!=null){
return packageBlock.getResourceName(resId, includePackageName);
}
return null;
}
@Override
public ResValueBag getAttributeBag(int resId){
byte pkgId= (byte) ((resId>>24)&0xFF);
if(pkgId==0){
return null;
}
PackageBlock packageBlock=getPackageBlockById(pkgId);
if(packageBlock!=null){
return packageBlock.getAttributeBag(resId);
}
return null;
}
@Override
public String toString(){
@ -37,4 +88,5 @@ public class TableBlock extends BaseChunk {
builder.append(pkgCount);
return builder.toString();
}
}

View File

@ -1,6 +1,8 @@
package com.reandroid.lib.arsc.chunk;
import com.reandroid.lib.arsc.array.EntryBlockArray;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.container.SpecTypePair;
import com.reandroid.lib.arsc.item.IntegerArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.value.EntryBlock;
@ -28,6 +30,48 @@ public class TypeBlock extends BaseTypeBlock {
addChild(mEntryOffsets);
addChild(mEntryArray);
}
public boolean isEmpty(){
return getEntryBlockArray().isEmpty();
}
public boolean isDefault(){
return getResConfig().isDefault();
}
public String getQualifiers(){
return getResConfig().getQualifiers();
}
public void setQualifiers(String qualifiers){
getResConfig().parseQualifiers(qualifiers);
}
public int countNonNullEntries(){
return getEntryBlockArray().countNonNull();
}
public SpecTypePair getParentSpecTypePair(){
Block parent=getParent();
while (parent!=null){
if(parent instanceof SpecTypePair){
return (SpecTypePair)parent;
}
parent=parent.getParent();
}
return null;
}
public void cleanEntries(){
PackageBlock packageBlock=getPackageBlock();
List<EntryBlock> allEntries=listEntries(true);
for(EntryBlock entryBlock:allEntries){
if(packageBlock!=null){
packageBlock.removeEntryGroup(entryBlock);
}
entryBlock.setNull(true);
}
}
public void removeEntry(EntryBlock entryBlock){
PackageBlock packageBlock=getPackageBlock();
if(packageBlock!=null){
packageBlock.removeEntryGroup(entryBlock);
}
entryBlock.setNull(true);
}
public EntryBlock getOrCreateEntry(short entryId){
return getEntryBlockArray().getOrCreate(entryId);
}
@ -45,7 +89,7 @@ public class TypeBlock extends BaseTypeBlock {
}
public List<EntryBlock> listEntries(boolean skipNullBlock){
List<EntryBlock> results=new ArrayList<>();
Iterator<EntryBlock> itr = mEntryArray.iterator(skipNullBlock);
Iterator<EntryBlock> itr = getEntryBlockArray().iterator(skipNullBlock);
while (itr.hasNext()){
EntryBlock block=itr.next();
results.add(block);
@ -53,22 +97,22 @@ public class TypeBlock extends BaseTypeBlock {
return results;
}
public EntryBlock getEntryBlock(int entryId){
return mEntryArray.get(entryId);
return getEntryBlockArray().get(entryId);
}
@Override
void onSetEntryCount(int count) {
mEntryArray.setChildesCount(count);
getEntryBlockArray().setChildesCount(count);
}
@Override
protected void onChunkRefreshed() {
getEntryBlockArray().refreshCountAndStart();
}
@Override
public String toString(){
StringBuilder builder=new StringBuilder();
builder.append(super.toString());
builder.append(", config=");
builder.append(getResConfig().toString());
builder.append(" ");
builder.append(super.toString());
return builder.toString();
}
}

View File

@ -69,6 +69,9 @@ public class ResXmlAttribute extends FixedBlockContainer {
mRawValue.set(val);
}
public ResXmlString getNameString(){
return getResXmlString(getNameReference());
}
public ValueType getValueType(){
return ValueType.valueOf(getValueTypeByte());
}
@ -104,7 +107,7 @@ public class ResXmlAttribute extends FixedBlockContainer {
return getResourceId(getNameReference());
}
private int getResourceId(int ref){
if(ref<=0){
if(ref<0){
return 0;
}
ResXmlIDMap xmlIDMap=getResXmlIDMap();
@ -171,9 +174,9 @@ public class ResXmlAttribute extends FixedBlockContainer {
}
String valStr=getValueString();
if(valStr!=null){
return getIndex()+" {"+fullName+"=\""+valStr+"\""+"}";
return fullName+"=\""+valStr+"\"";
}
return getIndex()+" {"+fullName+"}"+"["+getValueType()+"]=\""+getRawValue()+"\"";
return fullName+"["+getValueType()+"]=\""+getRawValue()+"\"";
}
StringBuilder builder=new StringBuilder();
builder.append(getClass().getSimpleName());

View File

@ -11,6 +11,8 @@ import com.reandroid.lib.arsc.pool.ResXmlStringPool;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ResXmlElement extends FixedBlockContainer {
@ -36,6 +38,20 @@ public class ResXmlElement extends FixedBlockContainer {
addChild(4, mEndElementContainer);
addChild(5, mEndNamespaceList);
}
public String getTagName(){
ResXmlStartElement startElement=getStartElement();
if(startElement!=null){
return startElement.getTagName();
}
return null;
}
public Collection<ResXmlAttribute> listResXmlAttributes(){
ResXmlStartElement startElement=getStartElement();
if(startElement!=null){
return startElement.listResXmlAttributes();
}
return new ArrayList<>();
}
public ResXmlStringPool getStringPool(){
Block parent=getParent();
while (parent!=null){
@ -287,4 +303,25 @@ public class ResXmlElement extends FixedBlockContainer {
+hasStartElement()+", hasEnd="+hasEndElement());
}
}
@Override
public String toString(){
ResXmlStartElement start = getStartElement();
if(start!=null){
ResXmlText text=getResXmlText();
StringBuilder builder=new StringBuilder();
builder.append("<");
builder.append(start.toString());
if(text!=null){
builder.append(">");
builder.append(text.toString());
builder.append("</");
builder.append(start.getTagName());
builder.append(">");
}else {
builder.append("/>");
}
return builder.toString();
}
return "NULL";
}
}

View File

@ -4,8 +4,10 @@ import com.reandroid.lib.arsc.chunk.ChunkType;
import com.reandroid.lib.arsc.array.ResXmlIDArray;
import com.reandroid.lib.arsc.chunk.BaseChunk;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ResXmlID;
import java.io.IOException;
import java.util.Collection;
public class ResXmlIDMap extends BaseChunk {
private final ResXmlIDArray mResXmlIDArray;
@ -18,6 +20,21 @@ public class ResXmlIDMap extends BaseChunk {
return mResXmlIDArray;
}
public Collection<ResXmlID> listResXmlID(){
return getResXmlIDArray().listItems();
}
public void addResourceId(int index, int resId){
getResXmlIDArray().addResourceId(index, resId);
}
public ResXmlID getResXmlID(int ref){
return getResXmlIDArray().get(ref);
}
public ResXmlID getOrCreate(int resId){
return getResXmlIDArray().getOrCreate(resId);
}
public ResXmlID getByResId(int resId){
return getResXmlIDArray().getByResId(resId);
}
@Override
protected void onChunkRefreshed() {

View File

@ -5,6 +5,8 @@ import com.reandroid.lib.arsc.array.ResXmlAttributeArray;
import com.reandroid.lib.arsc.item.IntegerItem;
import com.reandroid.lib.arsc.item.ShortItem;
import java.util.Collection;
public class ResXmlStartElement extends BaseXmlChunk {
private final ShortItem mAttributeStart;
@ -37,6 +39,12 @@ public class ResXmlStartElement extends BaseXmlChunk {
}
return prefix+":"+name;
}
public Collection<ResXmlAttribute> listResXmlAttributes(){
return getResXmlAttributeArray().listItems();
}
public ResXmlAttributeArray getResXmlAttributeArray(){
return mAttributeArray;
}
public String getPrefix(){
int uriRef=getNamespaceReference();
if(uriRef<0){
@ -78,14 +86,14 @@ public class ResXmlStartElement extends BaseXmlChunk {
return super.toString();
}
StringBuilder builder=new StringBuilder();
builder.append("TAG: line=").append(getLineNumber()).append(" <").append(txt).append(">");
builder.append(txt);
ResXmlAttribute[] allAttr=mAttributeArray.getChildes();
if(allAttr!=null){
for(int i=0;i<allAttr.length;i++){
if(i>10){
break;
}
builder.append(", ");
builder.append(" ");
builder.append(allAttr[i].toString());
}
}

View File

@ -34,6 +34,15 @@ public class SpecTypePair extends BlockContainer<Block> {
public SpecTypePair(){
this(new SpecBlock(), new TypeBlockArray());
}
public void removeEmptyTypeBlocks(){
getTypeBlockArray().removeEmptyBlocks();
}
public boolean isEmpty(){
return getTypeBlockArray().isEmpty();
}
public int countTypeBlocks(){
return getTypeBlockArray().childesCount();
}
public EntryBlock getOrCreateEntry(short entryId, String qualifiers){
return getTypeBlockArray().getOrCreateEntry(entryId, qualifiers);
}
@ -49,6 +58,7 @@ public class SpecTypePair extends BlockContainer<Block> {
public List<ResConfig> listResConfig(){
return mTypeBlockArray.listResConfig();
}
public byte getTypeId(){
return mSpecBlock.getTypeId();
}

View File

@ -0,0 +1,85 @@
package com.reandroid.lib.arsc.decoder;
import com.reandroid.lib.arsc.base.Block;
import com.reandroid.lib.arsc.value.ResValueBag;
import com.reandroid.lib.arsc.value.ResValueBagItem;
import com.reandroid.lib.arsc.value.ValueType;
public abstract class ResDecoder<InputBlock extends Block, Output> implements ResourceNameProvider{
private final ResourceNameStore resourceNameStore;
public ResDecoder(ResourceNameStore store){
this.resourceNameStore=store;
}
public String decodeAttribute(int attrResId, int rawValue){
ResValueBag valueBag=getAttributeBag(attrResId);
if(valueBag==null){
return null;
}
ResValueBagItem[] bagItems=valueBag.getBagItems();
if(bagItems==null||bagItems.length==0){
return null;
}
int len=bagItems.length;
ResValueBagItem firstAttrChild=bagItems[0];
if(len==1){
return null;
}
if(isFlagAttr(firstAttrChild)){
for(int i=1;i<len;i++){
ResValueBagItem bagItem=bagItems[i];
int data=bagItem.getData();
if(data!=rawValue){
continue;
}
int id=bagItem.getId();
return getResourceName(id, false);
}
return null;
}
StringBuilder builder=new StringBuilder();
boolean appendOnce=false;
for(int i=1;i<len;i++){
ResValueBagItem bagItem=bagItems[i];
int data=bagItem.getData();
if((data&rawValue)==0){
continue;
}
int id=bagItem.getId();
String name=getResourceName(id, false);
if(appendOnce){
builder.append("|");
}
builder.append(name);
builder.append(data);
appendOnce=true;
}
if(!appendOnce){
return null;
}
builder.append(":");
builder.append(rawValue);
builder.append(firstAttrChild.getValueType());
return builder.toString();
}
private boolean isFlagAttr(ResValueBagItem firstAttrChild){
ValueType valueType=firstAttrChild.getValueType();
return valueType==ValueType.FIRST_INT;
}
public ResourceNameStore getResourceNameStore() {
return resourceNameStore;
}
@Override
public String getResourceFullName(int resId, boolean includePackageName) {
return getResourceNameStore().getResourceFullName(resId, includePackageName);
}
@Override
public String getResourceName(int resId, boolean includePackageName) {
return getResourceNameStore().getResourceName(resId, includePackageName);
}
@Override
public ResValueBag getAttributeBag(int resId) {
return getResourceNameStore().getAttributeBag(resId);
}
public abstract Output decode(byte currentPackageId, InputBlock inputBlock);
}

View File

@ -0,0 +1,10 @@
package com.reandroid.lib.arsc.decoder;
import com.reandroid.lib.arsc.value.ResValueBag;
public interface ResourceNameProvider {
String getResourceFullName(int resId, boolean includePackageName);
String getResourceName(int resId, boolean includePackageName);
ResValueBag getAttributeBag(int resId);
}

View File

@ -0,0 +1,52 @@
package com.reandroid.lib.arsc.decoder;
import com.reandroid.lib.arsc.value.ResValueBag;
import java.util.HashSet;
import java.util.Set;
public class ResourceNameStore implements ResourceNameProvider {
private final Set<ResourceNameProvider> resourceNameProviders;
public ResourceNameStore(){
this.resourceNameProviders=new HashSet<>();
}
public void addResourceNameProvider(ResourceNameProvider provider){
if(provider!=null){
resourceNameProviders.add(provider);
}
}
public Set<ResourceNameProvider> getResourceNameProviders(){
return resourceNameProviders;
}
@Override
public String getResourceFullName(int resId, boolean includePackageName) {
for(ResourceNameProvider provider:this.resourceNameProviders){
String name=provider.getResourceFullName(resId, includePackageName);
if(name!=null){
return name;
}
}
return null;
}
@Override
public String getResourceName(int resId, boolean includePackageName) {
for(ResourceNameProvider provider:this.resourceNameProviders){
String name=provider.getResourceName(resId, includePackageName);
if(name!=null){
return name;
}
}
return null;
}
@Override
public ResValueBag getAttributeBag(int resId) {
for(ResourceNameProvider provider:this.resourceNameProviders){
ResValueBag resValueBag=provider.getAttributeBag(resId);
if(resValueBag!=null){
return resValueBag;
}
}
return null;
}
}

View File

@ -0,0 +1,108 @@
package com.reandroid.lib.arsc.decoder;
import com.reandroid.lib.arsc.value.ValueType;
public class ValueDecoder {
public static String decode(ValueType valueType, int data){
if(valueType==null){
return null;
}
switch (valueType){
case INT_BOOLEAN:
return decodeBoolean(data);
case FIRST_COLOR_INT:
case INT_COLOR_ARGB4:
case INT_COLOR_ARGB8:
case INT_COLOR_RGB4:
case INT_COLOR_RGB8:
case LAST_COLOR_INT:
return decodeColor(data);
case DIMENSION:
case FLOAT:
case FRACTION:
return decodeDimensionOrFloat(valueType, data);
case INT_HEX:
return decodeHex(data);
case INT_DEC:
case FIRST_INT:
case LAST_INT:
return decodeInt(data);
}
return null;
}
private static String decodeHex(int rawVal){
return String.format("0x%x", rawVal);
}
private static String decodeInt(int rawVal){
return String.valueOf(rawVal);
}
private static String decodeBoolean(int data){
if(data == 0xFFFFFFFF){
return "true";
}
return "false";
}
private static String decodeColor(int rawVal){
String hex=String.format("%x", rawVal);
if(hex.length()<=6){
return String.format("#%06x", rawVal);
}
return String.format("#%08x", rawVal);
}
private static String decodeDimensionOrFloat(ValueType valueType, int rawVal){
return decodeFloat(rawVal, valueType);
}
private static String decodeFloat(int val, ValueType valueType){
if(valueType==ValueType.FLOAT){
float f=Float.intBitsToFloat(val);
return Float.toString(f);
}
float f=complexToFloat(val);
String unit="";
switch (valueType){
case FRACTION:
f=f*100;
if((val & 0x3)==0){
unit="%";
}else {
unit="%p";
}
break;
case DIMENSION:
int i=(val & 0xf);
unit=getDimensionUnit(i);
break;
}
return Float.toString(f)+unit;
}
private static float complexToFloat(int complex) {
int y=(complex >> 4) & 0x3;
float result=complex & 0xffffff00;
float y2=RADIX_MULTS[y];
result=result * y2;
return result;
}
private static String getDimensionUnit(int index){
if(index<0 || index>DIMENSION_UNIT_STRS.length){
index=1;
}
return DIMENSION_UNIT_STRS[index];
}
private static int getDimensionIndex(String unit){
String[] dims=DIMENSION_UNIT_STRS;
for(int i=0;i<dims.length;i++){
if(dims[i].equals(unit)){
return i;
}
}
return 0;
}
private static final String[] DIMENSION_UNIT_STRS = new String[] { "px", "dip", "sp", "pt", "in", "mm" };
private static final float MANTISSA_MULT = 1.0f / (1 << 8);
private static final float[] RADIX_MULTS = new float[] {
1.0f * MANTISSA_MULT, 1.0f / (1 << 7) * MANTISSA_MULT,
1.0f / (1 << 15) * MANTISSA_MULT, 1.0f / (1 << 23) * MANTISSA_MULT };
}

View File

@ -0,0 +1,139 @@
package com.reandroid.lib.arsc.decoder.xml;
import com.reandroid.lib.arsc.chunk.xml.ResXmlAttribute;
import com.reandroid.lib.arsc.chunk.xml.ResXmlBlock;
import com.reandroid.lib.arsc.chunk.xml.ResXmlElement;
import com.reandroid.lib.arsc.chunk.xml.ResXmlText;
import com.reandroid.lib.arsc.decoder.ResDecoder;
import com.reandroid.lib.arsc.decoder.ResourceNameStore;
import com.reandroid.lib.arsc.decoder.ValueDecoder;
import com.reandroid.lib.arsc.value.ValueType;
import java.util.Collection;
import java.util.List;
public class ResXmlDecoder extends ResDecoder<ResXmlBlock, String> {
private byte mCurrentPackageId;
public ResXmlDecoder(ResourceNameStore store){
super(store);
}
private String decodeToString(ResXmlBlock resXmlBlock){
StringBuilder builder=new StringBuilder();
builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
builder.append("\n");
String body=decodeToString(resXmlBlock.getResXmlElement());
builder.append(body);
return builder.toString();
}
private String decodeToString(ResXmlElement resXmlElement){
if(resXmlElement==null){
return null;
}
StringBuilder builder=new StringBuilder();
for(int i=0;i<resXmlElement.getDepth();i++){
builder.append(' ');
}
builder.append('<');
String tagName=resXmlElement.getTagName();
builder.append(tagName);
for(ResXmlAttribute attribute:resXmlElement.listResXmlAttributes()){
builder.append(' ');
String name=decodeAttributeFullName(attribute);
builder.append(name);
builder.append("=\"");
String value=decodeAttributeValue(attribute);
builder.append(value);
builder.append("\"");
}
boolean useEndTag=false;
ResXmlText resXmlText=resXmlElement.getResXmlText();
String text=null;
if(resXmlText!=null){
useEndTag=true;
text=resXmlText.getText();
}
List<ResXmlElement> childElements=resXmlElement.listElements();
if(!useEndTag){
useEndTag=childElements.size()>0;
}
if(!useEndTag){
builder.append("/>");
return builder.toString();
}
builder.append(">");
if(text!=null){
builder.append(text);
}
for(ResXmlElement child:childElements){
builder.append("\n");
String txtChild=decodeToString(child);
builder.append(txtChild);
}
if(childElements.size()>0){
builder.append("\n");
for(int i=0;i<resXmlElement.getDepth();i++){
builder.append(' ');
}
}
builder.append("</");
builder.append(tagName);
builder.append(">");
return builder.toString();
}
private String decodeAttributeValue(ResXmlAttribute attribute){
ValueType valueType=attribute.getValueType();
if(valueType==ValueType.FIRST_INT || valueType==ValueType.INT_HEX){
int nameId=attribute.getNameResourceID();
String val=decodeAttribute(nameId, attribute.getRawValue());
if(val!=null){
return val;
}
}
if(valueType==ValueType.REFERENCE){
int id=attribute.getRawValue();
byte pkgId= (byte) ((id>>24)&0xFF);
return getResourceFullName(id, pkgId!=getCurrentPackageId());
}
if(valueType==ValueType.STRING){
return attribute.getValueString();
}
String val= ValueDecoder.decode(valueType, attribute.getRawValue());
if(val!=null){
return val;
}
return attribute.getRawValue()+"["+valueType+"]";
}
private String decodeAttributeFullName(ResXmlAttribute attribute){
StringBuilder builder=new StringBuilder();
String prefix=getRealAttributeNamePrefix(attribute);
String name=getRealAttributeName(attribute);
if(prefix!=null&&!name.contains(":")){
builder.append(prefix);
builder.append(':');
}
builder.append(name);
return builder.toString();
}
private String getRealAttributeNamePrefix(ResXmlAttribute attribute){
/* TODO readjust wrong/stripped attribute name prefix prefix; */
return attribute.getNamePrefix();
}
private String getRealAttributeName(ResXmlAttribute attribute){
int nameId=attribute.getNameResourceID();
ResourceNameStore store=getResourceNameStore();
byte pkgId= (byte) ((nameId>>24)&0xFF);
String name=store.getResourceName(nameId, getCurrentPackageId()!=pkgId);
if(name!=null){
return name;
}
return attribute.getName();
}
private byte getCurrentPackageId(){
return mCurrentPackageId;
}
@Override
public String decode(byte currentPackageId, ResXmlBlock resXmlBlock) {
this.mCurrentPackageId=currentPackageId;
return decodeToString(resXmlBlock);
}
}

View File

@ -53,18 +53,37 @@ public class EntryGroup extends ItemGroup<EntryBlock> {
}
return renameOk;
}
public TypeString getTypeString(){
public EntryBlock pickOne(){
EntryBlock defEntryBlock=getDefault();
if(defEntryBlock!=null){
return defEntryBlock;
}
Iterator<EntryBlock> itr=iterator(true);
while (itr.hasNext()){
return itr.next();
}
return null;
}
public EntryBlock getDefault(){
Iterator<EntryBlock> itr=iterator(true);
while (itr.hasNext()){
EntryBlock entryBlock=itr.next();
if(entryBlock.isDefault()){
return entryBlock;
}
}
return null;
}
public TypeString getTypeString(){
EntryBlock entryBlock=pickOne();
if(entryBlock!=null){
return entryBlock.getTypeString();
}
return null;
}
public SpecString getSpecString(){
Iterator<EntryBlock> itr=iterator(true);
while (itr.hasNext()){
EntryBlock entryBlock=itr.next();
EntryBlock entryBlock=pickOne();
if(entryBlock!=null){
return entryBlock.getSpecString();
}
return null;
@ -98,6 +117,14 @@ public class EntryGroup extends ItemGroup<EntryBlock> {
}
return packageBlock.getSpecStringPool();
}
@Override
public String toString(){
EntryBlock entryBlock=pickOne();
if(entryBlock==null){
return super.toString();
}
return super.toString()+"{"+entryBlock.toString()+"}";
}
private static BlockArrayCreator<EntryBlock> create(){
return new BlockArrayCreator<EntryBlock>(){
@Override
@ -111,4 +138,5 @@ public class EntryGroup extends ItemGroup<EntryBlock> {
}
};
}
}

View File

@ -28,7 +28,7 @@ public class PackageName extends StringItem {
return decodeUtf16Bytes(getBytesInternal());
}
@Override
StyleItem getStyle(){
public StyleItem getStyle(){
return null;
}
@Override

View File

@ -1,11 +1,51 @@
package com.reandroid.lib.arsc.item;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ResXmlID extends IntegerItem {
public ResXmlID(){
super();
}
private final List<ReferenceItem> mReferencedList;
public ResXmlID(int resId){
super(resId);
this.mReferencedList=new ArrayList<>();
}
public ResXmlID(){
this(0);
}
public boolean removeReference(ReferenceItem ref){
return mReferencedList.remove(ref);
}
public boolean removeAllReference(Collection<ReferenceItem> referenceItems){
return mReferencedList.removeAll(referenceItems);
}
public void removeAllReference(){
mReferencedList.clear();
}
public List<ReferenceItem> getReferencedList(){
return mReferencedList;
}
public void addReference(ReferenceItem ref){
if(ref!=null){
mReferencedList.add(ref);
}
}
public void addReference(Collection<ReferenceItem> refList){
if(refList==null){
return;
}
for(ReferenceItem ref:refList){
addReference(ref);
}
}
private void reUpdateReferences(int newIndex){
for(ReferenceItem ref:mReferencedList){
ref.set(newIndex);
}
}
@Override
public void onIndexChanged(int oldIndex, int newIndex){
reUpdateReferences(newIndex);
}
@Override
public String toString(){

View File

@ -5,7 +5,7 @@ public class SpecString extends StringItem {
super(utf8);
}
@Override
StyleItem getStyle(){
public StyleItem getStyle(){
return null;
}
}

View File

@ -50,7 +50,8 @@ public class StringItem extends BlockItem {
}
}
private void reUpdateReferences(int newIndex){
for(ReferenceItem ref:mReferencedList){
List<ReferenceItem> referenceItems=new ArrayList<>(mReferencedList);
for(ReferenceItem ref:referenceItems){
ref.set(newIndex);
}
}
@ -103,6 +104,9 @@ public class StringItem extends BlockItem {
@Override
public void onReadBytes(BlockReader reader) throws IOException {
if(reader.available()<4){
return;
}
int len=calculateReadLength(reader);
setBytesLength(len, false);
byte[] bts=getBytesInternal();
@ -110,6 +114,9 @@ public class StringItem extends BlockItem {
onBytesChanged();
}
int calculateReadLength(BlockReader reader) throws IOException {
if(reader.available()<4){
return reader.available();
}
byte[] bts=new byte[4];
reader.readFully(bts);
reader.offset(-4);
@ -156,12 +163,12 @@ public class StringItem extends BlockItem {
CharBuffer charBuffer=charsetDecoder.decode(buf);
return charBuffer.toString();
} catch (CharacterCodingException ex) {
return new String(allStringBytes, offLen[0], offLen[1]);
return new String(allStringBytes, offLen[0], offLen[1], StandardCharsets.UTF_16LE);
}
}
StyleItem getStyle(){
public StyleItem getStyle(){
BaseStringPool stringPool=getStringPool();
if(stringPool==null){
return null;

View File

@ -9,7 +9,7 @@ public class TypeString extends StringItem {
return (byte) (getIndex()+1);
}
@Override
StyleItem getStyle(){
public StyleItem getStyle(){
return null;
}
}

View File

@ -11,9 +11,7 @@ import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.*;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
public abstract class BaseStringPool<T extends StringItem> extends BaseChunk implements BlockLoad {
@ -65,7 +63,26 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
mUniqueMap=new HashMap<>();
}
public List<T> removeUnusedStrings(){
return getStringsArray().removeUnusedStrings();
}
public List<T> listUnusedStrings(){
return getStringsArray().listUnusedStrings();
}
public StyleArray getStyleArray(){
return mArrayStyles;
}
public StringArray<T> getStringsArray(){
return mArrayStrings;
}
public void removeReferences(Collection<ReferenceItem> referenceList){
if(referenceList==null){
return;
}
for(ReferenceItem ref:referenceList){
removeReference(ref);
}
}
public boolean removeReference(ReferenceItem ref){
if(ref==null){
return false;
@ -207,7 +224,8 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
abstract StringArray<T> newInstance(IntegerArray offsets, IntegerItem itemCount, IntegerItem itemStart, boolean is_utf8);
@Override
protected void onChunkRefreshed() {
mArrayStrings.refreshCountAndStart();
mArrayStyles.refreshCountAndStart();
}
@Override
public void onChunkLoaded() {

View File

@ -0,0 +1,144 @@
package com.reandroid.lib.arsc.util;
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.ReferenceItem;
import com.reandroid.lib.arsc.item.TableString;
import com.reandroid.lib.arsc.pool.TableStringPool;
import com.reandroid.lib.arsc.value.EntryBlock;
import java.io.*;
import java.util.*;
public class FrameworkTable extends TableBlock {
public FrameworkTable(){
super();
}
public int writeTable(File resourcesArscFile) throws IOException{
File dir=resourcesArscFile.getParentFile();
if(dir!=null && !dir.exists()){
dir.mkdirs();
}
FileOutputStream outputStream=new FileOutputStream(resourcesArscFile, false);
return writeTable(outputStream);
}
public int writeTable(OutputStream outputStream) throws IOException{
return writeBytes(outputStream);
}
public void readTable(File resourcesArscFile) throws IOException{
FileInputStream inputStream=new FileInputStream(resourcesArscFile);
readTable(inputStream);
}
public void readTable(InputStream inputStream) throws IOException{
BlockReader reader=new BlockReader(inputStream);
super.readBytes(reader);
}
@Override
public int onWriteBytes(OutputStream stream) throws IOException{
int length=super.onWriteBytes(stream);
stream.flush();
stream.close();
return length;
}
@Override
public void onReadBytes(BlockReader reader) throws IOException {
super.onReadBytes(reader);
reader.close();
}
public void optimize(){
Map<Integer, EntryGroup> groupMap=scanAllEntryGroups();
for(EntryGroup group:groupMap.values()){
List<EntryBlock> entryBlockList=getEntriesToRemove(group);
removeEntryBlocks(entryBlockList);
}
for(PackageBlock pkg:listPackages()){
pkg.removeEmpty();
pkg.refresh();
}
optimizeTableString();
refresh();
}
private void optimizeTableString(){
removeUnusedTableString();
shrinkTableString();
removeUnusedTableString();
}
private void removeUnusedTableString(){
TableStringPool tableStringPool=getTableStringPool();
tableStringPool.getStyleArray().clearChildes();
tableStringPool.removeUnusedStrings();
tableStringPool.refresh();
}
private void shrinkTableString(){
TableStringPool tableStringPool=getTableStringPool();
TableString zero=tableStringPool.get(0);
zero.set("Framework string table");
for(TableString tableString:tableStringPool.getStringsArray().listItems()){
if(tableString==zero){
continue;
}
shrinkTableString(zero, tableString);
}
tableStringPool.refresh();
}
private void shrinkTableString(TableString zero, TableString tableString){
List<ReferenceItem> allRef = new ArrayList<>(tableString.getReferencedList());
tableString.removeAllReference();
for(ReferenceItem item:allRef){
item.set(zero.getIndex());
}
zero.addReference(allRef);
}
private void removeEntryBlocks(List<EntryBlock> removeList){
for(EntryBlock entryBlock:removeList){
removeEntryBlock(entryBlock);
}
}
private void removeEntryBlock(EntryBlock entryBlock){
TypeBlock typeBlock=entryBlock.getTypeBlock();
if(typeBlock==null){
return;
}
typeBlock.removeEntry(entryBlock);
}
private List<EntryBlock> getEntriesToRemove(EntryGroup group){
List<EntryBlock> results=new ArrayList<>();
EntryBlock mainEntry=group.pickOne();
if(mainEntry==null){
return results;
}
Iterator<EntryBlock> itr = group.iterator(true);
while (itr.hasNext()){
EntryBlock entryBlock=itr.next();
if(entryBlock==mainEntry){
continue;
}
results.add(entryBlock);
}
return results;
}
private Map<Integer, EntryGroup> scanAllEntryGroups(){
Map<Integer, EntryGroup> results=new HashMap<>();
for(PackageBlock packageBlock:listPackages()){
Map<Integer, EntryGroup> map=packageBlock.getEntriesGroupMap();
for(Map.Entry<Integer, EntryGroup> entry:map.entrySet()){
int id=entry.getKey();
EntryGroup group=entry.getValue();
EntryGroup exist=results.get(id);
if(exist!=null && exist.getDefault()!=null){
if(exist.getDefault()!=null){
continue;
}
results.remove(id);
}
results.put(id, group);
}
}
return results;
}
}

View File

@ -1,6 +1,10 @@
package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.chunk.PackageBlock;
import com.reandroid.lib.arsc.chunk.TableBlock;
import com.reandroid.lib.arsc.item.ReferenceItem;
import com.reandroid.lib.arsc.item.TableString;
import com.reandroid.lib.arsc.pool.TableStringPool;
public abstract class BaseResValueItem extends BaseResValue implements ResValueItem {
@ -8,6 +12,35 @@ public abstract class BaseResValueItem extends BaseResValue implements ResValueI
BaseResValueItem(int bytesLength) {
super(bytesLength);
}
String getString(int ref){
TableString tableString=getTableString(ref);
if(tableString==null){
return null;
}
return tableString.getHtml();
}
TableString getTableString(int ref){
TableStringPool stringPool=getTableStringPool();
if(stringPool==null){
return null;
}
return stringPool.get(ref);
}
TableStringPool getTableStringPool(){
EntryBlock entryBlock=getEntryBlock();
if(entryBlock==null){
return null;
}
PackageBlock packageBlock=entryBlock.getPackageBlock();
if(packageBlock==null){
return null;
}
TableBlock tableBlock=packageBlock.getTableBlock();
if(tableBlock!=null){
return tableBlock.getTableStringPool();
}
return null;
}
public ReferenceItem getTableStringReference(){
if(getValueType()!=ValueType.STRING){
return null;

View File

@ -26,6 +26,13 @@ public class EntryBlock extends Block {
super();
}
public boolean isDefault(){
TypeBlock typeBlock=getTypeBlock();
if(typeBlock!=null){
return typeBlock.isDefault();
}
return false;
}
public List<ReferenceItem> getTableStringReferences(){
if(isNull()){
return null;
@ -98,6 +105,30 @@ public class EntryBlock extends Block {
TableStringPool tableStringPool=tableBlock.getTableStringPool();
tableStringPool.addReference(ref);
}
private void removeTableReferences(){
PackageBlock packageBlock=getPackageBlock();
if(packageBlock==null){
return;
}
TableBlock tableBlock=packageBlock.getTableBlock();
if(tableBlock==null){
return;
}
TableStringPool tableStringPool=tableBlock.getTableStringPool();
tableStringPool.removeReferences(getTableStringReferences());
}
private void removeSpecReferences(){
PackageBlock packageBlock=getPackageBlock();
if(packageBlock==null){
return;
}
SpecStringPool specStringPool=packageBlock.getSpecStringPool();
specStringPool.removeReference(getSpecReferenceBlock());
}
private void removeAllReferences(){
removeTableReferences();
removeSpecReferences();
}
public short getFlags(){
return mFlags.get();
@ -271,6 +302,7 @@ public class EntryBlock extends Block {
if(!mUnLocked){
return;
}
removeAllReferences();
mUnLocked =false;
mHeaderSize.setParent(null);
mFlags.setParent(null);
@ -456,6 +488,13 @@ public class EntryBlock extends Block {
builder.append(name);
builder.append(')');
}
BaseResValue baseResValue=getResValue();
if(baseResValue instanceof ResValueInt){
ResValueInt resValueInt=(ResValueInt)baseResValue;
builder.append(" '");
builder.append(resValueInt.toString());
builder.append(" '");
}
return builder.toString();
}

View File

@ -425,7 +425,7 @@ public class ResConfig extends BlockArray<Block> implements BlockLoad {
public String getQualifiers(){
if(mQualifiers==null){
mQualifiers= ResConfigHelper.toQualifier(this);
mQualifiers = ResConfigHelper.toQualifier(this).trim();
}
return mQualifiers;
}
@ -503,13 +503,16 @@ public class ResConfig extends BlockArray<Block> implements BlockLoad {
}
return false;
}
public boolean isDefault(){
return getQualifiers().length()==0;
}
@Override
public String toString(){
String q=getQualifiers();
if(q.trim().length()==0){
return "[DEFAULT]";
if(q.length()==0){
q="DEFAULT";
}
return q;
return "["+q+"]";
}

View File

@ -9,8 +9,7 @@ import com.reandroid.lib.arsc.item.ReferenceItem;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public class ResValueBag extends BaseResValue {
@ -30,6 +29,9 @@ public class ResValueBag extends BaseResValue {
mResValueBagItemArray.setParent(this);
mResValueBagItemArray.setIndex(2);
}
public ResValueBagItem[] getBagItems(){
return getResValueBagItemArray().getChildes();
}
public List<ReferenceItem> getTableStringReferences(){
List<ReferenceItem> results=null;
for(ResValueBagItem bagItem:getResValueBagItemArray().listItems()){

View File

@ -1,5 +1,6 @@
package com.reandroid.lib.arsc.value;
import com.reandroid.lib.arsc.decoder.ValueDecoder;
import com.reandroid.lib.arsc.io.BlockReader;
import com.reandroid.lib.arsc.item.ReferenceItem;
@ -76,10 +77,19 @@ public class ResValueInt extends BaseResValueItem {
}else {
builder.append("Unknown");
}
String data=null;
if(vt==ValueType.STRING){
data=getString(getData());
}else{
data= ValueDecoder.decode(vt, getData());
}
if(data==null){
data=String.format("0x%08x", getData());
}
builder.append('(');
builder.append(String.format("0x%02x", getType()));
builder.append("), data=");
builder.append(String.format("0x%08x", getData()));
builder.append(data);
return builder.toString();
}