mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-29 22:04:25 +02:00
Initial commit
This commit is contained in:
parent
5a847aae87
commit
1763dfbc3c
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
85
src/main/java/com/reandroid/lib/arsc/decoder/ResDecoder.java
Normal file
85
src/main/java/com/reandroid/lib/arsc/decoder/ResDecoder.java
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
108
src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java
Normal file
108
src/main/java/com/reandroid/lib/arsc/decoder/ValueDecoder.java
Normal 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 };
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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> {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class PackageName extends StringItem {
|
||||
return decodeUtf16Bytes(getBytesInternal());
|
||||
}
|
||||
@Override
|
||||
StyleItem getStyle(){
|
||||
public StyleItem getStyle(){
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
|
@ -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(){
|
||||
|
@ -5,7 +5,7 @@ public class SpecString extends StringItem {
|
||||
super(utf8);
|
||||
}
|
||||
@Override
|
||||
StyleItem getStyle(){
|
||||
public StyleItem getStyle(){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -9,7 +9,7 @@ public class TypeString extends StringItem {
|
||||
return (byte) (getIndex()+1);
|
||||
}
|
||||
@Override
|
||||
StyleItem getStyle(){
|
||||
public StyleItem getStyle(){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
144
src/main/java/com/reandroid/lib/arsc/util/FrameworkTable.java
Normal file
144
src/main/java/com/reandroid/lib/arsc/util/FrameworkTable.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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+"]";
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()){
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user